blob: 9e5731bbfc032bffd0bf75f2ed4356dbef47db02 [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 Wundsam001b1822013-08-02 22:25:55 -070051 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
52 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070053
54 @property
55 @memoize
56 def versions(self):
57 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
58
59 @property
60 @memoize
61 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -070062 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -070063
64 for raw_version, of_protocol in of_g.ir.items():
65 jversion = JavaOFVersion(of_protocol.wire_version)
66
67 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -070068 if not of_class.name in version_map_per_class:
69 version_map_per_class[of_class.name] = collections.OrderedDict()
70
Andreas Wundsam27303462013-07-16 12:52:35 -070071 version_map_per_class[of_class.name][jversion] = of_class
72
73 interfaces = []
74 for class_name, version_map in version_map_per_class.items():
75 interfaces.append(JavaOFInterface(class_name, version_map))
76
77 return interfaces
78
79 @property
80 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -070081 def all_classes(self):
82 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
83
84 @property
85 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -070086 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070087 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -070088
89 for version in self.versions:
90 of_protocol = of_g.ir[version.int_version]
91 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070092 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -070093
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070094 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
95 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -070096
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070097 # inelegant - need java name here
98 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -070099 return enums
100
101 @memoize
102 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700103 res = find(lambda e: e.name == name, self.enums)
104 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700105 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700106 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700107
Andreas Wundsam5204de22013-07-30 11:34:45 -0700108 @property
109 @memoize
110 def of_factory(self):
111 return OFFactory(
112 package="org.openflow.protocol",
113 name="OFFactory",
114 members=self.interfaces)
115
116 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700117 """ return wether or not to generate implementation class clazz.
118 Now true for everything except OFTableModVer10.
119 @param clazz JavaOFClass instance
120 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700121 if clazz.interface.name.startswith("OFMatchV"):
122 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700123 elif clazz.name == "OFTableModVer10":
124 # tablemod ver 10 is a hack and has no oftype defined
125 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700126 if loxi_utils.class_is_message(clazz.interface.c_name):
127 return True
128 if loxi_utils.class_is_oxm(clazz.interface.c_name):
129 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700130 if loxi_utils.class_is_action(clazz.interface.c_name):
131 return True
132 if loxi_utils.class_is_instruction(clazz.interface.c_name):
133 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700134 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700135 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700136
137
138class OFFactory(namedtuple("OFFactory", ("package", "name", "members"))):
139 @property
140 def factory_classes(self):
141 return [ OFFactoryClass(
142 package="org.openflow.protocol.ver{}".format(version.of_version),
143 name="OFFactoryVer{}".format(version.of_version),
144 interface=self,
145 version=version
146 ) for version in model.versions ]
147
148
149OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
150OFFactoryClass = namedtuple("OFFactory", ("package", "name", "interface", "version"))
151
Andreas Wundsam27303462013-07-16 12:52:35 -0700152model = JavaModel()
153
154#######################################################################
155### OFVersion
156#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700157
158class JavaOFVersion(object):
159 """ Models a version of OpenFlow. contains methods to convert the internal
160 Loxi version to a java constant / a string """
161 def __init__(self, int_version):
162 self.int_version = int(int_version)
163
164 @property
165 def of_version(self):
166 return "1" + str(int(self.int_version) - 1)
167
168 @property
169 def constant_version(self):
170 return "OF_" + self.of_version
171
Andreas Wundsam27303462013-07-16 12:52:35 -0700172 def __repr__(self):
173 return "JavaOFVersion(%d)" % self.int_version
174
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700175 def __str__(self):
176 return of_g.param_version_names[self.int_version]
177
Andreas Wundsam27303462013-07-16 12:52:35 -0700178 def __hash__(self):
179 return hash(self.int_version)
180
181 def __eq__(self, other):
182 if other is None or type(self) != type(other):
183 return False
184 return (self.int_version,) == (other.int_version,)
185
186#######################################################################
187### Interface
188#######################################################################
189
190class JavaOFInterface(object):
191 """ Models an OpenFlow Message class for the purpose of the java class.
192 Version agnostic, in contrast to the loxi_ir python model.
193 """
194 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700195 """"
196 @param c_name: loxi style name (e.g., of_flow_add)
197 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
198 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700199 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700200 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700201 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700202 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 -0700203 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700204 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700205 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700206 self.constant_name = c_name.upper().replace("OF_", "")
207
208 pck_suffix, parent_interface = self.class_info()
209 self.package = "org.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.openflow.protocol"
210 if self.name != parent_interface:
211 self.parent_interface = parent_interface
212 else:
213 self.parent_interface = None
214
215 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700216 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
217 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
218 # model (note, that the loxi model is on versioned classes). Should check/infer the
219 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700220 if re.match(r'OF.+StatsRequest$', self.name):
221 return ("", "OFStatsRequest")
222 elif re.match(r'OF.+StatsReply$', self.name):
223 return ("", "OFStatsReply")
224 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700225 return ("", "OFFlowMod")
Andreas Wundsam001b1822013-08-02 22:25:55 -0700226 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
227 return ("", "OFBsnHeader")
228 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
229 return ("", "OFNiciraHeader")
Andreas Wundsam43526532013-08-01 22:03:50 -0700230 elif re.match(r'OFMatch.*', self.name):
231 return ("", "Match")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700232 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700233 return ("", "OFMessage")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700234 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam001b1822013-08-02 22:25:55 -0700235 if re.match(r'OFActionBsn.*', self.name):
236 return ("action", "OFActionBsn")
237 elif re.match(r'OFActionNicira.*', self.name):
238 return ("action", "OFActionNicira")
239 else:
240 return ("action", "OFAction")
241 elif re.match(r'OFBsnVport.+$', self.name):
242 return ("", "OFBsnVport")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700243 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700244 return ("oxm", "OFOxm")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700245 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700246 return ("instruction", "OFInstruction")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700247 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700248 return ("meterband", "OFMeterBand")
Andreas Wundsam001b1822013-08-02 22:25:55 -0700249 elif loxi_utils.class_is_queue_prop(self.c_name):
250 return ("queueprop", "OFQueueProp")
251 elif loxi_utils.class_is_hello_elem(self.c_name):
252 return ("", "OFHelloElem")
Andreas Wundsam27303462013-07-16 12:52:35 -0700253 else:
254 return ("", None)
255
256 @property
257 @memoize
258 def members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700259 """return a list of all members to be exposed by this interface. Corresponds to
260 the union of the members of the vesioned classes without length, fieldlength
261 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700262 all_versions = []
263 member_map = collections.OrderedDict()
264
265 for (version, of_class) in self.version_map.items():
266 for of_member in of_class.members:
267 if isinstance(of_member, OFLengthMember) or \
268 isinstance(of_member, OFFieldLengthMember) or \
269 isinstance(of_member, OFPadMember):
270 continue
271 if of_member.name not in member_map:
272 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
273
274 return member_map.values()
275
276 @property
277 @memoize
278 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700279 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700280 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 -0700281
282 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700283 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700284 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700285 return len(self.all_versions) == len(model.versions)
286
287 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700288 @memoize
289 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700290 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700291 return self.version_map.keys()
292
Andreas Wundsam5204de22013-07-30 11:34:45 -0700293 def has_version(self, version):
294 return version in self.version_map
295
Andreas Wundsam27303462013-07-16 12:52:35 -0700296 def versioned_class(self, version):
297 return JavaOFClass(self, version, self.version_map[version])
298
299 @property
300 @memoize
301 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700302 return [ self.versioned_class(version) for version in self.all_versions ]
303
304#######################################################################
305### (Versioned) Classes
306#######################################################################
307
308class JavaOFClass(object):
309 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700310 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700311 """
312 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700313 """
314 @param interface JavaOFInterface instance of the parent interface
315 @param version JavaOFVersion
316 @param ir_class OFClass from loxi_ir
317 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700318 self.interface = interface
319 self.ir_class = ir_class
320 self.c_name = self.ir_class.name
321 self.version = version
322 self.constant_name = self.c_name.upper().replace("OF_", "")
323 self.package = "org.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700324 self.generated = False
325
326 @property
327 @memoize
328 def unit_test(self):
329 return JavaUnitTest(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700330
331 @property
332 def name(self):
333 return "%sVer%s" % (self.interface.name, self.version.of_version)
334
335 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700336 def variable_name(self):
337 return self.name[3:]
338
339 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700340 def length(self):
341 if self.is_fixed_length:
342 return self.min_length
343 else:
344 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
345
346 @property
347 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700348 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700349 id_tuple = (self.ir_class.name, self.version.int_version)
350 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
351
352 @property
353 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700354 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsam27303462013-07-16 12:52:35 -0700355 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
356
357 def all_properties(self):
358 return self.interface.members
359
360 def get_member(self, name):
361 for m in self.members:
362 if m.name == name:
363 return m
364
365 @property
366 @memoize
367 def data_members(self):
368 return [ prop for prop in self.members if prop.is_data ]
369
370 @property
371 @memoize
372 def fixed_value_members(self):
373 return [ prop for prop in self.members if prop.is_fixed_value ]
374
375 @property
376 @memoize
377 def public_members(self):
378 return [ prop for prop in self.members if prop.is_public ]
379
380 @property
381 @memoize
382 def members(self):
383 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
384 return members
385
386 def all_versions(self):
387 return [ JavaOFVersion(int_version)
388 for int_version in of_g.unified[self.c_name]
389 if int_version != 'union' and int_version != 'object_id' ]
390
391 def version_is_inherited(self, version):
392 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
393
394 def inherited_from(self, version):
395 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
396
397 @property
398 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700399 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
400
401 @property
402 def discriminator(self):
403 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700404
405 @property
406 def is_extension(self):
407 return type_maps.message_is_extension(self.c_name, -1)
408
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700409 @property
410 def align(self):
411 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
412
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700413 @property
414 @memoize
415 def superclass(self):
416 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
417
418 @property
419 @memoize
420 def subclasses(self):
421 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
422
Andreas Wundsam27303462013-07-16 12:52:35 -0700423#######################################################################
424### Member
425#######################################################################
426
427
428class JavaMember(object):
429 """ Models a property (member) of an openflow class. """
430 def __init__(self, msg, name, java_type, member):
431 self.msg = msg
432 self.name = name
433 self.java_type = java_type
434 self.member = member
435 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700436
437 @property
438 def title_name(self):
439 return self.name[0].upper() + self.name[1:]
440
441 @property
442 def constant_name(self):
443 return self.c_name.upper()
444
445 @property
446 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700447 if self.is_fixed_value:
448 return self.constant_name
449 else:
450 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700451
452 @property
453 def default_value(self):
454 java_type = self.java_type.public_type;
455
Andreas Wundsam27303462013-07-16 12:52:35 -0700456 if self.is_fixed_value:
457 return self.enum_value
458 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700459 return "Collections.emptyList()"
460 elif java_type == "boolean":
461 return "false";
462 elif java_type in ("byte", "char", "short", "int", "long"):
463 return "({0}) 0".format(java_type);
464 else:
465 return "null";
466
467 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700468 def enum_value(self):
469 if self.name == "version":
470 return "OFVersion.%s" % self.msg.version.constant_version
471
472 java_type = self.java_type.public_type;
473 try:
474 global model
475 enum = model.enum_by_name(java_type)
476 entry = enum.entry_by_version_value(self.msg.version, self.value)
477 return "%s.%s" % ( enum.name, entry.name)
478 except KeyError, e:
479 print e.message
480 return self.value
481
482 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700483 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700484 return isinstance(self.member, OFPadMember)
485
486 def is_type_value(self, version=None):
487 if(version==None):
488 return any(self.is_type_value(version) for version in self.msg.all_versions)
489 try:
490 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
491 except:
492 return False
493
494 @property
495 def is_field_length_value(self):
496 return isinstance(self.member, OFFieldLengthMember)
497
498 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700499 def is_discriminator(self):
500 return isinstance(self.member, OFDiscriminatorMember)
501
502 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700503 def is_length_value(self):
504 return isinstance(self.member, OFLengthMember)
505
506 @property
507 def is_public(self):
508 return not (self.is_pad or self.is_length_value)
509
510 @property
511 def is_data(self):
512 return isinstance(self.member, OFDataMember) and self.name != "version"
513
514 @property
515 def is_fixed_value(self):
516 return hasattr(self.member, "value") or self.name == "version" \
517 or ( self.name == "length" and self.msg.is_fixed_length) \
518 or ( self.name == "len" and self.msg.is_fixed_length)
519
520 @property
521 def value(self):
522 if self.name == "version":
523 return self.msg.version.int_version
524 elif self.name == "length" or self.name == "len":
525 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700526 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700527 return self.java_type.format_value(self.member.value)
528
529 @property
530 def priv_value(self):
531 if self.name == "version":
532 return self.msg.version.int_version
533 elif self.name == "length" or self.name == "len":
534 return self.msg.length
535 else:
536 return self.java_type.format_value(self.member.value, pub_type=False)
537
Andreas Wundsam27303462013-07-16 12:52:35 -0700538
539 @property
540 def is_writeable(self):
541 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
542
543 def get_type_value_info(self, version):
544 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700545
546 @property
547 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700548 if hasattr(self.member, "length"):
549 return self.member.length
550 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700551 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700552 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700553
554 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700555 def for_of_member(java_class, member):
556 if isinstance(member, OFPadMember):
557 return JavaMember(None, "", None, member)
558 else:
559 if member.name == 'len':
560 name = 'length'
561 else:
562 name = java_type.name_c_to_camel(member.name)
563 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
564 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700565
566 @property
567 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700568 if not self.msg.c_name in of_g.unified:
569 print("%s not self.unified" % self.msg.c_name)
570 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700571 for version in of_g.unified[self.msg.c_name]:
572 if version == 'union' or version =='object_id':
573 continue
574 if 'use_version' in of_g.unified[self.msg.c_name][version]:
575 continue
576
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 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 -0700578 return False
579 return True
580
Andreas Wundsam27303462013-07-16 12:52:35 -0700581 def __hash__(self):
582 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700583
Andreas Wundsam27303462013-07-16 12:52:35 -0700584 def __eq__(self, other):
585 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700586 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700587 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700588
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700589
590#######################################################################
591### Unit Test
592#######################################################################
593
594class JavaUnitTest(object):
595 def __init__(self, java_class):
596 self.java_class = java_class
597 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
598 name=java_class.c_name[3:])
599 @property
600 def package(self):
601 return self.java_class.package
602
603 @property
604 def name(self):
605 return self.java_class.name + "Test"
606
607 @property
608 def has_test_data(self):
609 return test_data.exists(self.data_file_name)
610
611 @property
612 @memoize
613 def test_data(self):
614 return test_data.read(self.data_file_name)
615
616
Andreas Wundsam27303462013-07-16 12:52:35 -0700617#######################################################################
618### Enums
619#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700620
Andreas Wundsam27303462013-07-16 12:52:35 -0700621class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700622 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700623 self.c_name = c_name
624 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700625
Andreas Wundsam27303462013-07-16 12:52:35 -0700626 # Port_features has constants that start with digits
627 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700628
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700629 self.version_enums = version_enum_map
630
631 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
632 for version, ir_enum in version_enum_map.items():
633 for ir_entry in ir_enum.entries:
634 if "virtual" in ir_entry.params:
635 continue
636 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
637
Andreas Wundsam27303462013-07-16 12:52:35 -0700638 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700639 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700640
641 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 -0700642 self.package = "org.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700643
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700644 def wire_type(self, version):
645 ir_enum = self.version_enums[version]
646 if "wire_type" in ir_enum.params:
647 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
648 else:
649 return java_type.u8
650
651 @property
652 def versions(self):
653 return self.version_enums.keys()
654
Andreas Wundsam27303462013-07-16 12:52:35 -0700655 @memoize
656 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700657 res = find(lambda e: e.name == name, self.entries)
658 if res:
659 return res
660 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700661 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
662
663 @memoize
664 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700665 res = find(lambda e: e.c_name == name, self.entries)
666 if res:
667 return res
668 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700669 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
670
671 @memoize
672 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700673 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
674 if res:
675 return res
676 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700677 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
678
679# values: Map JavaVersion->Value
680class JavaEnumEntry(object):
681 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700682 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700683 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
684 self.values = values
685
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700686 def has_value(self, version):
687 return version in self.values
688
Andreas Wundsam27303462013-07-16 12:52:35 -0700689 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700690 return self.values[version]
691
692 def format_value(self, version):
693 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -0700694 return res
695
Andreas Wundsam27303462013-07-16 12:52:35 -0700696 def all_values(self, versions, not_present=None):
697 return [ self.values[version] if version in self.values else not_present for version in versions ]