blob: 65dac746dfc4dcef4d16ff0468ca118e73f1c805 [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),
115 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True) }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700116
Andreas Wundsam27303462013-07-16 12:52:35 -0700117 @property
118 @memoize
119 def versions(self):
120 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
121
122 @property
123 @memoize
124 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700125 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700126
127 for raw_version, of_protocol in of_g.ir.items():
128 jversion = JavaOFVersion(of_protocol.wire_version)
129
130 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700131 if not of_class.name in version_map_per_class:
132 version_map_per_class[of_class.name] = collections.OrderedDict()
133
Andreas Wundsam27303462013-07-16 12:52:35 -0700134 version_map_per_class[of_class.name][jversion] = of_class
135
136 interfaces = []
137 for class_name, version_map in version_map_per_class.items():
138 interfaces.append(JavaOFInterface(class_name, version_map))
139
Andreas Wundsambe168f72013-08-03 22:49:35 -0700140 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
141
Andreas Wundsam27303462013-07-16 12:52:35 -0700142 return interfaces
143
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700144 @memoize
145 def interface_by_name(self, name):
146 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
147
Andreas Wundsam27303462013-07-16 12:52:35 -0700148 @property
149 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700150 def all_classes(self):
151 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
152
153 @property
154 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700155 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700156 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700157
158 for version in self.versions:
159 of_protocol = of_g.ir[version.int_version]
160 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700161 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700162
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700163 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
164 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700165
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700166 # inelegant - need java name here
167 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700168 return enums
169
170 @memoize
171 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700172 res = find(lambda e: e.name == name, self.enums)
173 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700174 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700175 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700176
Andreas Wundsam5204de22013-07-30 11:34:45 -0700177 @property
178 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700179 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700180 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700181
182 factories = OrderedDict()
183
184 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
185 for base_class in sub_factory_classes:
186 package = base_class[2:].lower()
187 remove_prefix = base_class[2].lower() + base_class[3:]
188
189 # HACK need to have a better way to deal with parameterized base classes
190 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
191
192 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
193 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
194
195 factories[""] = OFFactory(
196 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700197 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700198 remove_prefix="",
199 members=[], base_class="OFMessage", sub_factories=OrderedDict(
200 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
201
202 for i in self.interfaces:
203 for n, factory in factories.items():
204 if n == "":
205 factory.members.append(i)
206 break
207 else:
208 super_class = self.interface_by_name(n)
209 if i.is_instance_of(super_class):
210 factory.members.append(i)
211 break
212 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700213
214 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700215 """ return wether or not to generate implementation class clazz.
216 Now true for everything except OFTableModVer10.
217 @param clazz JavaOFClass instance
218 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700219 if clazz.interface.name.startswith("OFMatchV"):
220 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700221 elif clazz.name == "OFTableModVer10":
222 # tablemod ver 10 is a hack and has no oftype defined
223 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700224 if loxi_utils.class_is_message(clazz.interface.c_name):
225 return True
226 if loxi_utils.class_is_oxm(clazz.interface.c_name):
227 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700228 if loxi_utils.class_is_action(clazz.interface.c_name):
229 return True
230 if loxi_utils.class_is_instruction(clazz.interface.c_name):
231 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700232 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700233 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700234
235
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700236class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700237 @property
238 def factory_classes(self):
239 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700240 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700241 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700242 interface=self,
243 version=version
244 ) for version in model.versions ]
245
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700246 def method_name(self, member, builder=True):
247 n = member.variable_name
248 if n.startswith(self.remove_prefix):
249 n = n[len(self.remove_prefix):]
250 n = n[0].lower() + n[1:]
251 if builder:
252 return "build" + n[0].upper() + n[1:]
253 else:
254 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700255
256OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700257class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
258 @property
259 def base_class(self):
260 return self.interface.base_class
261
262 @property
263 def versioned_base_class(self):
264 base_class_interface = model.interface_by_name(self.interface.base_class)
265 if base_class_interface and base_class_interface.has_version(self.version):
266 return base_class_interface.versioned_class(self.version)
267 else:
268 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700269
Andreas Wundsam27303462013-07-16 12:52:35 -0700270model = JavaModel()
271
272#######################################################################
273### OFVersion
274#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700275
276class JavaOFVersion(object):
277 """ Models a version of OpenFlow. contains methods to convert the internal
278 Loxi version to a java constant / a string """
279 def __init__(self, int_version):
280 self.int_version = int(int_version)
281
282 @property
283 def of_version(self):
284 return "1" + str(int(self.int_version) - 1)
285
286 @property
287 def constant_version(self):
288 return "OF_" + self.of_version
289
Andreas Wundsam27303462013-07-16 12:52:35 -0700290 def __repr__(self):
291 return "JavaOFVersion(%d)" % self.int_version
292
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700293 def __str__(self):
294 return of_g.param_version_names[self.int_version]
295
Andreas Wundsam27303462013-07-16 12:52:35 -0700296 def __hash__(self):
297 return hash(self.int_version)
298
299 def __eq__(self, other):
300 if other is None or type(self) != type(other):
301 return False
302 return (self.int_version,) == (other.int_version,)
303
304#######################################################################
305### Interface
306#######################################################################
307
308class JavaOFInterface(object):
309 """ Models an OpenFlow Message class for the purpose of the java class.
310 Version agnostic, in contrast to the loxi_ir python model.
311 """
312 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700313 """"
314 @param c_name: loxi style name (e.g., of_flow_add)
315 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
316 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700317 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700318 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700319 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700320 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 -0700321 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700322 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700323 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700324 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700325 self.constant_name = c_name.upper().replace("OF_", "")
326
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700327 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700328 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700329 if self.name != parent_interface:
330 self.parent_interface = parent_interface
331 else:
332 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700333
334 def is_instance_of(self, other_class):
335 if self == other_class:
336 return True
337 parent = self.super_class
338 if parent is None:
339 return False
340 else:
341 return parent.is_instance_of(other_class)
342
343 @property
344 def super_class(self):
345 if not self.parent_interface:
346 return None
347 else:
348 return model.interface_by_name(self.parent_interface)
349
350
351 def inherited_declaration(self, type_spec="?"):
352 if self.type_annotation:
353 return "%s<%s>" % (self.name, type_spec)
354 else:
355 return "%s" % self.name
356
357 @property
358 def type_variable(self):
359 if self.type_annotation:
360 return "<T>"
361 else:
362 return "";
363
Andreas Wundsam27303462013-07-16 12:52:35 -0700364 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700365 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
366 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
367 # model (note, that the loxi model is on versioned classes). Should check/infer the
368 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700369 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700370 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700371 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700372 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700373 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700374 return ("", "OFFlowMod", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700375 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700376 return ("", "OFBsnHeader", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700377 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700378 return ("", "OFNiciraHeader", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700379 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700380 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700381 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700382 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700383 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700384 if re.match(r'OFActionBsn.+', self.name):
385 return ("action", "OFActionBsn", None)
386 elif re.match(r'OFActionNicira.+', self.name):
387 return ("action", "OFActionNicira", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700388 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700389 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700390 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700391 return ("", "OFBsnVport", None)
392 elif self.name == "OFOxm":
393 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700394 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700395 if self.name in model.oxm_map:
396 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
397 else:
398 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700399 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700400 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700401 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700402 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700403 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700404 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700405 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700406 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700407 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700408 return ("", None, None)
409
410 @property
411 @memoize
412 def writeable_members(self):
413 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700414
415 @property
416 @memoize
417 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700418 return self.ir_model_members + self.virtual_members
419
420 @property
421 @memoize
422 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700423 """return a list of all members to be exposed by this interface. Corresponds to
424 the union of the members of the vesioned classes without length, fieldlength
425 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700426 all_versions = []
427 member_map = collections.OrderedDict()
428
429 for (version, of_class) in self.version_map.items():
430 for of_member in of_class.members:
431 if isinstance(of_member, OFLengthMember) or \
432 isinstance(of_member, OFFieldLengthMember) or \
433 isinstance(of_member, OFPadMember):
434 continue
435 if of_member.name not in member_map:
436 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
437
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700438 return tuple(member_map.values())
439
440 @property
441 def virtual_members(self):
442 if self.name == "OFOxm":
443 return (
444 JavaVirtualMember(self, "value", java_type.generic_t),
445 JavaVirtualMember(self, "mask", java_type.generic_t),
446 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
447 JavaVirtualMember(self, "masked", java_type.boolean),
448 )
449 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
450 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
451 if self.name in model.oxm_map \
452 else java_type.make_match_field_jtype()
453
454 return (
455 JavaVirtualMember(self, "matchField", field_type),
456 JavaVirtualMember(self, "masked", java_type.boolean),
457 ) \
458 + \
459 (
460 ( 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
461 ()
462 )
463 else:
464 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700465
466 @property
467 @memoize
468 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700469 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700470 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 -0700471
472 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700473 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700474 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700475 return len(self.all_versions) == len(model.versions)
476
477 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700478 @memoize
479 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700480 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700481 return self.version_map.keys()
482
Andreas Wundsam5204de22013-07-30 11:34:45 -0700483 def has_version(self, version):
484 return version in self.version_map
485
Andreas Wundsam27303462013-07-16 12:52:35 -0700486 def versioned_class(self, version):
487 return JavaOFClass(self, version, self.version_map[version])
488
489 @property
490 @memoize
491 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700492 return [ self.versioned_class(version) for version in self.all_versions ]
493
494#######################################################################
495### (Versioned) Classes
496#######################################################################
497
498class JavaOFClass(object):
499 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700500 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700501 """
502 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700503 """
504 @param interface JavaOFInterface instance of the parent interface
505 @param version JavaOFVersion
506 @param ir_class OFClass from loxi_ir
507 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700508 self.interface = interface
509 self.ir_class = ir_class
510 self.c_name = self.ir_class.name
511 self.version = version
512 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700513 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700514 self.generated = False
515
516 @property
517 @memoize
518 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700519 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700520
521 @property
522 def name(self):
523 return "%sVer%s" % (self.interface.name, self.version.of_version)
524
525 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700526 def variable_name(self):
527 return self.name[3:]
528
529 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700530 def length(self):
531 if self.is_fixed_length:
532 return self.min_length
533 else:
534 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
535
536 @property
537 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700538 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700539 id_tuple = (self.ir_class.name, self.version.int_version)
540 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
541
542 @property
543 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700544 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700545 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
546
547 def all_properties(self):
548 return self.interface.members
549
550 def get_member(self, name):
551 for m in self.members:
552 if m.name == name:
553 return m
554
555 @property
556 @memoize
557 def data_members(self):
558 return [ prop for prop in self.members if prop.is_data ]
559
560 @property
561 @memoize
562 def fixed_value_members(self):
563 return [ prop for prop in self.members if prop.is_fixed_value ]
564
565 @property
566 @memoize
567 def public_members(self):
568 return [ prop for prop in self.members if prop.is_public ]
569
570 @property
571 @memoize
572 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700573 return self.ir_model_members + self.virtual_members
574
575 @property
576 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700578 return tuple(members)
579
580 @property
581 def virtual_members(self):
582 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
583 if self.interface.name in model.oxm_map:
584 oxm_entry = model.oxm_map[self.interface.name]
585 return (
586 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
587 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
588 )
589 else:
590 return (
591 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
592 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
593 )
594 else:
595 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700596
597 def all_versions(self):
598 return [ JavaOFVersion(int_version)
599 for int_version in of_g.unified[self.c_name]
600 if int_version != 'union' and int_version != 'object_id' ]
601
602 def version_is_inherited(self, version):
603 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
604
605 def inherited_from(self, version):
606 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
607
608 @property
609 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700610 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
611
612 @property
613 def discriminator(self):
614 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700615
616 @property
617 def is_extension(self):
618 return type_maps.message_is_extension(self.c_name, -1)
619
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700620 @property
621 def align(self):
622 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
623
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700624 @property
625 @memoize
626 def superclass(self):
627 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
628
629 @property
630 @memoize
631 def subclasses(self):
632 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
633
Andreas Wundsam27303462013-07-16 12:52:35 -0700634#######################################################################
635### Member
636#######################################################################
637
638
639class JavaMember(object):
640 """ Models a property (member) of an openflow class. """
641 def __init__(self, msg, name, java_type, member):
642 self.msg = msg
643 self.name = name
644 self.java_type = java_type
645 self.member = member
646 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700647
648 @property
649 def title_name(self):
650 return self.name[0].upper() + self.name[1:]
651
652 @property
653 def constant_name(self):
654 return self.c_name.upper()
655
656 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700657 def getter_name(self):
658 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
659
660 @property
661 def setter_name(self):
662 return "set" + self.title_name
663
664 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700665 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700666 if self.is_fixed_value:
667 return self.constant_name
668 else:
669 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700670
671 @property
672 def default_value(self):
673 java_type = self.java_type.public_type;
674
Andreas Wundsam27303462013-07-16 12:52:35 -0700675 if self.is_fixed_value:
676 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700677 elif java_type == "OFOxmList":
678 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700679 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700680 return "Collections.emptyList()"
681 elif java_type == "boolean":
682 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700683 elif self.java_type.is_array:
684 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700685 elif java_type in ("byte", "char", "short", "int", "long"):
686 return "({0}) 0".format(java_type);
687 else:
688 return "null";
689
690 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700691 def enum_value(self):
692 if self.name == "version":
693 return "OFVersion.%s" % self.msg.version.constant_version
694
695 java_type = self.java_type.public_type;
696 try:
697 global model
698 enum = model.enum_by_name(java_type)
699 entry = enum.entry_by_version_value(self.msg.version, self.value)
700 return "%s.%s" % ( enum.name, entry.name)
701 except KeyError, e:
702 print e.message
703 return self.value
704
705 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700706 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700707 return isinstance(self.member, OFPadMember)
708
709 def is_type_value(self, version=None):
710 if(version==None):
711 return any(self.is_type_value(version) for version in self.msg.all_versions)
712 try:
713 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
714 except:
715 return False
716
717 @property
718 def is_field_length_value(self):
719 return isinstance(self.member, OFFieldLengthMember)
720
721 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700722 def is_discriminator(self):
723 return isinstance(self.member, OFDiscriminatorMember)
724
725 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700726 def is_length_value(self):
727 return isinstance(self.member, OFLengthMember)
728
729 @property
730 def is_public(self):
731 return not (self.is_pad or self.is_length_value)
732
733 @property
734 def is_data(self):
735 return isinstance(self.member, OFDataMember) and self.name != "version"
736
737 @property
738 def is_fixed_value(self):
739 return hasattr(self.member, "value") or self.name == "version" \
740 or ( self.name == "length" and self.msg.is_fixed_length) \
741 or ( self.name == "len" and self.msg.is_fixed_length)
742
743 @property
744 def value(self):
745 if self.name == "version":
746 return self.msg.version.int_version
747 elif self.name == "length" or self.name == "len":
748 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700749 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700750 return self.java_type.format_value(self.member.value)
751
752 @property
753 def priv_value(self):
754 if self.name == "version":
755 return self.msg.version.int_version
756 elif self.name == "length" or self.name == "len":
757 return self.msg.length
758 else:
759 return self.java_type.format_value(self.member.value, pub_type=False)
760
Andreas Wundsam27303462013-07-16 12:52:35 -0700761
762 @property
763 def is_writeable(self):
764 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
765
766 def get_type_value_info(self, version):
767 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700768
769 @property
770 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700771 if hasattr(self.member, "length"):
772 return self.member.length
773 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700774 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700775 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700776
777 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700778 def for_of_member(java_class, member):
779 if isinstance(member, OFPadMember):
780 return JavaMember(None, "", None, member)
781 else:
782 if member.name == 'len':
783 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700784 elif member.name == 'value_mask':
785 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 else:
787 name = java_type.name_c_to_camel(member.name)
788 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
789 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700790
791 @property
792 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700793 if not self.msg.c_name in of_g.unified:
794 print("%s not self.unified" % self.msg.c_name)
795 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700796 for version in of_g.unified[self.msg.c_name]:
797 if version == 'union' or version =='object_id':
798 continue
799 if 'use_version' in of_g.unified[self.msg.c_name][version]:
800 continue
801
Andreas Wundsam27303462013-07-16 12:52:35 -0700802 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 -0700803 return False
804 return True
805
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700806 @property
807 def is_virtual(self):
808 return False
809
Andreas Wundsam27303462013-07-16 12:52:35 -0700810 def __hash__(self):
811 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700812
Andreas Wundsam27303462013-07-16 12:52:35 -0700813 def __eq__(self, other):
814 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700815 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700816 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700817
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700818class JavaVirtualMember(JavaMember):
819 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
820 def __init__(self, msg, name, java_type, value=None):
821 JavaMember.__init__(self, msg, name, java_type, member=None)
822 self._value = value
823
824 @property
825 def is_fixed_value(self):
826 return True
827
828 @property
829 def value(self):
830 return self._value
831
832 @property
833 def priv_value(self):
834 return self._value
835
836
837 @property
838 def is_universal(self):
839 return True
840
841 @property
842 def is_virtual(self):
843 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700844
845#######################################################################
846### Unit Test
847#######################################################################
848
Yotam Harchol466b3212013-08-15 12:14:46 -0700849class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700850 def __init__(self, java_class):
851 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700852 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700853 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700854 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
855 name=java_class.c_name[3:]) + "{i}.data"
856 test_class_name = self.java_class.name + "Test"
857 self.test_units = []
858 if test_data.exists(first_data_file_name):
859 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
860 i = 1
861 while test_data.exists(data_file_template.format(i=i)):
862 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
863 i = i + 1
864
865 @property
866 def package(self):
867 return self.java_class.package
868
869 @property
870 def has_test_data(self):
871 return len(self.test_units) > 0
872
873 @property
874 def length(self):
875 return len(self.test_units)
876
877 def get_test_unit(self, i):
878 return self.test_units[i]
879
880
881class JavaUnitTest(object):
882 def __init__(self, java_class, file_name=None, test_class_name=None):
883 self.java_class = java_class
884 if file_name is None:
885 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
886 name=java_class.c_name[3:])
887 else:
888 self.data_file_name = file_name
889 if test_class_name is None:
890 self.test_class_name = self.java_class.name + "Test"
891 else:
892 self.test_class_name = test_class_name
893
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700894 @property
895 def package(self):
896 return self.java_class.package
897
898 @property
899 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700900 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700901
902 @property
903 def has_test_data(self):
904 return test_data.exists(self.data_file_name)
905
906 @property
907 @memoize
908 def test_data(self):
909 return test_data.read(self.data_file_name)
910
911
Andreas Wundsam27303462013-07-16 12:52:35 -0700912#######################################################################
913### Enums
914#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700915
Andreas Wundsam27303462013-07-16 12:52:35 -0700916class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700917 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700918 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700919
920 if c_name == "of_stats_types":
921 self.name = "OFStatsType"
922 else:
923 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700924
Andreas Wundsam27303462013-07-16 12:52:35 -0700925 # Port_features has constants that start with digits
926 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700927
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700928 self.version_enums = version_enum_map
929
930 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
931 for version, ir_enum in version_enum_map.items():
932 for ir_entry in ir_enum.entries:
933 if "virtual" in ir_entry.params:
934 continue
935 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
936
Andreas Wundsam27303462013-07-16 12:52:35 -0700937 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700938 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700939
940 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 -0700941 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700942
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700943 def wire_type(self, version):
944 ir_enum = self.version_enums[version]
945 if "wire_type" in ir_enum.params:
946 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
947 else:
948 return java_type.u8
949
950 @property
951 def versions(self):
952 return self.version_enums.keys()
953
Andreas Wundsam27303462013-07-16 12:52:35 -0700954 @memoize
955 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700956 res = find(lambda e: e.name == name, self.entries)
957 if res:
958 return res
959 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700960 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
961
962 @memoize
963 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700964 res = find(lambda e: e.c_name == name, self.entries)
965 if res:
966 return res
967 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700968 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
969
970 @memoize
971 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700972 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
973 if res:
974 return res
975 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700976 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
977
978# values: Map JavaVersion->Value
979class JavaEnumEntry(object):
980 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700981 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700982 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
983 self.values = values
984
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700985 def has_value(self, version):
986 return version in self.values
987
Andreas Wundsam27303462013-07-16 12:52:35 -0700988 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700989 return self.values[version]
990
991 def format_value(self, version):
992 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -0700993 return res
994
Andreas Wundsam27303462013-07-16 12:52:35 -0700995 def all_values(self, versions, not_present=None):
996 return [ self.values[version] if version in self.values else not_present for version in versions ]