blob: 66eeacd51245191962cf0c6319687f4f0faf12e9 [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 Wundsam40e14f72013-05-06 14:49:08 -070047
Andreas Wundsam27303462013-07-16 12:52:35 -070048class JavaModel(object):
Andreas Wundsam43526532013-08-01 22:03:50 -070049 enum_blacklist = set(("OFDefinitions",))
50 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 -070051 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
52 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsam001b1822013-08-02 22:25:55 -070053 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
54 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070055
56 @property
57 @memoize
58 def versions(self):
59 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
60
61 @property
62 @memoize
63 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -070064 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -070065
66 for raw_version, of_protocol in of_g.ir.items():
67 jversion = JavaOFVersion(of_protocol.wire_version)
68
69 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -070070 if not of_class.name in version_map_per_class:
71 version_map_per_class[of_class.name] = collections.OrderedDict()
72
Andreas Wundsam27303462013-07-16 12:52:35 -070073 version_map_per_class[of_class.name][jversion] = of_class
74
75 interfaces = []
76 for class_name, version_map in version_map_per_class.items():
77 interfaces.append(JavaOFInterface(class_name, version_map))
78
Andreas Wundsambe168f72013-08-03 22:49:35 -070079 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
80
Andreas Wundsam27303462013-07-16 12:52:35 -070081 return interfaces
82
83 @property
84 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -070085 def all_classes(self):
86 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
87
88 @property
89 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -070090 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070091 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -070092
93 for version in self.versions:
94 of_protocol = of_g.ir[version.int_version]
95 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070096 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -070097
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070098 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
99 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700100
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700101 # inelegant - need java name here
102 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700103 return enums
104
105 @memoize
106 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700107 res = find(lambda e: e.name == name, self.enums)
108 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700109 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700110 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700111
Andreas Wundsam5204de22013-07-30 11:34:45 -0700112 @property
113 @memoize
114 def of_factory(self):
115 return OFFactory(
116 package="org.openflow.protocol",
117 name="OFFactory",
118 members=self.interfaces)
119
120 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700121 """ return wether or not to generate implementation class clazz.
122 Now true for everything except OFTableModVer10.
123 @param clazz JavaOFClass instance
124 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700125 if clazz.interface.name.startswith("OFMatchV"):
126 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700127 elif clazz.name == "OFTableModVer10":
128 # tablemod ver 10 is a hack and has no oftype defined
129 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700130 if loxi_utils.class_is_message(clazz.interface.c_name):
131 return True
132 if loxi_utils.class_is_oxm(clazz.interface.c_name):
133 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700134 if loxi_utils.class_is_action(clazz.interface.c_name):
135 return True
136 if loxi_utils.class_is_instruction(clazz.interface.c_name):
137 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700138 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700139 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700140
141
142class OFFactory(namedtuple("OFFactory", ("package", "name", "members"))):
143 @property
144 def factory_classes(self):
145 return [ OFFactoryClass(
146 package="org.openflow.protocol.ver{}".format(version.of_version),
147 name="OFFactoryVer{}".format(version.of_version),
148 interface=self,
149 version=version
150 ) for version in model.versions ]
151
152
153OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
154OFFactoryClass = namedtuple("OFFactory", ("package", "name", "interface", "version"))
155
Andreas Wundsam27303462013-07-16 12:52:35 -0700156model = JavaModel()
157
158#######################################################################
159### OFVersion
160#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700161
162class JavaOFVersion(object):
163 """ Models a version of OpenFlow. contains methods to convert the internal
164 Loxi version to a java constant / a string """
165 def __init__(self, int_version):
166 self.int_version = int(int_version)
167
168 @property
169 def of_version(self):
170 return "1" + str(int(self.int_version) - 1)
171
172 @property
173 def constant_version(self):
174 return "OF_" + self.of_version
175
Andreas Wundsam27303462013-07-16 12:52:35 -0700176 def __repr__(self):
177 return "JavaOFVersion(%d)" % self.int_version
178
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700179 def __str__(self):
180 return of_g.param_version_names[self.int_version]
181
Andreas Wundsam27303462013-07-16 12:52:35 -0700182 def __hash__(self):
183 return hash(self.int_version)
184
185 def __eq__(self, other):
186 if other is None or type(self) != type(other):
187 return False
188 return (self.int_version,) == (other.int_version,)
189
190#######################################################################
191### Interface
192#######################################################################
193
194class JavaOFInterface(object):
195 """ Models an OpenFlow Message class for the purpose of the java class.
196 Version agnostic, in contrast to the loxi_ir python model.
197 """
198 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700199 """"
200 @param c_name: loxi style name (e.g., of_flow_add)
201 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
202 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700203 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700204 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700205 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700206 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 -0700207 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700208 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700209 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700210 self.constant_name = c_name.upper().replace("OF_", "")
211
212 pck_suffix, parent_interface = self.class_info()
213 self.package = "org.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.openflow.protocol"
214 if self.name != parent_interface:
215 self.parent_interface = parent_interface
216 else:
217 self.parent_interface = None
Yotam Harchol466b3212013-08-15 12:14:46 -0700218
Andreas Wundsam27303462013-07-16 12:52:35 -0700219 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700220 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
221 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
222 # model (note, that the loxi model is on versioned classes). Should check/infer the
223 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700224 if re.match(r'OF.+StatsRequest$', self.name):
225 return ("", "OFStatsRequest")
226 elif re.match(r'OF.+StatsReply$', self.name):
227 return ("", "OFStatsReply")
228 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700229 return ("", "OFFlowMod")
Andreas Wundsam001b1822013-08-02 22:25:55 -0700230 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
231 return ("", "OFBsnHeader")
232 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
233 return ("", "OFNiciraHeader")
Andreas Wundsam43526532013-08-01 22:03:50 -0700234 elif re.match(r'OFMatch.*', self.name):
235 return ("", "Match")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700236 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700237 return ("", "OFMessage")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700238 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam001b1822013-08-02 22:25:55 -0700239 if re.match(r'OFActionBsn.*', self.name):
240 return ("action", "OFActionBsn")
241 elif re.match(r'OFActionNicira.*', self.name):
242 return ("action", "OFActionNicira")
243 else:
244 return ("action", "OFAction")
245 elif re.match(r'OFBsnVport.+$', self.name):
246 return ("", "OFBsnVport")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700247 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700248 return ("oxm", "OFOxm")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700249 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700250 return ("instruction", "OFInstruction")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700251 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700252 return ("meterband", "OFMeterBand")
Andreas Wundsam001b1822013-08-02 22:25:55 -0700253 elif loxi_utils.class_is_queue_prop(self.c_name):
254 return ("queueprop", "OFQueueProp")
255 elif loxi_utils.class_is_hello_elem(self.c_name):
256 return ("", "OFHelloElem")
Andreas Wundsam27303462013-07-16 12:52:35 -0700257 else:
258 return ("", None)
259
260 @property
261 @memoize
262 def members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700263 """return a list of all members to be exposed by this interface. Corresponds to
264 the union of the members of the vesioned classes without length, fieldlength
265 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700266 all_versions = []
267 member_map = collections.OrderedDict()
268
269 for (version, of_class) in self.version_map.items():
270 for of_member in of_class.members:
271 if isinstance(of_member, OFLengthMember) or \
272 isinstance(of_member, OFFieldLengthMember) or \
273 isinstance(of_member, OFPadMember):
274 continue
275 if of_member.name not in member_map:
276 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
277
278 return member_map.values()
279
280 @property
281 @memoize
282 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700283 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700284 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 -0700285
286 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700287 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700288 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700289 return len(self.all_versions) == len(model.versions)
290
291 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700292 @memoize
293 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700294 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700295 return self.version_map.keys()
296
Andreas Wundsam5204de22013-07-30 11:34:45 -0700297 def has_version(self, version):
298 return version in self.version_map
299
Andreas Wundsam27303462013-07-16 12:52:35 -0700300 def versioned_class(self, version):
301 return JavaOFClass(self, version, self.version_map[version])
302
303 @property
304 @memoize
305 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700306 return [ self.versioned_class(version) for version in self.all_versions ]
307
308#######################################################################
309### (Versioned) Classes
310#######################################################################
311
312class JavaOFClass(object):
313 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700314 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700315 """
316 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700317 """
318 @param interface JavaOFInterface instance of the parent interface
319 @param version JavaOFVersion
320 @param ir_class OFClass from loxi_ir
321 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700322 self.interface = interface
323 self.ir_class = ir_class
324 self.c_name = self.ir_class.name
325 self.version = version
326 self.constant_name = self.c_name.upper().replace("OF_", "")
327 self.package = "org.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700328 self.generated = False
329
330 @property
331 @memoize
332 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700333 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700334
335 @property
336 def name(self):
337 return "%sVer%s" % (self.interface.name, self.version.of_version)
338
339 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700340 def variable_name(self):
341 return self.name[3:]
342
343 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700344 def length(self):
345 if self.is_fixed_length:
346 return self.min_length
347 else:
348 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
349
350 @property
351 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700352 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700353 id_tuple = (self.ir_class.name, self.version.int_version)
354 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
355
356 @property
357 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700358 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700359 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
360
361 def all_properties(self):
362 return self.interface.members
363
364 def get_member(self, name):
365 for m in self.members:
366 if m.name == name:
367 return m
368
369 @property
370 @memoize
371 def data_members(self):
372 return [ prop for prop in self.members if prop.is_data ]
373
374 @property
375 @memoize
376 def fixed_value_members(self):
377 return [ prop for prop in self.members if prop.is_fixed_value ]
378
379 @property
380 @memoize
381 def public_members(self):
382 return [ prop for prop in self.members if prop.is_public ]
383
384 @property
385 @memoize
386 def members(self):
387 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
388 return members
389
390 def all_versions(self):
391 return [ JavaOFVersion(int_version)
392 for int_version in of_g.unified[self.c_name]
393 if int_version != 'union' and int_version != 'object_id' ]
394
395 def version_is_inherited(self, version):
396 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
397
398 def inherited_from(self, version):
399 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
400
401 @property
402 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700403 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
404
405 @property
406 def discriminator(self):
407 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700408
409 @property
410 def is_extension(self):
411 return type_maps.message_is_extension(self.c_name, -1)
412
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700413 @property
414 def align(self):
415 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
416
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700417 @property
418 @memoize
419 def superclass(self):
420 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
421
422 @property
423 @memoize
424 def subclasses(self):
425 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
426
Andreas Wundsam27303462013-07-16 12:52:35 -0700427#######################################################################
428### Member
429#######################################################################
430
431
432class JavaMember(object):
433 """ Models a property (member) of an openflow class. """
434 def __init__(self, msg, name, java_type, member):
435 self.msg = msg
436 self.name = name
437 self.java_type = java_type
438 self.member = member
439 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700440
441 @property
442 def title_name(self):
443 return self.name[0].upper() + self.name[1:]
444
445 @property
446 def constant_name(self):
447 return self.c_name.upper()
448
449 @property
450 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700451 if self.is_fixed_value:
452 return self.constant_name
453 else:
454 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700455
456 @property
457 def default_value(self):
458 java_type = self.java_type.public_type;
459
Andreas Wundsam27303462013-07-16 12:52:35 -0700460 if self.is_fixed_value:
461 return self.enum_value
462 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700463 return "Collections.emptyList()"
464 elif java_type == "boolean":
465 return "false";
466 elif java_type in ("byte", "char", "short", "int", "long"):
467 return "({0}) 0".format(java_type);
468 else:
469 return "null";
470
471 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700472 def enum_value(self):
473 if self.name == "version":
474 return "OFVersion.%s" % self.msg.version.constant_version
475
476 java_type = self.java_type.public_type;
477 try:
478 global model
479 enum = model.enum_by_name(java_type)
480 entry = enum.entry_by_version_value(self.msg.version, self.value)
481 return "%s.%s" % ( enum.name, entry.name)
482 except KeyError, e:
483 print e.message
484 return self.value
485
486 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700487 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700488 return isinstance(self.member, OFPadMember)
489
490 def is_type_value(self, version=None):
491 if(version==None):
492 return any(self.is_type_value(version) for version in self.msg.all_versions)
493 try:
494 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
495 except:
496 return False
497
498 @property
499 def is_field_length_value(self):
500 return isinstance(self.member, OFFieldLengthMember)
501
502 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700503 def is_discriminator(self):
504 return isinstance(self.member, OFDiscriminatorMember)
505
506 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700507 def is_length_value(self):
508 return isinstance(self.member, OFLengthMember)
509
510 @property
511 def is_public(self):
512 return not (self.is_pad or self.is_length_value)
513
514 @property
515 def is_data(self):
516 return isinstance(self.member, OFDataMember) and self.name != "version"
517
518 @property
519 def is_fixed_value(self):
520 return hasattr(self.member, "value") or self.name == "version" \
521 or ( self.name == "length" and self.msg.is_fixed_length) \
522 or ( self.name == "len" and self.msg.is_fixed_length)
523
524 @property
525 def value(self):
526 if self.name == "version":
527 return self.msg.version.int_version
528 elif self.name == "length" or self.name == "len":
529 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700530 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700531 return self.java_type.format_value(self.member.value)
532
533 @property
534 def priv_value(self):
535 if self.name == "version":
536 return self.msg.version.int_version
537 elif self.name == "length" or self.name == "len":
538 return self.msg.length
539 else:
540 return self.java_type.format_value(self.member.value, pub_type=False)
541
Andreas Wundsam27303462013-07-16 12:52:35 -0700542
543 @property
544 def is_writeable(self):
545 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
546
547 def get_type_value_info(self, version):
548 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700549
550 @property
551 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700552 if hasattr(self.member, "length"):
553 return self.member.length
554 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700555 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700556 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700557
558 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700559 def for_of_member(java_class, member):
560 if isinstance(member, OFPadMember):
561 return JavaMember(None, "", None, member)
562 else:
563 if member.name == 'len':
564 name = 'length'
565 else:
566 name = java_type.name_c_to_camel(member.name)
567 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
568 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700569
570 @property
571 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700572 if not self.msg.c_name in of_g.unified:
573 print("%s not self.unified" % self.msg.c_name)
574 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700575 for version in of_g.unified[self.msg.c_name]:
576 if version == 'union' or version =='object_id':
577 continue
578 if 'use_version' in of_g.unified[self.msg.c_name][version]:
579 continue
580
Andreas Wundsam27303462013-07-16 12:52:35 -0700581 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 -0700582 return False
583 return True
584
Andreas Wundsam27303462013-07-16 12:52:35 -0700585 def __hash__(self):
586 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700587
Andreas Wundsam27303462013-07-16 12:52:35 -0700588 def __eq__(self, other):
589 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700590 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700591 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700592
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700593
594#######################################################################
595### Unit Test
596#######################################################################
597
Yotam Harchol466b3212013-08-15 12:14:46 -0700598class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700599 def __init__(self, java_class):
600 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700601 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700602 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700603 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
604 name=java_class.c_name[3:]) + "{i}.data"
605 test_class_name = self.java_class.name + "Test"
606 self.test_units = []
607 if test_data.exists(first_data_file_name):
608 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
609 i = 1
610 while test_data.exists(data_file_template.format(i=i)):
611 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
612 i = i + 1
613
614 @property
615 def package(self):
616 return self.java_class.package
617
618 @property
619 def has_test_data(self):
620 return len(self.test_units) > 0
621
622 @property
623 def length(self):
624 return len(self.test_units)
625
626 def get_test_unit(self, i):
627 return self.test_units[i]
628
629
630class JavaUnitTest(object):
631 def __init__(self, java_class, file_name=None, test_class_name=None):
632 self.java_class = java_class
633 if file_name is None:
634 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
635 name=java_class.c_name[3:])
636 else:
637 self.data_file_name = file_name
638 if test_class_name is None:
639 self.test_class_name = self.java_class.name + "Test"
640 else:
641 self.test_class_name = test_class_name
642
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700643 @property
644 def package(self):
645 return self.java_class.package
646
647 @property
648 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700649 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700650
651 @property
652 def has_test_data(self):
653 return test_data.exists(self.data_file_name)
654
655 @property
656 @memoize
657 def test_data(self):
658 return test_data.read(self.data_file_name)
659
660
Andreas Wundsam27303462013-07-16 12:52:35 -0700661#######################################################################
662### Enums
663#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700664
Andreas Wundsam27303462013-07-16 12:52:35 -0700665class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700666 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700667 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700668
669 if c_name == "of_stats_types":
670 self.name = "OFStatsType"
671 else:
672 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700673
Andreas Wundsam27303462013-07-16 12:52:35 -0700674 # Port_features has constants that start with digits
675 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700676
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700677 self.version_enums = version_enum_map
678
679 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
680 for version, ir_enum in version_enum_map.items():
681 for ir_entry in ir_enum.entries:
682 if "virtual" in ir_entry.params:
683 continue
684 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
685
Andreas Wundsam27303462013-07-16 12:52:35 -0700686 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700687 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700688
689 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700690 self.package = "org.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700691
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700692 def wire_type(self, version):
693 ir_enum = self.version_enums[version]
694 if "wire_type" in ir_enum.params:
695 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
696 else:
697 return java_type.u8
698
699 @property
700 def versions(self):
701 return self.version_enums.keys()
702
Andreas Wundsam27303462013-07-16 12:52:35 -0700703 @memoize
704 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700705 res = find(lambda e: e.name == name, self.entries)
706 if res:
707 return res
708 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700709 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
710
711 @memoize
712 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700713 res = find(lambda e: e.c_name == name, self.entries)
714 if res:
715 return res
716 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700717 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
718
719 @memoize
720 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700721 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
722 if res:
723 return res
724 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700725 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
726
727# values: Map JavaVersion->Value
728class JavaEnumEntry(object):
729 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700730 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700731 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
732 self.values = values
733
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700734 def has_value(self, version):
735 return version in self.values
736
Andreas Wundsam27303462013-07-16 12:52:35 -0700737 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700738 return self.values[version]
739
740 def format_value(self, version):
741 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -0700742 return res
743
Andreas Wundsam27303462013-07-16 12:52:35 -0700744 def all_values(self, versions, not_present=None):
745 return [ self.values[version] if version in self.values else not_present for version in versions ]