Merge pull request #133 from andi-bigswitch/master

java_gen.OFMatchV3V13: auto-gen list of supported fields
diff --git a/Makefile b/Makefile
index 4712a04..7b241c3 100644
--- a/Makefile
+++ b/Makefile
@@ -72,7 +72,7 @@
 	mkdir -p ${OPENFLOWJ_WORKSPACE}
 	ln -sf ../java_gen/pre-written/pom.xml ${OPENFLOWJ_WORKSPACE}/pom.xml
 	ln -sf ../java_gen/pre-written/LICENSE.txt ${OPENFLOWJ_WORKSPACE}/LICENSE.txt
-	ln -sf ../java_gen/pre-written/src ${OPENFLOWJ_WORKSPACE}/src
+	ln -sf ../java_gen/pre-written/src ${OPENFLOWJ_WORKSPACE}
 	rsync --checksum --delete -rv ${LOXI_OUTPUT_DIR}/openflowj/src/ ${OPENFLOWJ_WORKSPACE}/gen-src
 
 .loxi_ts.java: ${LOXI_PY_FILES} ${LOXI_TEMPLATE_FILES} ${INPUT_FILES} ${TEST_DATA}
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 824a320..cfece7d 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -71,95 +71,6 @@
     # interfaces that are virtual
     virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
 
-    OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
-    oxm_map = { "OFOxmInPort":              OxmMapEntry("OFPort", "IN_PORT", False),
-                "OFOxmInPortMasked":        OxmMapEntry("OFPort", "IN_PORT", True),
-                "OFOxmInPhyPort":           OxmMapEntry("OFPort", "IN_PHY_PORT", False),
-                "OFOxmInPhyPortMasked":     OxmMapEntry("OFPort", "IN_PHY_PORT", True),
-                "OFOxmMetadata":            OxmMapEntry("OFMetadata", "METADATA", False),
-                "OFOxmMetadataMasked":      OxmMapEntry("OFMetadata", "METADATA", True),
-                "OFOxmEthDst":              OxmMapEntry("MacAddress", "ETH_DST", False),
-                "OFOxmEthDstMasked":        OxmMapEntry("MacAddress", "ETH_DST", True),
-                "OFOxmEthSrc":              OxmMapEntry("MacAddress", "ETH_SRC", False),
-                "OFOxmEthSrcMasked":        OxmMapEntry("MacAddress", "ETH_SRC", True),
-                "OFOxmEthType":             OxmMapEntry("EthType", "ETH_TYPE", False),
-                "OFOxmEthTypeMasked":       OxmMapEntry("EthType", "ETH_TYPE", True),
-                "OFOxmVlanVid":             OxmMapEntry("OFVlanVidMatch", "VLAN_VID", False),
-                "OFOxmVlanVidMasked":       OxmMapEntry("OFVlanVidMatch", "VLAN_VID", True),
-                "OFOxmVlanPcp":             OxmMapEntry("VlanPcp", "VLAN_PCP", False),
-                "OFOxmVlanPcpMasked":       OxmMapEntry("VlanPcp", "VLAN_PCP", True),
-                "OFOxmIpDscp":              OxmMapEntry("IpDscp", "IP_DSCP", False),
-                "OFOxmIpDscpMasked":        OxmMapEntry("IpDscp", "IP_DSCP", True),
-                "OFOxmIpEcn":               OxmMapEntry("IpEcn", "IP_ECN", False),
-                "OFOxmIpEcnMasked":         OxmMapEntry("IpEcn", "IP_ECN", True),
-                "OFOxmIpProto":             OxmMapEntry("IpProtocol", "IP_PROTO", False),
-                "OFOxmIpProtoMasked":       OxmMapEntry("IpProtocol", "IP_PROTO", True),
-                "OFOxmIpv4Src":             OxmMapEntry("IPv4Address", "IPV4_SRC", False),
-                "OFOxmIpv4SrcMasked":       OxmMapEntry("IPv4Address", "IPV4_SRC", True),
-                "OFOxmIpv4Dst":             OxmMapEntry("IPv4Address", "IPV4_DST", False),
-                "OFOxmIpv4DstMasked":       OxmMapEntry("IPv4Address", "IPV4_DST", True),
-                "OFOxmTcpSrc":              OxmMapEntry("TransportPort", "TCP_SRC", False),
-                "OFOxmTcpSrcMasked":        OxmMapEntry("TransportPort", "TCP_SRC", True),
-                "OFOxmTcpDst":              OxmMapEntry("TransportPort", "TCP_DST", False),
-                "OFOxmTcpDstMasked":        OxmMapEntry("TransportPort", "TCP_DST", True),
-                "OFOxmUdpSrc":              OxmMapEntry("TransportPort", "UDP_SRC", False),
-                "OFOxmUdpSrcMasked":        OxmMapEntry("TransportPort", "UDP_SRC", True),
-                "OFOxmUdpDst":              OxmMapEntry("TransportPort", "UDP_DST", False),
-                "OFOxmUdpDstMasked":        OxmMapEntry("TransportPort", "UDP_DST", True),
-                "OFOxmSctpSrc":             OxmMapEntry("TransportPort", "SCTP_SRC", False),
-                "OFOxmSctpSrcMasked":       OxmMapEntry("TransportPort", "SCTP_SRC", True),
-                "OFOxmSctpDst":             OxmMapEntry("TransportPort", "SCTP_DST", False),
-                "OFOxmSctpDstMasked":       OxmMapEntry("TransportPort", "SCTP_DST", True),
-                "OFOxmIcmpv4Type":          OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
-                "OFOxmIcmpv4TypeMasked":    OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
-                "OFOxmIcmpv4Code":          OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
-                "OFOxmIcmpv4CodeMasked":    OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
-                "OFOxmArpOp":               OxmMapEntry("ArpOpcode", "ARP_OP", False),
-                "OFOxmArpOpMasked":         OxmMapEntry("ArpOpcode", "ARP_OP", True),
-                "OFOxmArpSpa":              OxmMapEntry("IPv4Address", "ARP_SPA", False),
-                "OFOxmArpSpaMasked":        OxmMapEntry("IPv4Address", "ARP_SPA", True),
-                "OFOxmArpTpa":              OxmMapEntry("IPv4Address", "ARP_TPA", False),
-                "OFOxmArpTpaMasked":        OxmMapEntry("IPv4Address", "ARP_TPA", True),
-                "OFOxmArpSha":              OxmMapEntry("MacAddress", "ARP_SHA", False),
-                "OFOxmArpShaMasked":        OxmMapEntry("MacAddress", "ARP_SHA", True),
-                "OFOxmArpTha":              OxmMapEntry("MacAddress", "ARP_THA", False),
-                "OFOxmArpThaMasked":        OxmMapEntry("MacAddress", "ARP_THA", True),
-                "OFOxmIpv6Src":             OxmMapEntry("IPv6Address", "IPV6_SRC", False),
-                "OFOxmIpv6SrcMasked":       OxmMapEntry("IPv6Address", "IPV6_SRC", True),
-                "OFOxmIpv6Dst":             OxmMapEntry("IPv6Address", "IPV6_DST", False),
-                "OFOxmIpv6DstMasked":       OxmMapEntry("IPv6Address", "IPV6_DST", True),
-                "OFOxmIpv6Flabel":          OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
-                "OFOxmIpv6FlabelMasked":    OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
-                "OFOxmIcmpv6Type":          OxmMapEntry("U8", "ICMPV6_TYPE", False),
-                "OFOxmIcmpv6TypeMasked":    OxmMapEntry("U8", "ICMPV6_TYPE", True),
-                "OFOxmIcmpv6Code":          OxmMapEntry("U8", "ICMPV6_CODE", False),
-                "OFOxmIcmpv6CodeMasked":    OxmMapEntry("U8", "ICMPV6_CODE", True),
-                "OFOxmIpv6NdTarget":        OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
-                "OFOxmIpv6NdTargetMasked":  OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
-                "OFOxmIpv6NdSll":           OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
-                "OFOxmIpv6NdSllMasked":     OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
-                "OFOxmIpv6NdTll":           OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
-                "OFOxmIpv6NdTllMasked":     OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
-                "OFOxmMplsLabel":           OxmMapEntry("U32", "MPLS_LABEL", False),
-                "OFOxmMplsLabelMasked":     OxmMapEntry("U32", "MPLS_LABEL", True),
-                "OFOxmMplsTc":              OxmMapEntry("U8", "MPLS_TC", False),
-                "OFOxmMplsTcMasked":        OxmMapEntry("U8", "MPLS_TC", True),
-                "OFOxmBsnInPorts128":       OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", False),
-                "OFOxmBsnInPorts128Masked": OxmMapEntry("OFBitMask128", "BSN_IN_PORTS_128", True),
-                "OFOxmBsnLagId":            OxmMapEntry("LagId", "BSN_LAG_ID", False),
-                "OFOxmBsnLagIdMasked":      OxmMapEntry("LagId", "BSN_LAG_ID", True),
-                "OFOxmBsnVrf":              OxmMapEntry("VRF", "BSN_VRF", False),
-                "OFOxmBsnVrfMasked":        OxmMapEntry("VRF", "BSN_VRF", True),
-                "OFOxmBsnGlobalVrfAllowed":          OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", False),
-                "OFOxmBsnGlobalVrfAllowedMasked":    OxmMapEntry("OFBooleanValue", "BSN_GLOBAL_VRF_ALLOWED", True),
-                "OFOxmBsnL3InterfaceClassId":        OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", False),
-                "OFOxmBsnL3InterfaceClassIdMasked":  OxmMapEntry("ClassId", "BSN_L3_INTERFACE_CLASS_ID", True),
-                "OFOxmBsnL3SrcClassId":              OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", False),
-                "OFOxmBsnL3SrcClassIdMasked":        OxmMapEntry("ClassId", "BSN_L3_SRC_CLASS_ID", True),
-                "OFOxmBsnL3DstClassId":              OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", False),
-                "OFOxmBsnL3DstClassIdMasked":        OxmMapEntry("ClassId", "BSN_L3_DST_CLASS_ID", True),
-                }
-
     # Registry of nullable properties:
     # ${java_class_name} -> set(${java_property_name})
     nullable_map = defaultdict(lambda: set(),
@@ -342,6 +253,14 @@
         else:
             return True
 
+    @property
+    @memoize
+    def oxm_map(self):
+        OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
+        return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
+                                       value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
+                                       masked=oxm.ir_class.name.endswith("_masked")))
+                  for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
 
 class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
     @property
@@ -549,8 +468,8 @@
         elif self.name == "OFOxm":
             return ("oxm", None, "T extends OFValueType<T>")
         elif loxi_utils.class_is_oxm(self.c_name):
-            if self.name in model.oxm_map:
-                return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
+            if self.member_by_name("value") is not None:
+                return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
             else:
                 return ("oxm", "OFOxm", None)
         elif loxi_utils.class_is_instruction(self.c_name):
@@ -629,14 +548,16 @@
                     JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
                    ]
         elif self.ir_class.is_subclassof("of_oxm"):
-            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()
+            value = find(lambda m: m.name=="value", self.ir_model_members)
+            if value:
+                field_type = java_type.make_match_field_jtype(value.java_type.public_type)
+            else:
+                field_type = java_type.make_match_field_jtype()
 
             virtual_members += [
                     JavaVirtualMember(self, "matchField", field_type),
                     JavaVirtualMember(self, "masked", java_type.boolean),
-                    JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(model.oxm_map[self.name].type_name),
+                    JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
                             custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
                    ]
             if not find(lambda x: x.name == "mask", self.ir_model_members):
@@ -760,11 +681,12 @@
     @property
     def virtual_members(self):
         virtual_members = []
-        if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
-            if self.interface.name in model.oxm_map:
+        if self.ir_class.is_subclassof("of_oxm"):
+            value_member = find(lambda m: m.name, self.ir_model_members)
+            if value_member:
                 oxm_entry = model.oxm_map[self.interface.name]
                 virtual_members += [
-                    JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
+                    JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(value_member.java_type.public_type), "MatchField.%s" % oxm_entry.value),
                     JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
                     ]
             else:
@@ -883,7 +805,7 @@
             entry = enum.entry_by_version_value(self.msg.version, self.value)
             return "%s.%s" % ( enum.name, entry.name)
         except KeyError, e:
-            print e.message
+            logger.debug("No enum found", e)
             return self.value
 
     @property
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.java b/java_gen/templates/custom/OFMatchV3Ver13.java
index 9bfb234..24cab5b 100644
--- a/java_gen/templates/custom/OFMatchV3Ver13.java
+++ b/java_gen/templates/custom/OFMatchV3Ver13.java
@@ -1,4 +1,5 @@
-
+//:: from generic_utils import OrderedSet
+//:: from java_gen.java_model import model
     @Override
     public <F extends OFValueType<F>> F get(MatchField<F> field)
             throws UnsupportedOperationException {
@@ -33,36 +34,9 @@
 
     private static boolean supportsField(MatchField<?> field) {
         switch (field.id) {
-            case IN_PORT:
-            case IN_PHY_PORT:
-            case METADATA:
-            case ETH_DST:
-            case ETH_SRC:
-            case ETH_TYPE:
-            case VLAN_VID:
-            case VLAN_PCP:
-            case IP_DSCP:
-            case IP_ECN:
-            case IP_PROTO:
-            case IPV4_SRC:
-            case IPV4_DST:
-            case TCP_SRC:
-            case TCP_DST:
-            case UDP_SRC:
-            case UDP_DST:
-            case SCTP_SRC:
-            case SCTP_DST:
-            case ICMPV4_TYPE:
-            case ICMPV4_CODE:
-            case ARP_OP:
-            case ARP_SPA:
-            case ARP_TPA:
-            case ARP_SHA:
-            case ARP_THA:
-            case IPV6_SRC:
-            case IPV6_DST:
-            case IPV6_FLABEL:
-            case BSN_IN_PORTS_128:
+            //:: for id_constant in sorted(set(id_constant for _, id_constant, _ in model.oxm_map.values())):
+            case ${id_constant}:
+            //:: #endfor
                 return true;
             default:
                 return false;
diff --git a/java_gen/templates/of_factory_class.java b/java_gen/templates/of_factory_class.java
index deb6e53..ef26ca0 100644
--- a/java_gen/templates/of_factory_class.java
+++ b/java_gen/templates/of_factory_class.java
@@ -121,7 +121,7 @@
                 return (OFOxm<F>)((Object)${method_name}((${type_name})((Object)value)));
             //:: #endfor
             default:
-                return null;
+                throw new IllegalArgumentException("No OXM known for match field " + field);
         }
     }
 
@@ -140,7 +140,7 @@
                 return (OFOxm<F>)((Object)${method_name}((${type_name})((Object)value), (${type_name})((Object)mask)));
             //:: #endfor
             default:
-                return null;
+                throw new IllegalArgumentException("No OXM known for match field " + field);
         }
     }