blob: 0225af516d17d51fcc0482930fac0db3552af51f [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsam43526532013-08-01 22:03:50 -070050 enum_blacklist = set(("OFDefinitions",))
51 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsambe168f72013-08-03 22:49:35 -070052 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
53 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsam001b1822013-08-02 22:25:55 -070054 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
55 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070056
Andreas Wundsam2be7da52013-08-22 07:34:25 -070057 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070058 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
59 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
60 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
61 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
62 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
63 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
64 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
65 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
66 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
67 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
68 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
69 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
70 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
71 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
72 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
73 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
74 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
75 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
76 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
77 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
78 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
79 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
80 "OFOxmIpv4Src": OxmMapEntry("IPv4", "IPV4_SRC", False),
81 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4", "IPV4_SRC", True),
82 "OFOxmIpv4Dst": OxmMapEntry("IPv4", "IPV4_DST", False),
83 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4", "IPV4_DST", True),
84 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
85 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
86 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
87 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
88 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
89 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
90 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
91 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
92 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
93 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
94 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
95 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
96 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
97 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
98 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
99 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
100 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
101 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
102 "OFOxmArpSpa": OxmMapEntry("IPv4", "ARP_SPA", False),
103 "OFOxmArpSpaMasked": OxmMapEntry("IPv4", "ARP_SPA", True),
104 "OFOxmArpTpa": OxmMapEntry("IPv4", "ARP_TPA", False),
105 "OFOxmArpTpaMasked": OxmMapEntry("IPv4", "ARP_TPA", True),
106 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
107 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
108 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
109 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
110 "OFOxmIpv6Src": OxmMapEntry("IPv6", "IPV6_SRC", False),
111 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6", "IPV6_SRC", True),
112 "OFOxmIpv6Dst": OxmMapEntry("IPv6", "IPV6_DST", False),
113 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6", "IPV6_DST", True),
114 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700115 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
116 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
117 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
118 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
119 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
120 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6", "IPV6_ND_TARGET", False),
121 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6", "IPV6_ND_TARGET", True),
122 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
123 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
124 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
125 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
126 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
127 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
128 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
129 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
130 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700131
Andreas Wundsam27303462013-07-16 12:52:35 -0700132 @property
133 @memoize
134 def versions(self):
135 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
136
137 @property
138 @memoize
139 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700140 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700141
142 for raw_version, of_protocol in of_g.ir.items():
143 jversion = JavaOFVersion(of_protocol.wire_version)
144
145 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700146 if not of_class.name in version_map_per_class:
147 version_map_per_class[of_class.name] = collections.OrderedDict()
148
Andreas Wundsam27303462013-07-16 12:52:35 -0700149 version_map_per_class[of_class.name][jversion] = of_class
150
151 interfaces = []
152 for class_name, version_map in version_map_per_class.items():
153 interfaces.append(JavaOFInterface(class_name, version_map))
154
Andreas Wundsambe168f72013-08-03 22:49:35 -0700155 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
156
Andreas Wundsam27303462013-07-16 12:52:35 -0700157 return interfaces
158
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700159 @memoize
160 def interface_by_name(self, name):
161 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
162
Andreas Wundsam27303462013-07-16 12:52:35 -0700163 @property
164 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700165 def all_classes(self):
166 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
167
168 @property
169 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700170 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700171 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700172
173 for version in self.versions:
174 of_protocol = of_g.ir[version.int_version]
175 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700176 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700177
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700178 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
179 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700180
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700181 # inelegant - need java name here
182 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700183 return enums
184
185 @memoize
186 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700187 res = find(lambda e: e.name == name, self.enums)
188 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700189 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700190 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700191
Andreas Wundsam5204de22013-07-30 11:34:45 -0700192 @property
193 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700194 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700195 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700196
197 factories = OrderedDict()
198
199 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
200 for base_class in sub_factory_classes:
201 package = base_class[2:].lower()
202 remove_prefix = base_class[2].lower() + base_class[3:]
203
204 # HACK need to have a better way to deal with parameterized base classes
205 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
206
207 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
208 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
209
210 factories[""] = OFFactory(
211 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700212 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700213 remove_prefix="",
214 members=[], base_class="OFMessage", sub_factories=OrderedDict(
215 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
216
217 for i in self.interfaces:
218 for n, factory in factories.items():
219 if n == "":
220 factory.members.append(i)
221 break
222 else:
223 super_class = self.interface_by_name(n)
224 if i.is_instance_of(super_class):
225 factory.members.append(i)
226 break
227 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700228
229 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700230 """ return wether or not to generate implementation class clazz.
231 Now true for everything except OFTableModVer10.
232 @param clazz JavaOFClass instance
233 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700234 if clazz.interface.name.startswith("OFMatchV"):
235 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700236 elif clazz.name == "OFTableModVer10":
237 # tablemod ver 10 is a hack and has no oftype defined
238 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700239 if loxi_utils.class_is_message(clazz.interface.c_name):
240 return True
241 if loxi_utils.class_is_oxm(clazz.interface.c_name):
242 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700243 if loxi_utils.class_is_action(clazz.interface.c_name):
244 return True
245 if loxi_utils.class_is_instruction(clazz.interface.c_name):
246 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700247 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700248 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700249
250
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700251class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700252 @property
253 def factory_classes(self):
254 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700255 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700256 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700257 interface=self,
258 version=version
259 ) for version in model.versions ]
260
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700261 def method_name(self, member, builder=True):
262 n = member.variable_name
263 if n.startswith(self.remove_prefix):
264 n = n[len(self.remove_prefix):]
265 n = n[0].lower() + n[1:]
266 if builder:
267 return "build" + n[0].upper() + n[1:]
268 else:
269 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270
271OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700272class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
273 @property
274 def base_class(self):
275 return self.interface.base_class
276
277 @property
278 def versioned_base_class(self):
279 base_class_interface = model.interface_by_name(self.interface.base_class)
280 if base_class_interface and base_class_interface.has_version(self.version):
281 return base_class_interface.versioned_class(self.version)
282 else:
283 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700284
Andreas Wundsam27303462013-07-16 12:52:35 -0700285model = JavaModel()
286
287#######################################################################
288### OFVersion
289#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700290
291class JavaOFVersion(object):
292 """ Models a version of OpenFlow. contains methods to convert the internal
293 Loxi version to a java constant / a string """
294 def __init__(self, int_version):
295 self.int_version = int(int_version)
296
297 @property
298 def of_version(self):
299 return "1" + str(int(self.int_version) - 1)
300
301 @property
302 def constant_version(self):
303 return "OF_" + self.of_version
304
Andreas Wundsam27303462013-07-16 12:52:35 -0700305 def __repr__(self):
306 return "JavaOFVersion(%d)" % self.int_version
307
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700308 def __str__(self):
309 return of_g.param_version_names[self.int_version]
310
Andreas Wundsam27303462013-07-16 12:52:35 -0700311 def __hash__(self):
312 return hash(self.int_version)
313
314 def __eq__(self, other):
315 if other is None or type(self) != type(other):
316 return False
317 return (self.int_version,) == (other.int_version,)
318
319#######################################################################
320### Interface
321#######################################################################
322
323class JavaOFInterface(object):
324 """ Models an OpenFlow Message class for the purpose of the java class.
325 Version agnostic, in contrast to the loxi_ir python model.
326 """
327 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700328 """"
329 @param c_name: loxi style name (e.g., of_flow_add)
330 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
331 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700332 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700333 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700334 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700335 self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700336 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700337 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700338 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700339 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700340 self.constant_name = c_name.upper().replace("OF_", "")
341
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700342 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700343 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700344 if self.name != parent_interface:
345 self.parent_interface = parent_interface
346 else:
347 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700348
349 def is_instance_of(self, other_class):
350 if self == other_class:
351 return True
352 parent = self.super_class
353 if parent is None:
354 return False
355 else:
356 return parent.is_instance_of(other_class)
357
358 @property
359 def super_class(self):
360 if not self.parent_interface:
361 return None
362 else:
363 return model.interface_by_name(self.parent_interface)
364
365
366 def inherited_declaration(self, type_spec="?"):
367 if self.type_annotation:
368 return "%s<%s>" % (self.name, type_spec)
369 else:
370 return "%s" % self.name
371
372 @property
373 def type_variable(self):
374 if self.type_annotation:
375 return "<T>"
376 else:
377 return "";
378
Andreas Wundsam27303462013-07-16 12:52:35 -0700379 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700380 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
381 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
382 # model (note, that the loxi model is on versioned classes). Should check/infer the
383 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700384 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700385 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700386 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700387 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700388 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700389 return ("", "OFFlowMod", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700390 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700391 return ("", "OFBsnHeader", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700392 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700393 return ("", "OFNiciraHeader", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700394 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700395 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700396 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700397 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700398 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700399 if re.match(r'OFActionBsn.+', self.name):
400 return ("action", "OFActionBsn", None)
401 elif re.match(r'OFActionNicira.+', self.name):
402 return ("action", "OFActionNicira", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700403 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700404 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700405 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 return ("", "OFBsnVport", None)
407 elif self.name == "OFOxm":
408 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700409 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700410 if self.name in model.oxm_map:
411 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
412 else:
413 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700414 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700415 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700416 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700417 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700418 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700419 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700420 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700421 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700422 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700423 return ("", None, None)
424
425 @property
426 @memoize
427 def writeable_members(self):
428 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700429
430 @property
431 @memoize
432 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700433 return self.ir_model_members + self.virtual_members
434
435 @property
436 @memoize
437 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700438 """return a list of all members to be exposed by this interface. Corresponds to
439 the union of the members of the vesioned classes without length, fieldlength
440 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700441 all_versions = []
442 member_map = collections.OrderedDict()
443
444 for (version, of_class) in self.version_map.items():
445 for of_member in of_class.members:
446 if isinstance(of_member, OFLengthMember) or \
447 isinstance(of_member, OFFieldLengthMember) or \
448 isinstance(of_member, OFPadMember):
449 continue
450 if of_member.name not in member_map:
451 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
452
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700453 return tuple(member_map.values())
454
455 @property
456 def virtual_members(self):
457 if self.name == "OFOxm":
458 return (
459 JavaVirtualMember(self, "value", java_type.generic_t),
460 JavaVirtualMember(self, "mask", java_type.generic_t),
461 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
462 JavaVirtualMember(self, "masked", java_type.boolean),
463 )
464 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
465 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
466 if self.name in model.oxm_map \
467 else java_type.make_match_field_jtype()
468
469 return (
470 JavaVirtualMember(self, "matchField", field_type),
471 JavaVirtualMember(self, "masked", java_type.boolean),
472 ) \
473 + \
474 (
475 ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
476 ()
477 )
478 else:
479 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700480
481 @property
482 @memoize
483 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700484 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700485 return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
Andreas Wundsam27303462013-07-16 12:52:35 -0700486
487 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700488 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700489 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700490 return len(self.all_versions) == len(model.versions)
491
492 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700493 @memoize
494 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700495 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700496 return self.version_map.keys()
497
Andreas Wundsam5204de22013-07-30 11:34:45 -0700498 def has_version(self, version):
499 return version in self.version_map
500
Andreas Wundsam27303462013-07-16 12:52:35 -0700501 def versioned_class(self, version):
502 return JavaOFClass(self, version, self.version_map[version])
503
504 @property
505 @memoize
506 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700507 return [ self.versioned_class(version) for version in self.all_versions ]
508
509#######################################################################
510### (Versioned) Classes
511#######################################################################
512
513class JavaOFClass(object):
514 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700515 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700516 """
517 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700518 """
519 @param interface JavaOFInterface instance of the parent interface
520 @param version JavaOFVersion
521 @param ir_class OFClass from loxi_ir
522 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700523 self.interface = interface
524 self.ir_class = ir_class
525 self.c_name = self.ir_class.name
526 self.version = version
527 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700528 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700529 self.generated = False
530
531 @property
532 @memoize
533 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700534 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700535
536 @property
537 def name(self):
538 return "%sVer%s" % (self.interface.name, self.version.of_version)
539
540 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700541 def variable_name(self):
542 return self.name[3:]
543
544 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700545 def length(self):
546 if self.is_fixed_length:
547 return self.min_length
548 else:
549 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
550
551 @property
552 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700553 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700554 id_tuple = (self.ir_class.name, self.version.int_version)
555 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
556
557 @property
558 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700559 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700560 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
561
562 def all_properties(self):
563 return self.interface.members
564
565 def get_member(self, name):
566 for m in self.members:
567 if m.name == name:
568 return m
569
570 @property
571 @memoize
572 def data_members(self):
573 return [ prop for prop in self.members if prop.is_data ]
574
575 @property
576 @memoize
577 def fixed_value_members(self):
578 return [ prop for prop in self.members if prop.is_fixed_value ]
579
580 @property
581 @memoize
582 def public_members(self):
583 return [ prop for prop in self.members if prop.is_public ]
584
585 @property
586 @memoize
587 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700588 return self.ir_model_members + self.virtual_members
589
590 @property
591 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700592 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700593 return tuple(members)
594
595 @property
596 def virtual_members(self):
597 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
598 if self.interface.name in model.oxm_map:
599 oxm_entry = model.oxm_map[self.interface.name]
600 return (
601 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
602 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
603 )
604 else:
605 return (
606 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
607 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
608 )
609 else:
610 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700611
612 def all_versions(self):
613 return [ JavaOFVersion(int_version)
614 for int_version in of_g.unified[self.c_name]
615 if int_version != 'union' and int_version != 'object_id' ]
616
617 def version_is_inherited(self, version):
618 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
619
620 def inherited_from(self, version):
621 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
622
623 @property
624 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700625 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
626
627 @property
628 def discriminator(self):
629 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700630
631 @property
632 def is_extension(self):
633 return type_maps.message_is_extension(self.c_name, -1)
634
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700635 @property
636 def align(self):
637 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
638
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700639 @property
640 @memoize
641 def superclass(self):
642 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
643
644 @property
645 @memoize
646 def subclasses(self):
647 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
648
Andreas Wundsam27303462013-07-16 12:52:35 -0700649#######################################################################
650### Member
651#######################################################################
652
653
654class JavaMember(object):
655 """ Models a property (member) of an openflow class. """
656 def __init__(self, msg, name, java_type, member):
657 self.msg = msg
658 self.name = name
659 self.java_type = java_type
660 self.member = member
661 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700662
663 @property
664 def title_name(self):
665 return self.name[0].upper() + self.name[1:]
666
667 @property
668 def constant_name(self):
669 return self.c_name.upper()
670
671 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700672 def getter_name(self):
673 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
674
675 @property
676 def setter_name(self):
677 return "set" + self.title_name
678
679 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700680 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700681 if self.is_fixed_value:
682 return self.constant_name
683 else:
684 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700685
686 @property
687 def default_value(self):
688 java_type = self.java_type.public_type;
689
Andreas Wundsam27303462013-07-16 12:52:35 -0700690 if self.is_fixed_value:
691 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700692 elif java_type == "OFOxmList":
693 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700694 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700695 return "Collections.emptyList()"
696 elif java_type == "boolean":
697 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700698 elif self.java_type.is_array:
699 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700700 elif java_type in ("byte", "char", "short", "int", "long"):
701 return "({0}) 0".format(java_type);
702 else:
703 return "null";
704
705 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700706 def enum_value(self):
707 if self.name == "version":
708 return "OFVersion.%s" % self.msg.version.constant_version
709
710 java_type = self.java_type.public_type;
711 try:
712 global model
713 enum = model.enum_by_name(java_type)
714 entry = enum.entry_by_version_value(self.msg.version, self.value)
715 return "%s.%s" % ( enum.name, entry.name)
716 except KeyError, e:
717 print e.message
718 return self.value
719
720 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700721 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700722 return isinstance(self.member, OFPadMember)
723
724 def is_type_value(self, version=None):
725 if(version==None):
726 return any(self.is_type_value(version) for version in self.msg.all_versions)
727 try:
728 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
729 except:
730 return False
731
732 @property
733 def is_field_length_value(self):
734 return isinstance(self.member, OFFieldLengthMember)
735
736 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700737 def is_discriminator(self):
738 return isinstance(self.member, OFDiscriminatorMember)
739
740 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700741 def is_length_value(self):
742 return isinstance(self.member, OFLengthMember)
743
744 @property
745 def is_public(self):
746 return not (self.is_pad or self.is_length_value)
747
748 @property
749 def is_data(self):
750 return isinstance(self.member, OFDataMember) and self.name != "version"
751
752 @property
753 def is_fixed_value(self):
754 return hasattr(self.member, "value") or self.name == "version" \
755 or ( self.name == "length" and self.msg.is_fixed_length) \
756 or ( self.name == "len" and self.msg.is_fixed_length)
757
758 @property
759 def value(self):
760 if self.name == "version":
761 return self.msg.version.int_version
762 elif self.name == "length" or self.name == "len":
763 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700764 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700765 return self.java_type.format_value(self.member.value)
766
767 @property
768 def priv_value(self):
769 if self.name == "version":
770 return self.msg.version.int_version
771 elif self.name == "length" or self.name == "len":
772 return self.msg.length
773 else:
774 return self.java_type.format_value(self.member.value, pub_type=False)
775
Andreas Wundsam27303462013-07-16 12:52:35 -0700776
777 @property
778 def is_writeable(self):
779 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
780
781 def get_type_value_info(self, version):
782 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700783
784 @property
785 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 if hasattr(self.member, "length"):
787 return self.member.length
788 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700789 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700790 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700791
792 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700793 def for_of_member(java_class, member):
794 if isinstance(member, OFPadMember):
795 return JavaMember(None, "", None, member)
796 else:
797 if member.name == 'len':
798 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700799 elif member.name == 'value_mask':
800 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700801 else:
802 name = java_type.name_c_to_camel(member.name)
803 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
804 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700805
806 @property
807 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700808 if not self.msg.c_name in of_g.unified:
809 print("%s not self.unified" % self.msg.c_name)
810 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700811 for version in of_g.unified[self.msg.c_name]:
812 if version == 'union' or version =='object_id':
813 continue
814 if 'use_version' in of_g.unified[self.msg.c_name][version]:
815 continue
816
Andreas Wundsam27303462013-07-16 12:52:35 -0700817 if not self.member.name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700818 return False
819 return True
820
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700821 @property
822 def is_virtual(self):
823 return False
824
Andreas Wundsam27303462013-07-16 12:52:35 -0700825 def __hash__(self):
826 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700827
Andreas Wundsam27303462013-07-16 12:52:35 -0700828 def __eq__(self, other):
829 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700830 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700831 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700832
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700833class JavaVirtualMember(JavaMember):
834 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
835 def __init__(self, msg, name, java_type, value=None):
836 JavaMember.__init__(self, msg, name, java_type, member=None)
837 self._value = value
838
839 @property
840 def is_fixed_value(self):
841 return True
842
843 @property
844 def value(self):
845 return self._value
846
847 @property
848 def priv_value(self):
849 return self._value
850
851
852 @property
853 def is_universal(self):
854 return True
855
856 @property
857 def is_virtual(self):
858 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700859
860#######################################################################
861### Unit Test
862#######################################################################
863
Yotam Harchol466b3212013-08-15 12:14:46 -0700864class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700865 def __init__(self, java_class):
866 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700867 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700868 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700869 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
870 name=java_class.c_name[3:]) + "{i}.data"
871 test_class_name = self.java_class.name + "Test"
872 self.test_units = []
873 if test_data.exists(first_data_file_name):
874 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
875 i = 1
876 while test_data.exists(data_file_template.format(i=i)):
877 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
878 i = i + 1
879
880 @property
881 def package(self):
882 return self.java_class.package
883
884 @property
885 def has_test_data(self):
886 return len(self.test_units) > 0
887
888 @property
889 def length(self):
890 return len(self.test_units)
891
892 def get_test_unit(self, i):
893 return self.test_units[i]
894
895
896class JavaUnitTest(object):
897 def __init__(self, java_class, file_name=None, test_class_name=None):
898 self.java_class = java_class
899 if file_name is None:
900 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
901 name=java_class.c_name[3:])
902 else:
903 self.data_file_name = file_name
904 if test_class_name is None:
905 self.test_class_name = self.java_class.name + "Test"
906 else:
907 self.test_class_name = test_class_name
908
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700909 @property
910 def package(self):
911 return self.java_class.package
912
913 @property
914 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700915 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700916
917 @property
918 def has_test_data(self):
919 return test_data.exists(self.data_file_name)
920
921 @property
922 @memoize
923 def test_data(self):
924 return test_data.read(self.data_file_name)
925
926
Andreas Wundsam27303462013-07-16 12:52:35 -0700927#######################################################################
928### Enums
929#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700930
Andreas Wundsam27303462013-07-16 12:52:35 -0700931class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700932 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700933 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700934
935 if c_name == "of_stats_types":
936 self.name = "OFStatsType"
937 else:
938 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700939
Andreas Wundsam27303462013-07-16 12:52:35 -0700940 # Port_features has constants that start with digits
941 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700942
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700943 self.version_enums = version_enum_map
944
945 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
946 for version, ir_enum in version_enum_map.items():
947 for ir_entry in ir_enum.entries:
948 if "virtual" in ir_entry.params:
949 continue
950 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
951
Andreas Wundsam27303462013-07-16 12:52:35 -0700952 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700953 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700954
955 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Yotam Harchol791e4882013-09-05 16:32:56 -0700956 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700957
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700958 def wire_type(self, version):
959 ir_enum = self.version_enums[version]
960 if "wire_type" in ir_enum.params:
961 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
962 else:
963 return java_type.u8
964
965 @property
966 def versions(self):
967 return self.version_enums.keys()
968
Andreas Wundsam27303462013-07-16 12:52:35 -0700969 @memoize
970 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700971 res = find(lambda e: e.name == name, self.entries)
972 if res:
973 return res
974 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700975 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
976
977 @memoize
978 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700979 res = find(lambda e: e.c_name == name, self.entries)
980 if res:
981 return res
982 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700983 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
984
985 @memoize
986 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700987 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
988 if res:
989 return res
990 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700991 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
992
993# values: Map JavaVersion->Value
994class JavaEnumEntry(object):
995 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700996 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700997 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
998 self.values = values
999
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001000 def has_value(self, version):
1001 return version in self.values
1002
Andreas Wundsam27303462013-07-16 12:52:35 -07001003 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001004 return self.values[version]
1005
1006 def format_value(self, version):
1007 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001008 return res
1009
Andreas Wundsam27303462013-07-16 12:52:35 -07001010 def all_values(self, versions, not_present=None):
1011 return [ self.values[version] if version in self.values else not_present for version in versions ]