blob: a118fdfff4497dde00a33c297e15f31b007bbccb [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" ]))
51 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)))
52 virtual_interfaces = set(['OFOxm', 'OFAction', 'OFInstruction' ])
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
81 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070082 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -070083
84 for version in self.versions:
85 of_protocol = of_g.ir[version.int_version]
86 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070087 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -070088
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070089 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
90 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -070091
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070092 # inelegant - need java name here
93 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -070094 return enums
95
96 @memoize
97 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -070098 res = find(lambda e: e.name == name, self.enums)
99 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700100 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700101 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700102
Andreas Wundsam5204de22013-07-30 11:34:45 -0700103 @property
104 @memoize
105 def of_factory(self):
106 return OFFactory(
107 package="org.openflow.protocol",
108 name="OFFactory",
109 members=self.interfaces)
110
111 def generate_class(self, clazz):
112 if clazz.interface.is_virtual:
113 return False
114 if clazz.interface.name == "OFTableMod":
115 return False
Andreas Wundsam43526532013-08-01 22:03:50 -0700116 if clazz.interface.name.startswith("OFMatchV"):
117 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700118 if loxi_utils.class_is_message(clazz.interface.c_name):
119 return True
120 if loxi_utils.class_is_oxm(clazz.interface.c_name):
121 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700122 if loxi_utils.class_is_action(clazz.interface.c_name):
123 return True
124 if loxi_utils.class_is_instruction(clazz.interface.c_name):
125 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700126 else:
127 return False
128
129
130class OFFactory(namedtuple("OFFactory", ("package", "name", "members"))):
131 @property
132 def factory_classes(self):
133 return [ OFFactoryClass(
134 package="org.openflow.protocol.ver{}".format(version.of_version),
135 name="OFFactoryVer{}".format(version.of_version),
136 interface=self,
137 version=version
138 ) for version in model.versions ]
139
140
141OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
142OFFactoryClass = namedtuple("OFFactory", ("package", "name", "interface", "version"))
143
Andreas Wundsam27303462013-07-16 12:52:35 -0700144model = JavaModel()
145
146#######################################################################
147### OFVersion
148#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700149
150class JavaOFVersion(object):
151 """ Models a version of OpenFlow. contains methods to convert the internal
152 Loxi version to a java constant / a string """
153 def __init__(self, int_version):
154 self.int_version = int(int_version)
155
156 @property
157 def of_version(self):
158 return "1" + str(int(self.int_version) - 1)
159
160 @property
161 def constant_version(self):
162 return "OF_" + self.of_version
163
Andreas Wundsam27303462013-07-16 12:52:35 -0700164 def __repr__(self):
165 return "JavaOFVersion(%d)" % self.int_version
166
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700167 def __str__(self):
168 return of_g.param_version_names[self.int_version]
169
Andreas Wundsam27303462013-07-16 12:52:35 -0700170 def __hash__(self):
171 return hash(self.int_version)
172
173 def __eq__(self, other):
174 if other is None or type(self) != type(other):
175 return False
176 return (self.int_version,) == (other.int_version,)
177
178#######################################################################
179### Interface
180#######################################################################
181
182class JavaOFInterface(object):
183 """ Models an OpenFlow Message class for the purpose of the java class.
184 Version agnostic, in contrast to the loxi_ir python model.
185 """
186 def __init__(self, c_name, version_map):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700187 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700188 self.version_map = version_map
189 self.name = java_type.name_c_to_caps_camel(c_name)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700190 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam27303462013-07-16 12:52:35 -0700191 self.constant_name = c_name.upper().replace("OF_", "")
192
193 pck_suffix, parent_interface = self.class_info()
194 self.package = "org.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.openflow.protocol"
195 if self.name != parent_interface:
196 self.parent_interface = parent_interface
197 else:
198 self.parent_interface = None
199
200 def class_info(self):
Yotam Harchol161a5d52013-07-25 17:17:48 -0700201 if re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700202 return ("", "OFFlowMod")
Andreas Wundsam43526532013-08-01 22:03:50 -0700203 elif re.match(r'OFMatch.*', self.name):
204 return ("", "Match")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700205 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700206 return ("", "OFMessage")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700207 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700208 return ("action", "OFAction")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700209 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700210 return ("oxm", "OFOxm")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700211 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700212 return ("instruction", "OFInstruction")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700213 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam27303462013-07-16 12:52:35 -0700214 return ("meterband", "OFMeterBand")
215 else:
216 return ("", None)
217
218 @property
219 @memoize
220 def members(self):
221 all_versions = []
222 member_map = collections.OrderedDict()
223
224 for (version, of_class) in self.version_map.items():
225 for of_member in of_class.members:
226 if isinstance(of_member, OFLengthMember) or \
227 isinstance(of_member, OFFieldLengthMember) or \
228 isinstance(of_member, OFPadMember):
229 continue
230 if of_member.name not in member_map:
231 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
232
233 return member_map.values()
234
235 @property
236 @memoize
237 def is_virtual(self):
238 return self.name in model.virtual_interfaces
239
240 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700241 def is_universal(self):
242 return len(self.all_versions) == len(model.versions)
243
244 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700245 @memoize
246 def all_versions(self):
247 return self.version_map.keys()
248
Andreas Wundsam5204de22013-07-30 11:34:45 -0700249 def has_version(self, version):
250 return version in self.version_map
251
Andreas Wundsam27303462013-07-16 12:52:35 -0700252 def versioned_class(self, version):
253 return JavaOFClass(self, version, self.version_map[version])
254
255 @property
256 @memoize
257 def versioned_classes(self):
258 if self.is_virtual:
259 return []
260 else:
261 return [ self.versioned_class(version) for version in self.all_versions ]
262
263#######################################################################
264### (Versioned) Classes
265#######################################################################
266
267class JavaOFClass(object):
268 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700269 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700270 """
271 def __init__(self, interface, version, ir_class):
272 self.interface = interface
273 self.ir_class = ir_class
274 self.c_name = self.ir_class.name
275 self.version = version
276 self.constant_name = self.c_name.upper().replace("OF_", "")
277 self.package = "org.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700278 self.generated = False
279
280 @property
281 @memoize
282 def unit_test(self):
283 return JavaUnitTest(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700284
285 @property
286 def name(self):
287 return "%sVer%s" % (self.interface.name, self.version.of_version)
288
289 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700290 def variable_name(self):
291 return self.name[3:]
292
293 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700294 def length(self):
295 if self.is_fixed_length:
296 return self.min_length
297 else:
298 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
299
300 @property
301 def min_length(self):
302 id_tuple = (self.ir_class.name, self.version.int_version)
303 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
304
305 @property
306 def is_fixed_length(self):
307 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
308
309 def all_properties(self):
310 return self.interface.members
311
312 def get_member(self, name):
313 for m in self.members:
314 if m.name == name:
315 return m
316
317 @property
318 @memoize
319 def data_members(self):
320 return [ prop for prop in self.members if prop.is_data ]
321
322 @property
323 @memoize
324 def fixed_value_members(self):
325 return [ prop for prop in self.members if prop.is_fixed_value ]
326
327 @property
328 @memoize
329 def public_members(self):
330 return [ prop for prop in self.members if prop.is_public ]
331
332 @property
333 @memoize
334 def members(self):
335 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
336 return members
337
338 def all_versions(self):
339 return [ JavaOFVersion(int_version)
340 for int_version in of_g.unified[self.c_name]
341 if int_version != 'union' and int_version != 'object_id' ]
342
343 def version_is_inherited(self, version):
344 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
345
346 def inherited_from(self, version):
347 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
348
349 @property
350 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700351 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
352
353 @property
354 def discriminator(self):
355 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700356
357 @property
358 def is_extension(self):
359 return type_maps.message_is_extension(self.c_name, -1)
360
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700361 @property
362 def align(self):
363 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
364
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700365 @property
366 @memoize
367 def superclass(self):
368 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
369
370 @property
371 @memoize
372 def subclasses(self):
373 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
374
Andreas Wundsam27303462013-07-16 12:52:35 -0700375#######################################################################
376### Member
377#######################################################################
378
379
380class JavaMember(object):
381 """ Models a property (member) of an openflow class. """
382 def __init__(self, msg, name, java_type, member):
383 self.msg = msg
384 self.name = name
385 self.java_type = java_type
386 self.member = member
387 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700388
389 @property
390 def title_name(self):
391 return self.name[0].upper() + self.name[1:]
392
393 @property
394 def constant_name(self):
395 return self.c_name.upper()
396
397 @property
398 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700399 if self.is_fixed_value:
400 return self.constant_name
401 else:
402 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700403
404 @property
405 def default_value(self):
406 java_type = self.java_type.public_type;
407
Andreas Wundsam27303462013-07-16 12:52:35 -0700408 if self.is_fixed_value:
409 return self.enum_value
410 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700411 return "Collections.emptyList()"
412 elif java_type == "boolean":
413 return "false";
414 elif java_type in ("byte", "char", "short", "int", "long"):
415 return "({0}) 0".format(java_type);
416 else:
417 return "null";
418
419 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700420 def enum_value(self):
421 if self.name == "version":
422 return "OFVersion.%s" % self.msg.version.constant_version
423
424 java_type = self.java_type.public_type;
425 try:
426 global model
427 enum = model.enum_by_name(java_type)
428 entry = enum.entry_by_version_value(self.msg.version, self.value)
429 return "%s.%s" % ( enum.name, entry.name)
430 except KeyError, e:
431 print e.message
432 return self.value
433
434 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700435 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700436 return isinstance(self.member, OFPadMember)
437
438 def is_type_value(self, version=None):
439 if(version==None):
440 return any(self.is_type_value(version) for version in self.msg.all_versions)
441 try:
442 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
443 except:
444 return False
445
446 @property
447 def is_field_length_value(self):
448 return isinstance(self.member, OFFieldLengthMember)
449
450 @property
451 def is_length_value(self):
452 return isinstance(self.member, OFLengthMember)
453
454 @property
455 def is_public(self):
456 return not (self.is_pad or self.is_length_value)
457
458 @property
459 def is_data(self):
460 return isinstance(self.member, OFDataMember) and self.name != "version"
461
462 @property
463 def is_fixed_value(self):
464 return hasattr(self.member, "value") or self.name == "version" \
465 or ( self.name == "length" and self.msg.is_fixed_length) \
466 or ( self.name == "len" and self.msg.is_fixed_length)
467
468 @property
469 def value(self):
470 if self.name == "version":
471 return self.msg.version.int_version
472 elif self.name == "length" or self.name == "len":
473 return self.msg.length
474 elif self.java_type.public_type in ("int", "short", "byte") and self.member.value > 100:
475 return "0x%x" % self.member.value
476 else:
477 return self.member.value
478
479 @property
480 def is_writeable(self):
481 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
482
483 def get_type_value_info(self, version):
484 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700485
486 @property
487 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700488 if hasattr(self.member, "length"):
489 return self.member.length
490 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700491 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700492 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700493
494 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700495 def for_of_member(java_class, member):
496 if isinstance(member, OFPadMember):
497 return JavaMember(None, "", None, member)
498 else:
499 if member.name == 'len':
500 name = 'length'
501 else:
502 name = java_type.name_c_to_camel(member.name)
503 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
504 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700505
506 @property
507 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700508 if not self.msg.c_name in of_g.unified:
509 print("%s not self.unified" % self.msg.c_name)
510 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700511 for version in of_g.unified[self.msg.c_name]:
512 if version == 'union' or version =='object_id':
513 continue
514 if 'use_version' in of_g.unified[self.msg.c_name][version]:
515 continue
516
Andreas Wundsam27303462013-07-16 12:52:35 -0700517 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 -0700518 return False
519 return True
520
Andreas Wundsam27303462013-07-16 12:52:35 -0700521 def __hash__(self):
522 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700523
Andreas Wundsam27303462013-07-16 12:52:35 -0700524 def __eq__(self, other):
525 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700526 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700527 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700528
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700529
530#######################################################################
531### Unit Test
532#######################################################################
533
534class JavaUnitTest(object):
535 def __init__(self, java_class):
536 self.java_class = java_class
537 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
538 name=java_class.c_name[3:])
539 @property
540 def package(self):
541 return self.java_class.package
542
543 @property
544 def name(self):
545 return self.java_class.name + "Test"
546
547 @property
548 def has_test_data(self):
549 return test_data.exists(self.data_file_name)
550
551 @property
552 @memoize
553 def test_data(self):
554 return test_data.read(self.data_file_name)
555
556
Andreas Wundsam27303462013-07-16 12:52:35 -0700557#######################################################################
558### Enums
559#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700560
Andreas Wundsam27303462013-07-16 12:52:35 -0700561class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700562 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700563 self.c_name = c_name
564 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700565
Andreas Wundsam27303462013-07-16 12:52:35 -0700566 # Port_features has constants that start with digits
567 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700568
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700569 self.version_enums = version_enum_map
570
571 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
572 for version, ir_enum in version_enum_map.items():
573 for ir_entry in ir_enum.entries:
574 if "virtual" in ir_entry.params:
575 continue
576 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
577
Andreas Wundsam27303462013-07-16 12:52:35 -0700578 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700579 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700580
581 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 -0700582 self.package = "org.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700583
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700584 def wire_type(self, version):
585 ir_enum = self.version_enums[version]
586 if "wire_type" in ir_enum.params:
587 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
588 else:
589 return java_type.u8
590
591 @property
592 def versions(self):
593 return self.version_enums.keys()
594
Andreas Wundsam27303462013-07-16 12:52:35 -0700595 @memoize
596 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700597 res = find(lambda e: e.name == name, self.entries)
598 if res:
599 return res
600 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
602
603 @memoize
604 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700605 res = find(lambda e: e.c_name == name, self.entries)
606 if res:
607 return res
608 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700609 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
610
611 @memoize
612 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700613 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
614 if res:
615 return res
616 else:
Andreas Wundsam27303462013-07-16 12:52:35 -0700617 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
618
619# values: Map JavaVersion->Value
620class JavaEnumEntry(object):
621 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700622 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700623 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
624 self.values = values
625
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700626 def has_value(self, version):
627 return version in self.values
628
Andreas Wundsam27303462013-07-16 12:52:35 -0700629 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700630 return self.values[version]
631
632 def format_value(self, version):
633 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -0700634 return res
635
Andreas Wundsam27303462013-07-16 12:52:35 -0700636 def all_values(self, versions, not_present=None):
637 return [ self.values[version] if version in self.values else not_present for version in versions ]