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