blob: 19ca09026301341d89efd657e06fc5aad7783c60 [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 Wundsamb1da3f62013-09-04 18:46:03 -070054 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
55 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsam001b1822013-08-02 22:25:55 -070056 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070057
Andreas Wundsam2be7da52013-08-22 07:34:25 -070058 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070059 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
60 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
61 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
62 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
63 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
64 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
65 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
66 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
67 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
68 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
69 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
70 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
71 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
72 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
73 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
74 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
75 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
76 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
77 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
78 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
79 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
80 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
81 "OFOxmIpv4Src": OxmMapEntry("IPv4", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4", "IPV4_DST", True),
85 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
86 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
87 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
88 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
89 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
90 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
91 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
92 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
93 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
94 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
95 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
96 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
97 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
98 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
99 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
100 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
101 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
102 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
103 "OFOxmArpSpa": OxmMapEntry("IPv4", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4", "ARP_TPA", True),
107 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
108 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
109 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
110 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
111 "OFOxmIpv6Src": OxmMapEntry("IPv6", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6", "IPV6_DST", True),
115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True) }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700117
Andreas Wundsam27303462013-07-16 12:52:35 -0700118 @property
119 @memoize
120 def versions(self):
121 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
122
123 @property
124 @memoize
125 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700126 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700127
128 for raw_version, of_protocol in of_g.ir.items():
129 jversion = JavaOFVersion(of_protocol.wire_version)
130
131 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700132 if not of_class.name in version_map_per_class:
133 version_map_per_class[of_class.name] = collections.OrderedDict()
134
Andreas Wundsam27303462013-07-16 12:52:35 -0700135 version_map_per_class[of_class.name][jversion] = of_class
136
137 interfaces = []
138 for class_name, version_map in version_map_per_class.items():
139 interfaces.append(JavaOFInterface(class_name, version_map))
140
Andreas Wundsambe168f72013-08-03 22:49:35 -0700141 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
142
Andreas Wundsam27303462013-07-16 12:52:35 -0700143 return interfaces
144
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700145 @memoize
146 def interface_by_name(self, name):
147 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
148
Andreas Wundsam27303462013-07-16 12:52:35 -0700149 @property
150 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700151 def all_classes(self):
152 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
153
154 @property
155 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700156 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700157 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700158
159 for version in self.versions:
160 of_protocol = of_g.ir[version.int_version]
161 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700162 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700163
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700164 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
165 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700166
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700167 # inelegant - need java name here
168 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700169 return enums
170
171 @memoize
172 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700173 res = find(lambda e: e.name == name, self.enums)
174 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700175 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700176 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700177
Andreas Wundsam5204de22013-07-30 11:34:45 -0700178 @property
179 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700180 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700181 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700182
183 factories = OrderedDict()
184
185 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
186 for base_class in sub_factory_classes:
187 package = base_class[2:].lower()
188 remove_prefix = base_class[2].lower() + base_class[3:]
189
190 # HACK need to have a better way to deal with parameterized base classes
191 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
192
193 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
194 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
195
196 factories[""] = OFFactory(
197 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700198 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700199 remove_prefix="",
200 members=[], base_class="OFMessage", sub_factories=OrderedDict(
201 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
202
203 for i in self.interfaces:
204 for n, factory in factories.items():
205 if n == "":
206 factory.members.append(i)
207 break
208 else:
209 super_class = self.interface_by_name(n)
210 if i.is_instance_of(super_class):
211 factory.members.append(i)
212 break
213 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700214
215 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700216 """ return wether or not to generate implementation class clazz.
217 Now true for everything except OFTableModVer10.
218 @param clazz JavaOFClass instance
219 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700220 if clazz.interface.name.startswith("OFMatchV"):
221 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700222 elif clazz.name == "OFTableModVer10":
223 # tablemod ver 10 is a hack and has no oftype defined
224 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700225 if loxi_utils.class_is_message(clazz.interface.c_name):
226 return True
227 if loxi_utils.class_is_oxm(clazz.interface.c_name):
228 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700229 if loxi_utils.class_is_action(clazz.interface.c_name):
230 return True
231 if loxi_utils.class_is_instruction(clazz.interface.c_name):
232 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700233 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700234 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700235
236
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700237class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700238 @property
239 def factory_classes(self):
240 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700241 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700242 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700243 interface=self,
244 version=version
245 ) for version in model.versions ]
246
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700247 def method_name(self, member, builder=True):
248 n = member.variable_name
249 if n.startswith(self.remove_prefix):
250 n = n[len(self.remove_prefix):]
251 n = n[0].lower() + n[1:]
252 if builder:
253 return "build" + n[0].upper() + n[1:]
254 else:
255 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700256
257OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700258class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
259 @property
260 def base_class(self):
261 return self.interface.base_class
262
263 @property
264 def versioned_base_class(self):
265 base_class_interface = model.interface_by_name(self.interface.base_class)
266 if base_class_interface and base_class_interface.has_version(self.version):
267 return base_class_interface.versioned_class(self.version)
268 else:
269 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270
Andreas Wundsam27303462013-07-16 12:52:35 -0700271model = JavaModel()
272
273#######################################################################
274### OFVersion
275#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700276
277class JavaOFVersion(object):
278 """ Models a version of OpenFlow. contains methods to convert the internal
279 Loxi version to a java constant / a string """
280 def __init__(self, int_version):
281 self.int_version = int(int_version)
282
283 @property
284 def of_version(self):
285 return "1" + str(int(self.int_version) - 1)
286
287 @property
288 def constant_version(self):
289 return "OF_" + self.of_version
290
Andreas Wundsam27303462013-07-16 12:52:35 -0700291 def __repr__(self):
292 return "JavaOFVersion(%d)" % self.int_version
293
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700294 def __str__(self):
295 return of_g.param_version_names[self.int_version]
296
Andreas Wundsam27303462013-07-16 12:52:35 -0700297 def __hash__(self):
298 return hash(self.int_version)
299
300 def __eq__(self, other):
301 if other is None or type(self) != type(other):
302 return False
303 return (self.int_version,) == (other.int_version,)
304
305#######################################################################
306### Interface
307#######################################################################
308
309class JavaOFInterface(object):
310 """ Models an OpenFlow Message class for the purpose of the java class.
311 Version agnostic, in contrast to the loxi_ir python model.
312 """
313 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700314 """"
315 @param c_name: loxi style name (e.g., of_flow_add)
316 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
317 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700318 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700319 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700320 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700321 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 -0700322 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700323 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700324 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700325 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700326 self.constant_name = c_name.upper().replace("OF_", "")
327
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700328 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700329 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700330 if self.name != parent_interface:
331 self.parent_interface = parent_interface
332 else:
333 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700334
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700335 @property
336 @memoize
337 def all_parent_interfaces(self):
338 return [ "OFObject" ] + \
339 ([ self.parent_interface ] if self.parent_interface else [] )+ \
340 self.additional_parent_interfaces
341 @property
342 @memoize
343 def additional_parent_interfaces(self):
344 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
345 m = re.match(r'(.*)Request$', self.name)
346 if m:
347 reply_name = m.group(1) + "Reply"
348 if model.interface_by_name(reply_name):
349 return ["OFRequest<%s>" % reply_name ]
350 return []
351
352
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700353 def is_instance_of(self, other_class):
354 if self == other_class:
355 return True
356 parent = self.super_class
357 if parent is None:
358 return False
359 else:
360 return parent.is_instance_of(other_class)
361
362 @property
363 def super_class(self):
364 if not self.parent_interface:
365 return None
366 else:
367 return model.interface_by_name(self.parent_interface)
368
369
370 def inherited_declaration(self, type_spec="?"):
371 if self.type_annotation:
372 return "%s<%s>" % (self.name, type_spec)
373 else:
374 return "%s" % self.name
375
376 @property
377 def type_variable(self):
378 if self.type_annotation:
379 return "<T>"
380 else:
381 return "";
382
Andreas Wundsam27303462013-07-16 12:52:35 -0700383 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700384 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
385 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
386 # model (note, that the loxi model is on versioned classes). Should check/infer the
387 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700388 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700389 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700390 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700391 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700392 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700393 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700394 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name) and self.name != "OFBsnHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700395 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700396 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name) and self.name != "OFNiciraHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700397 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700398 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
399 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700400 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700401 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700402 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700403 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700404 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700405 if re.match(r'OFActionBsn.+', self.name):
406 return ("action", "OFActionBsn", None)
407 elif re.match(r'OFActionNicira.+', self.name):
408 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700409 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
410 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700411 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700412 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700413 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700414 return ("", "OFBsnVport", None)
415 elif self.name == "OFOxm":
416 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700417 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700418 if self.name in model.oxm_map:
419 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
420 else:
421 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700422 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700423 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700424 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700425 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700426 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700427 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700428 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700429 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700430 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700431 return ("", None, None)
432
433 @property
434 @memoize
435 def writeable_members(self):
436 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700437
438 @property
439 @memoize
440 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700441 return self.ir_model_members + self.virtual_members
442
443 @property
444 @memoize
445 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700446 """return a list of all members to be exposed by this interface. Corresponds to
447 the union of the members of the vesioned classes without length, fieldlength
448 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700449 all_versions = []
450 member_map = collections.OrderedDict()
451
452 for (version, of_class) in self.version_map.items():
453 for of_member in of_class.members:
454 if isinstance(of_member, OFLengthMember) or \
455 isinstance(of_member, OFFieldLengthMember) or \
456 isinstance(of_member, OFPadMember):
457 continue
458 if of_member.name not in member_map:
459 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
460
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700461 return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700462
463 @property
464 def virtual_members(self):
465 if self.name == "OFOxm":
466 return (
467 JavaVirtualMember(self, "value", java_type.generic_t),
468 JavaVirtualMember(self, "mask", java_type.generic_t),
469 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
470 JavaVirtualMember(self, "masked", java_type.boolean),
471 )
472 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
473 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
474 if self.name in model.oxm_map \
475 else java_type.make_match_field_jtype()
476
477 return (
478 JavaVirtualMember(self, "matchField", field_type),
479 JavaVirtualMember(self, "masked", java_type.boolean),
480 ) \
481 + \
482 (
483 ( 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
484 ()
485 )
486 else:
487 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700488
489 @property
490 @memoize
491 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700492 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700493 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 -0700494
495 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700496 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700497 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700498 return len(self.all_versions) == len(model.versions)
499
500 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700501 @memoize
502 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700503 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700504 return self.version_map.keys()
505
Andreas Wundsam5204de22013-07-30 11:34:45 -0700506 def has_version(self, version):
507 return version in self.version_map
508
Andreas Wundsam27303462013-07-16 12:52:35 -0700509 def versioned_class(self, version):
510 return JavaOFClass(self, version, self.version_map[version])
511
512 @property
513 @memoize
514 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700515 return [ self.versioned_class(version) for version in self.all_versions ]
516
517#######################################################################
518### (Versioned) Classes
519#######################################################################
520
521class JavaOFClass(object):
522 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700523 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700524 """
525 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700526 """
527 @param interface JavaOFInterface instance of the parent interface
528 @param version JavaOFVersion
529 @param ir_class OFClass from loxi_ir
530 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700531 self.interface = interface
532 self.ir_class = ir_class
533 self.c_name = self.ir_class.name
534 self.version = version
535 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700536 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700537 self.generated = False
538
539 @property
540 @memoize
541 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700542 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700543
544 @property
545 def name(self):
546 return "%sVer%s" % (self.interface.name, self.version.of_version)
547
548 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700549 def variable_name(self):
550 return self.name[3:]
551
552 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700553 def length(self):
554 if self.is_fixed_length:
555 return self.min_length
556 else:
557 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
558
559 @property
560 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700561 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700562 id_tuple = (self.ir_class.name, self.version.int_version)
563 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
564
565 @property
566 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700567 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
569
570 def all_properties(self):
571 return self.interface.members
572
573 def get_member(self, name):
574 for m in self.members:
575 if m.name == name:
576 return m
577
578 @property
579 @memoize
580 def data_members(self):
581 return [ prop for prop in self.members if prop.is_data ]
582
583 @property
584 @memoize
585 def fixed_value_members(self):
586 return [ prop for prop in self.members if prop.is_fixed_value ]
587
588 @property
589 @memoize
590 def public_members(self):
591 return [ prop for prop in self.members if prop.is_public ]
592
593 @property
594 @memoize
595 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700596 return self.ir_model_members + self.virtual_members
597
598 @property
599 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700600 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700601 return tuple(members)
602
603 @property
604 def virtual_members(self):
605 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
606 if self.interface.name in model.oxm_map:
607 oxm_entry = model.oxm_map[self.interface.name]
608 return (
609 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
610 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
611 )
612 else:
613 return (
614 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
615 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
616 )
617 else:
618 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700619
620 def all_versions(self):
621 return [ JavaOFVersion(int_version)
622 for int_version in of_g.unified[self.c_name]
623 if int_version != 'union' and int_version != 'object_id' ]
624
625 def version_is_inherited(self, version):
626 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
627
628 def inherited_from(self, version):
629 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
630
631 @property
632 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700633 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
634
635 @property
636 def discriminator(self):
637 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700638
639 @property
640 def is_extension(self):
641 return type_maps.message_is_extension(self.c_name, -1)
642
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700643 @property
644 def align(self):
645 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
646
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700647 @property
648 @memoize
649 def superclass(self):
650 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
651
652 @property
653 @memoize
654 def subclasses(self):
655 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
656
Andreas Wundsam27303462013-07-16 12:52:35 -0700657#######################################################################
658### Member
659#######################################################################
660
661
662class JavaMember(object):
663 """ Models a property (member) of an openflow class. """
664 def __init__(self, msg, name, java_type, member):
665 self.msg = msg
666 self.name = name
667 self.java_type = java_type
668 self.member = member
669 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700670
671 @property
672 def title_name(self):
673 return self.name[0].upper() + self.name[1:]
674
675 @property
676 def constant_name(self):
677 return self.c_name.upper()
678
679 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700680 def getter_name(self):
681 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
682
683 @property
684 def setter_name(self):
685 return "set" + self.title_name
686
687 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700688 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700689 if self.is_fixed_value:
690 return self.constant_name
691 else:
692 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700693
694 @property
695 def default_value(self):
696 java_type = self.java_type.public_type;
697
Andreas Wundsam27303462013-07-16 12:52:35 -0700698 if self.is_fixed_value:
699 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700700 elif java_type == "OFOxmList":
701 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700702 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700703 return "Collections.emptyList()"
704 elif java_type == "boolean":
705 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700706 elif self.java_type.is_array:
707 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700708 elif java_type in ("byte", "char", "short", "int", "long"):
709 return "({0}) 0".format(java_type);
710 else:
711 return "null";
712
713 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700714 def enum_value(self):
715 if self.name == "version":
716 return "OFVersion.%s" % self.msg.version.constant_version
717
718 java_type = self.java_type.public_type;
719 try:
720 global model
721 enum = model.enum_by_name(java_type)
722 entry = enum.entry_by_version_value(self.msg.version, self.value)
723 return "%s.%s" % ( enum.name, entry.name)
724 except KeyError, e:
725 print e.message
726 return self.value
727
728 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700729 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700730 return isinstance(self.member, OFPadMember)
731
732 def is_type_value(self, version=None):
733 if(version==None):
734 return any(self.is_type_value(version) for version in self.msg.all_versions)
735 try:
736 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
737 except:
738 return False
739
740 @property
741 def is_field_length_value(self):
742 return isinstance(self.member, OFFieldLengthMember)
743
744 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700745 def is_discriminator(self):
746 return isinstance(self.member, OFDiscriminatorMember)
747
748 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700749 def is_length_value(self):
750 return isinstance(self.member, OFLengthMember)
751
752 @property
753 def is_public(self):
754 return not (self.is_pad or self.is_length_value)
755
756 @property
757 def is_data(self):
758 return isinstance(self.member, OFDataMember) and self.name != "version"
759
760 @property
761 def is_fixed_value(self):
762 return hasattr(self.member, "value") or self.name == "version" \
763 or ( self.name == "length" and self.msg.is_fixed_length) \
764 or ( self.name == "len" and self.msg.is_fixed_length)
765
766 @property
767 def value(self):
768 if self.name == "version":
769 return self.msg.version.int_version
770 elif self.name == "length" or self.name == "len":
771 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700772 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700773 return self.java_type.format_value(self.member.value)
774
775 @property
776 def priv_value(self):
777 if self.name == "version":
778 return self.msg.version.int_version
779 elif self.name == "length" or self.name == "len":
780 return self.msg.length
781 else:
782 return self.java_type.format_value(self.member.value, pub_type=False)
783
Andreas Wundsam27303462013-07-16 12:52:35 -0700784
785 @property
786 def is_writeable(self):
787 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
788
789 def get_type_value_info(self, version):
790 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700791
792 @property
793 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700794 if hasattr(self.member, "length"):
795 return self.member.length
796 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700797 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700798 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700799
800 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700801 def for_of_member(java_class, member):
802 if isinstance(member, OFPadMember):
803 return JavaMember(None, "", None, member)
804 else:
805 if member.name == 'len':
806 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700807 elif member.name == 'value_mask':
808 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700809 else:
810 name = java_type.name_c_to_camel(member.name)
811 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
812 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700813
814 @property
815 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700816 if not self.msg.c_name in of_g.unified:
817 print("%s not self.unified" % self.msg.c_name)
818 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700819 for version in of_g.unified[self.msg.c_name]:
820 if version == 'union' or version =='object_id':
821 continue
822 if 'use_version' in of_g.unified[self.msg.c_name][version]:
823 continue
824
Andreas Wundsam27303462013-07-16 12:52:35 -0700825 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 -0700826 return False
827 return True
828
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700829 @property
830 def is_virtual(self):
831 return False
832
Andreas Wundsam27303462013-07-16 12:52:35 -0700833 def __hash__(self):
834 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700835
Andreas Wundsam27303462013-07-16 12:52:35 -0700836 def __eq__(self, other):
837 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700838 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700839 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700840
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700841class JavaVirtualMember(JavaMember):
842 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
843 def __init__(self, msg, name, java_type, value=None):
844 JavaMember.__init__(self, msg, name, java_type, member=None)
845 self._value = value
846
847 @property
848 def is_fixed_value(self):
849 return True
850
851 @property
852 def value(self):
853 return self._value
854
855 @property
856 def priv_value(self):
857 return self._value
858
859
860 @property
861 def is_universal(self):
862 return True
863
864 @property
865 def is_virtual(self):
866 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700867
868#######################################################################
869### Unit Test
870#######################################################################
871
Yotam Harchol466b3212013-08-15 12:14:46 -0700872class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700873 def __init__(self, java_class):
874 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700875 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700876 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700877 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
878 name=java_class.c_name[3:]) + "{i}.data"
879 test_class_name = self.java_class.name + "Test"
880 self.test_units = []
881 if test_data.exists(first_data_file_name):
882 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
883 i = 1
884 while test_data.exists(data_file_template.format(i=i)):
885 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
886 i = i + 1
887
888 @property
889 def package(self):
890 return self.java_class.package
891
892 @property
893 def has_test_data(self):
894 return len(self.test_units) > 0
895
896 @property
897 def length(self):
898 return len(self.test_units)
899
900 def get_test_unit(self, i):
901 return self.test_units[i]
902
903
904class JavaUnitTest(object):
905 def __init__(self, java_class, file_name=None, test_class_name=None):
906 self.java_class = java_class
907 if file_name is None:
908 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
909 name=java_class.c_name[3:])
910 else:
911 self.data_file_name = file_name
912 if test_class_name is None:
913 self.test_class_name = self.java_class.name + "Test"
914 else:
915 self.test_class_name = test_class_name
916
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700917 @property
918 def package(self):
919 return self.java_class.package
920
921 @property
922 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700923 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700924
925 @property
926 def has_test_data(self):
927 return test_data.exists(self.data_file_name)
928
929 @property
930 @memoize
931 def test_data(self):
932 return test_data.read(self.data_file_name)
933
934
Andreas Wundsam27303462013-07-16 12:52:35 -0700935#######################################################################
936### Enums
937#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700938
Andreas Wundsam27303462013-07-16 12:52:35 -0700939class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700940 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700941 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700942
943 if c_name == "of_stats_types":
944 self.name = "OFStatsType"
945 else:
946 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700947
Andreas Wundsam27303462013-07-16 12:52:35 -0700948 # Port_features has constants that start with digits
949 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700950
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700951 self.version_enums = version_enum_map
952
953 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
954 for version, ir_enum in version_enum_map.items():
955 for ir_entry in ir_enum.entries:
956 if "virtual" in ir_entry.params:
957 continue
958 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
959
Andreas Wundsam27303462013-07-16 12:52:35 -0700960 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700961 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700962
963 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 -0700964 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700965
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700966 def wire_type(self, version):
967 ir_enum = self.version_enums[version]
968 if "wire_type" in ir_enum.params:
969 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
970 else:
971 return java_type.u8
972
973 @property
974 def versions(self):
975 return self.version_enums.keys()
976
Andreas Wundsam27303462013-07-16 12:52:35 -0700977 @memoize
978 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700979 res = find(lambda e: e.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 name %s" % (self.name, name))
984
985 @memoize
986 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700987 res = find(lambda e: e.c_name == name, 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 c_name %s" % (self.name, name))
992
993 @memoize
994 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700995 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
996 if res:
997 return res
998 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700999 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1000
1001# values: Map JavaVersion->Value
1002class JavaEnumEntry(object):
1003 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001004 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001005 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1006 self.values = values
1007
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001008 def has_value(self, version):
1009 return version in self.values
1010
Andreas Wundsam27303462013-07-16 12:52:35 -07001011 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001012 return self.values[version]
1013
1014 def format_value(self, version):
1015 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001016 return res
1017
Andreas Wundsam27303462013-07-16 12:52:35 -07001018 def all_values(self, versions, not_present=None):
1019 return [ self.values[version] if version in self.values else not_present for version in versions ]