Richer model for OXMs
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 66eeacd..0fefadb 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -53,6 +53,9 @@
write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
+ OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
+ oxm_map = { "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True) }
+
@property
@memoize
def versions(self):
@@ -206,60 +209,106 @@
self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
# variable_name name to use for variables of this type. i.e., flowAdd
self.variable_name = self.name[2].lower() + self.name[3:]
+ self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
# name for use in constants: FLOW_ADD
self.constant_name = c_name.upper().replace("OF_", "")
- pck_suffix, parent_interface = self.class_info()
+ pck_suffix, parent_interface, self.type_annotation = self.class_info()
self.package = "org.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.openflow.protocol"
if self.name != parent_interface:
self.parent_interface = parent_interface
else:
self.parent_interface = None
-
+
+ def is_instance_of(self, other_class):
+ if self == other_class:
+ return True
+ parent = self.super_class
+ if parent is None:
+ return False
+ else:
+ return parent.is_instance_of(other_class)
+
+ @property
+ def super_class(self):
+ if not self.parent_interface:
+ return None
+ else:
+ return model.interface_by_name(self.parent_interface)
+
+
+ def inherited_declaration(self, type_spec="?"):
+ if self.type_annotation:
+ return "%s<%s>" % (self.name, type_spec)
+ else:
+ return "%s" % self.name
+
+ @property
+ def type_variable(self):
+ if self.type_annotation:
+ return "<T>"
+ else:
+ return "";
+
def class_info(self):
""" return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
# FIXME: This duplicates inheritance information that is now available in the loxi_ir
# model (note, that the loxi model is on versioned classes). Should check/infer the
# inheritance information from the versioned lox_ir classes.
if re.match(r'OF.+StatsRequest$', self.name):
- return ("", "OFStatsRequest")
+ return ("", "OFStatsRequest", None)
elif re.match(r'OF.+StatsReply$', self.name):
- return ("", "OFStatsReply")
+ return ("", "OFStatsReply", None)
elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
- return ("", "OFFlowMod")
+ return ("", "OFFlowMod", None)
elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
- return ("", "OFBsnHeader")
+ return ("", "OFBsnHeader", None)
elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
- return ("", "OFNiciraHeader")
+ return ("", "OFNiciraHeader", None)
elif re.match(r'OFMatch.*', self.name):
- return ("", "Match")
+ return ("", "Match", None)
elif loxi_utils.class_is_message(self.c_name):
- return ("", "OFMessage")
+ return ("", "OFMessage", None)
elif loxi_utils.class_is_action(self.c_name):
- if re.match(r'OFActionBsn.*', self.name):
- return ("action", "OFActionBsn")
- elif re.match(r'OFActionNicira.*', self.name):
- return ("action", "OFActionNicira")
+ if re.match(r'OFActionBsn.+', self.name):
+ return ("action", "OFActionBsn", None)
+ elif re.match(r'OFActionNicira.+', self.name):
+ return ("action", "OFActionNicira", None)
else:
- return ("action", "OFAction")
+ return ("action", "OFAction", None)
elif re.match(r'OFBsnVport.+$', self.name):
- return ("", "OFBsnVport")
+ return ("", "OFBsnVport", None)
+ elif self.name == "OFOxm":
+ return ("oxm", None, "T extends OFValueType<T>")
elif loxi_utils.class_is_oxm(self.c_name):
- return ("oxm", "OFOxm")
+ if self.name in model.oxm_map:
+ return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
+ else:
+ return ("oxm", "OFOxm", None)
elif loxi_utils.class_is_instruction(self.c_name):
- return ("instruction", "OFInstruction")
+ return ("instruction", "OFInstruction", None)
elif loxi_utils.class_is_meter_band(self.c_name):
- return ("meterband", "OFMeterBand")
+ return ("meterband", "OFMeterBand", None)
elif loxi_utils.class_is_queue_prop(self.c_name):
- return ("queueprop", "OFQueueProp")
+ return ("queueprop", "OFQueueProp", None)
elif loxi_utils.class_is_hello_elem(self.c_name):
- return ("", "OFHelloElem")
+ return ("", "OFHelloElem", None)
else:
- return ("", None)
+ return ("", None, None)
+
+ @property
+ @memoize
+ def writeable_members(self):
+ return [ m for m in self.members if m.is_writeable ]
@property
@memoize
def members(self):
+ return self.ir_model_members + self.virtual_members
+
+ @property
+ @memoize
+ def ir_model_members(self):
"""return a list of all members to be exposed by this interface. Corresponds to
the union of the members of the vesioned classes without length, fieldlength
and pads (those are handled automatically during (de)serialization and not exposed"""
@@ -275,7 +324,33 @@
if of_member.name not in member_map:
member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
- return member_map.values()
+ return tuple(member_map.values())
+
+ @property
+ def virtual_members(self):
+ if self.name == "OFOxm":
+ return (
+ JavaVirtualMember(self, "value", java_type.generic_t),
+ JavaVirtualMember(self, "mask", java_type.generic_t),
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
+ JavaVirtualMember(self, "masked", java_type.boolean),
+ )
+ elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
+ field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
+ if self.name in model.oxm_map \
+ else java_type.make_match_field_jtype()
+
+ return (
+ JavaVirtualMember(self, "matchField", field_type),
+ JavaVirtualMember(self, "masked", java_type.boolean),
+ ) \
+ + \
+ (
+ ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
+ ()
+ )
+ else:
+ return ()
@property
@memoize
@@ -384,8 +459,29 @@
@property
@memoize
def members(self):
+ return self.ir_model_members + self.virtual_members
+
+ @property
+ def ir_model_members(self):
members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
- return members
+ return tuple(members)
+
+ @property
+ def virtual_members(self):
+ if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
+ if self.interface.name in model.oxm_map:
+ oxm_entry = model.oxm_map[self.interface.name]
+ return (
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
+ JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
+ )
+ else:
+ return (
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
+ JavaVirtualMember(self, "masked", java_type.boolean, "false"),
+ )
+ else:
+ return ()
def all_versions(self):
return [ JavaOFVersion(int_version)
@@ -447,6 +543,14 @@
return self.c_name.upper()
@property
+ def getter_name(self):
+ return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
+
+ @property
+ def setter_name(self):
+ return "set" + self.title_name
+
+ @property
def default_name(self):
if self.is_fixed_value:
return self.constant_name
@@ -562,6 +666,8 @@
else:
if member.name == 'len':
name = 'length'
+ elif member.name == 'value_mask':
+ name = 'mask'
else:
name = java_type.name_c_to_camel(member.name)
j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
@@ -582,6 +688,10 @@
return False
return True
+ @property
+ def is_virtual(self):
+ return False
+
def __hash__(self):
return hash(self.name)
@@ -590,6 +700,32 @@
return False
return (self.name,) == (other.name,)
+class JavaVirtualMember(JavaMember):
+ """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
+ def __init__(self, msg, name, java_type, value=None):
+ JavaMember.__init__(self, msg, name, java_type, member=None)
+ self._value = value
+
+ @property
+ def is_fixed_value(self):
+ return True
+
+ @property
+ def value(self):
+ return self._value
+
+ @property
+ def priv_value(self):
+ return self._value
+
+
+ @property
+ def is_universal(self):
+ return True
+
+ @property
+ def is_virtual(self):
+ return True
#######################################################################
### Unit Test