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
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 35503e5..c98df81 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -5,6 +5,13 @@
 import subprocess
 import time
 
+def erase_type_annotation(class_name):
+    m=re.match(r'(.*)<.*>', class_name)
+    if m:
+        return m.group(1)
+    else:
+        return class_name
+
 def name_c_to_camel(name):
     """ 'of_stats_reply' -> 'ofStatsReply' """
     name = re.sub(r'^_','', name)
@@ -288,11 +295,20 @@
         .op(read="IPv6FlowLabel.read4Bytes(bb)", write="$name.write4Bytes(bb)")
 metadata = JType("OFMetadata")\
         .op(read="OFMetadata.read8Bytes(bb)", write="$name.write8Bytes(bb)")
-oxm = JType("OFOxm")\
-        .op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+oxm = JType("OFOxm<?>")\
+        .op(  read="OFOxmVer$version.READER.readFrom(bb)",
+              write="$name.writeTo(bb)")
+oxm_list = JType("OFOxmList") \
+        .op(
+            read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
+            write='$name.writeTo(bb)')
 meter_features = JType("OFMeterFeatures")\
         .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
 
+boolean = JType("boolean")
+
+generic_t = JType("T")
+
 
 default_mtype_to_jtype_convert_map = {
         'uint8_t' : u8,
@@ -307,6 +323,7 @@
         'list(of_packet_queue_t)' : packet_queue_list,
         'list(of_uint32_t)' : u32_list,
         'list(of_uint8_t)' : u8_list,
+        'list(of_oxm_t)' : oxm_list,
         'of_octets_t' : octets,
         'of_match_t': of_match,
         'of_fm_cmd_t': flow_mod_cmd,
@@ -376,6 +393,9 @@
         'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
 }
 
+def make_match_field_jtype(sub_type_name="?"):
+    return JType("MatchField<{}>".format(sub_type_name))
+
 
 # Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
 def make_standard_list_jtype(c_type):
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java
new file mode 100644
index 0000000..d9ede81
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java
@@ -0,0 +1,128 @@
+package org.openflow.protocol;
+
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.match.MatchField;
+import org.openflow.protocol.match.MatchFields;
+import org.openflow.protocol.oxm.OFOxm;
+import org.openflow.types.OFValueType;
+import org.openflow.util.ChannelUtils;
+
+import com.google.common.collect.ImmutableMap;
+
+public class OFOxmList implements Iterable<OFOxm<?>>, Writeable {
+    private final Map<MatchFields, OFOxm<?>> oxmMap;
+
+    public final static OFOxmList EMPTY = new OFOxmList(ImmutableMap.<MatchFields, OFOxm<?>>of());
+
+    private OFOxmList(Map<MatchFields, OFOxm<?>> oxmMap) {
+        this.oxmMap = oxmMap;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends OFValueType<T>> OFOxm<T> get(MatchField<T> matchField) {
+        return (OFOxm<T>) oxmMap.get(matchField.id);
+    }
+
+    public static class Builder {
+        private final Map<MatchFields, OFOxm<?>> oxmMap;
+
+        public Builder() {
+            oxmMap = new EnumMap<MatchFields, OFOxm<?>>(MatchFields.class);
+        }
+
+        public Builder(EnumMap<MatchFields, OFOxm<?>> oxmMap) {
+            this.oxmMap = oxmMap;
+        }
+
+        public <T extends OFValueType<T>> void set(OFOxm<T> oxm) {
+            oxmMap.put(oxm.getMatchField().id, oxm);
+        }
+
+        public <T extends OFValueType<T>> void unset(MatchField<T> matchField) {
+            oxmMap.remove(matchField.id);
+        }
+
+        public OFOxmList build() {
+            return new OFOxmList(oxmMap);
+        }
+    }
+
+    @Override
+    public Iterator<OFOxm<?>> iterator() {
+        return oxmMap.values().iterator();
+    }
+
+    public static OFOxmList ofList(List<OFOxm<?>> oxmList) {
+        Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+                MatchFields.class);
+        for (OFOxm<?> o : oxmList) {
+            // TODO: if fully masked, ignore oxm.
+            map.put(o.getMatchField().id, o);
+        }
+        return new OFOxmList(map);
+    }
+
+    public static OFOxmList of(OFOxm<?>... oxms) {
+        Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+                MatchFields.class);
+        for (OFOxm<?> o : oxms) {
+            // TODO: if fully masked, ignore oxm.
+            map.put(o.getMatchField().id, o);
+        }
+        return new OFOxmList(map);
+    }
+
+    public static OFOxmList readFrom(ChannelBuffer bb, int length,
+            OFMessageReader<OFOxm<?>> reader) throws OFParseError {
+        return ofList(ChannelUtils.readList(bb, length, reader));
+    }
+
+    @Override
+    public void writeTo(ChannelBuffer bb) {
+        for (OFOxm<?> o : this) {
+            o.writeTo(bb);
+        }
+    }
+
+    public org.openflow.protocol.OFOxmList.Builder createBuilder() {
+        return new OFOxmList.Builder(new EnumMap<MatchFields, OFOxm<?>>(oxmMap));
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((oxmMap == null) ? 0 : oxmMap.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        OFOxmList other = (OFOxmList) obj;
+        if (oxmMap == null) {
+            if (other.oxmMap != null)
+                return false;
+        } else if (!oxmMap.equals(other.oxmMap))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "OFOxmList" + oxmMap;
+    }
+
+
+}
diff --git a/java_gen/templates/of_interface.java b/java_gen/templates/of_interface.java
index 4dec92f..8ddaba3 100644
--- a/java_gen/templates/of_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -26,6 +26,7 @@
 //:: # under the EPL.
 //::
 //:: import itertools
+//:: import re
 //:: import of_g
 //:: include('_copyright.java')
 
@@ -35,20 +36,21 @@
 
 //:: include("_imports.java", msg=msg)
 
-public interface ${msg.name} extends OFObject${", %s" % msg.parent_interface if msg.parent_interface else ""}{
+public interface ${msg.name}${ "<%s>" % msg.type_annotation if msg.type_annotation else ""} extends OFObject${", %s" % msg.parent_interface if msg.parent_interface else ""}{
 //:: for prop in msg.members:
-    ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
+    ${prop.java_type.public_type} ${prop.getter_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endfor
 
     void writeTo(ChannelBuffer channelBuffer);
 
-    Builder createBuilder();
-    public interface Builder ${"extends %s.Builder" % msg.parent_interface if msg.parent_interface else ""} {
-        ${msg.name} getMessage();
+    Builder${msg.type_variable} createBuilder();
+    //:: simple_type, annotation = re.match(r'(\w+)(<.*>)?', msg.parent_interface).groups() if msg.parent_interface else ("", "")
+    public interface Builder${ "<%s>" % msg.type_annotation if msg.type_annotation else ""} ${"extends %s.Builder" % simple_type if msg.parent_interface else ""}${annotation if annotation else ""} {
+        ${msg.name}${msg.type_variable} build();
 //:: for prop in msg.members:
-        ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
+        ${prop.java_type.public_type} ${prop.getter_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: if prop.is_writeable:
-        Builder set${prop.title_name}(${prop.java_type.public_type} ${prop.name})${ "" if prop.is_universal else " throws UnsupportedOperationException"};
+        Builder ${prop.setter_name}(${prop.java_type.public_type} ${prop.name})${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endif
 //:: #endfor
     }
diff --git a/java_gen/templates/of_virtual_class.java b/java_gen/templates/of_virtual_class.java
index f1ac849..fe5c66c 100644
--- a/java_gen/templates/of_virtual_class.java
+++ b/java_gen/templates/of_virtual_class.java
@@ -37,7 +37,7 @@
 
 //:: include("_imports.java", msg=msg)
 
-abstract class ${msg.name} implements ${msg.interface.name} {
+abstract class ${msg.name} {
     // version: ${version}
     private final static byte WIRE_VERSION = ${version.int_version};
 //:: if msg.is_fixed_length:
@@ -49,7 +49,7 @@
 
     public final static ${msg.name}.Reader READER = new Reader();
 
-    static class Reader implements OFMessageReader<${msg.interface.name}> {
+    static class Reader implements OFMessageReader<${msg.interface.inherited_declaration()}> {
         @Override
         public ${msg.interface.name} readFrom(ChannelBuffer bb) throws OFParseError {
             int start = bb.readerIndex();