Merge branch 'master' of github.com:floodlight/loxigen
diff --git a/.gitignore b/.gitignore
index 8206747..9712e8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,4 @@
 .*.swp
 .*.swo
 *.cache
+openflowj-loxi
diff --git a/Makefile b/Makefile
index c99ae0b..6f0fbaa 100644
--- a/Makefile
+++ b/Makefile
@@ -43,6 +43,7 @@
                                  \! \( -name '*.cache' -o -name '.*' \))
 INPUT_FILES = $(wildcard openflow_input/*)
 TEST_DATA = $(shell find test_data -name '*.data')
+OPENFLOWJ_WORKSPACE = openflowj-loxi
 
 all: c python
 
@@ -68,14 +69,19 @@
 	@echo "HTML documentation output to ${LOXI_OUTPUT_DIR}/pyloxi-doc"
 
 java: .loxi_ts.java
+	mkdir -p ${OPENFLOWJ_WORKSPACE}
+	ln -sf ../java_gen/pre-written/pom.xml ${OPENFLOWJ_WORKSPACE}/pom.xml
+	ln -sf ../java_gen/pre-written/src ${OPENFLOWJ_WORKSPACE}/src
+	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}
 	./loxigen.py --install-dir=${LOXI_OUTPUT_DIR} --lang=java
 	touch $@
 
 java-eclipse: java
-	mkdir -p java-eclipse
-	rsync --checksum --delete -rv loxi_output/openflowj/ java_eclipse/
+	cd ${OPENFLOWJ_WORKSPACE} && mvn eclipse:eclipse
+	# Unfortunately, mvn eclipse:eclipse resolves the symlink, which doesn't work with eclipse
+	cd ${OPENFLOWJ_WORKSPACE} && perl -pi -e 's{<classpathentry kind="src" path="[^"]*/java_gen/pre-written/src/}{<classpathentry kind="src" path="src/}' .classpath
 
 clean:
 	rm -rf loxi_output # only delete generated files in the default directory
@@ -108,10 +114,17 @@
 	${LOXI_OUTPUT_DIR}/locitest/locitest
 
 check-java: java
-	cd ${LOXI_OUTPUT_DIR}/openflowj/ && mvn compile test-compile test
+	cd ${OPENFLOWJ_WORKSPACE} && mvn compile test-compile test
 
 package-java: java
-	cd ${LOXI_OUTPUT_DIR}/openflowj/ && mvn package
+	cd ${OPENFLOWJ_WORKSPACE} && mvn package
+
+deploy-java: java
+	cd ${OPENFLOWJ_WORKSPACE} && mvn deploy
+
+install-java: java
+	cd ${OPENFLOWJ_WORKSPACE} && mvn install
+
 
 pylint:
 	pylint -E ${LOXI_PY_FILES}
diff --git a/java_gen/README.java-lang b/java_gen/README.java-lang
new file mode 100644
index 0000000..754c13b
--- /dev/null
+++ b/java_gen/README.java-lang
@@ -0,0 +1 @@
+Work in progress to port OpenFlow/J to support OpenFlow 1.0, 1.1., 1.2, and 1.3.
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index 8606682..1b9f445 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -57,8 +57,6 @@
     gen.create_of_const_enums()
     gen.create_of_factories()
 
-    with open('%s/README.java-lang' % os.path.dirname(__file__)) as readme_src:
-        out.writelines(readme_src.readlines())
     out.close()
 
 
@@ -157,6 +155,3 @@
     """ Recursively copy the directory structure from ./java_gen/pre-write
        into $basedir"""
     print "Copying pre-written files into %s" % basedir
-    #subprocess.call("cd java_gen/pre-written && tar cpf - pom.xml | ( cd ../../%s && tar xvpf - )" % basedir,
-    #        shell=True)
-    os.symlink(os.path.abspath("%s/pre-written/pom.xml" %  os.path.dirname(__file__)), "%s/pom.xml" % basedir)
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 0225af5..bd1967b 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -51,7 +51,8 @@
     enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
     # OFUint structs are there for god-knows what in loci. We certainly don't need them.
     interface_blacklist = set( ("OFUint8", "OFUint32",))
-    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
+    read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
+    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
     virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
 
     OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
@@ -346,6 +347,24 @@
         else:
             self.parent_interface = None
 
+    @property
+    @memoize
+    def all_parent_interfaces(self):
+        return [ "OFObject" ] + \
+               ([ self.parent_interface ] if self.parent_interface else [] )+ \
+               self.additional_parent_interfaces
+    @property
+    @memoize
+    def additional_parent_interfaces(self):
+        if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
+            m = re.match(r'(.*)Request$', self.name)
+            if m:
+                reply_name = m.group(1) + "Reply"
+                if model.interface_by_name(reply_name):
+                    return ["OFRequest<%s>" % reply_name ]
+        return []
+
+
     def is_instance_of(self, other_class):
         if self == other_class:
             return True
@@ -387,10 +406,12 @@
             return ("", "OFStatsReply", None)
         elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
             return ("", "OFFlowMod", None)
-        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
+        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name) and self.name != "OFBsnHeader":
             return ("", "OFBsnHeader", None)
-        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
+        elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name) and self.name != "OFNiciraHeader":
             return ("", "OFNiciraHeader", None)
+        elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
+            return ("", "OFExperimenter", None)
         elif re.match(r'OFMatch.*', self.name):
             return ("", "Match", None)
         elif loxi_utils.class_is_message(self.c_name):
@@ -400,6 +421,8 @@
                 return ("action", "OFActionBsn", None)
             elif re.match(r'OFActionNicira.+', self.name):
                 return ("action", "OFActionNicira", None)
+            elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
+                return ("action", "OFActionExperimenter", None)
             else:
                 return ("action", "OFAction", None)
         elif re.match(r'OFBsnVport.+$', self.name):
@@ -450,7 +473,7 @@
                 if of_member.name not in member_map:
                     member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
 
-        return tuple(member_map.values())
+        return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
 
     @property
     def virtual_members(self):
diff --git a/java_gen/pre-written/.classpath b/java_gen/pre-written/.classpath
deleted file mode 100644
index b6bc6ad..0000000
--- a/java_gen/pre-written/.classpath
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="src/main/java"/>
-	<classpathentry kind="lib" path="lib/netty-3.2.6.Final.jar"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/java_gen/pre-written/.project b/java_gen/pre-written/.project
deleted file mode 100644
index b347bd6..0000000
--- a/java_gen/pre-written/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>openflowj-loxi</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
diff --git a/java_gen/pre-written/pom.xml b/java_gen/pre-written/pom.xml
index d01d797..2461cfe 100644
--- a/java_gen/pre-written/pom.xml
+++ b/java_gen/pre-written/pom.xml
@@ -2,9 +2,9 @@
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>org.openflow</groupId>
+    <groupId>org.projectfloodlight</groupId>
     <artifactId>openflowj</artifactId>
-    <version>2.0-SNAPSHOT</version>
+    <version>0.1-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <name>Loxi-Generated OpenFlow/J</name>
@@ -40,16 +40,77 @@
         <version>1.8</version>
         <executions>
             <execution>
+                <id>gen-src-add-source</id>
                 <phase>generate-sources</phase>
                 <goals><goal>add-source</goal></goals>
                 <configuration>
                     <sources>
-                        <source>../../java_gen/pre-written/src/main/java/</source>
+                        <source>gen-src/main/java</source>
+                    </sources>
+                </configuration>
+            </execution>
+            <execution>
+                <id>add-gen-src-test-source</id>
+                <!-- note: purposefully not using phase generate-test-sources,
+                     because that is not picked up by eclipse:eclipse -->
+                <phase>validate</phase>
+                <goals><goal>add-test-source</goal></goals>
+                <configuration>
+                    <sources>
+                        <source>gen-src/test/java</source>
                     </sources>
                 </configuration>
             </execution>
         </executions>
     </plugin>
+    <!-- attach sources -->
+    <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.2.1</version>
+        <executions>
+            <execution>
+                <id>attach-sources</id>
+                <goals>
+                    <goal>jar</goal>
+                </goals>
+            </execution>
+        </executions>
+    </plugin>
+    <!-- attach javadoc -->
+    <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.9.1</version>
+        <executions>
+            <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                    <goal>jar</goal>
+                </goals>
+            </execution>
+        </executions>
+    </plugin>
+    <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <configuration>
+            <downloadSources>true</downloadSources>
+            <downloadJavadocs>true</downloadJavadocs>
+        </configuration>
+    </plugin>
 </plugins>
 </build>
+<distributionManagement>
+  <repository>
+     <id>deployment</id>
+     <name>Internal Releases</name>
+     <url>http://10.197.128.18:8081/nexus/content/repositories/releases/</url>
+  </repository>
+  <snapshotRepository>
+     <id>deployment</id>
+     <name>Internal Releases</name>
+     <url>http://10.197.128.18:8081/nexus/content/repositories/snapshots/</url>
+  </snapshotRepository>
+</distributionManagement>
 </project>
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFRequest.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFRequest.java
new file mode 100644
index 0000000..6666943
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/OFRequest.java
@@ -0,0 +1,5 @@
+package org.projectfloodlight.openflow.protocol;
+
+/** Type safety interface. Enables type safe combinations of requests and replies */
+public interface OFRequest<REPLY extends OFMessage> extends OFMessage {
+}
diff --git a/java_gen/templates/of_interface.java b/java_gen/templates/of_interface.java
index 8ddaba3..8c9bf25 100644
--- a/java_gen/templates/of_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -36,7 +36,7 @@
 
 //:: include("_imports.java", msg=msg)
 
-public interface ${msg.name}${ "<%s>" % msg.type_annotation if msg.type_annotation else ""} 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 ${", ".join(msg.all_parent_interfaces)} {
 //:: for prop in msg.members:
     ${prop.java_type.public_type} ${prop.getter_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endfor
diff --git a/java_gen/templates/of_virtual_class.java b/java_gen/templates/of_virtual_class.java
index fc6a6c0..55ccc5e 100644
--- a/java_gen/templates/of_virtual_class.java
+++ b/java_gen/templates/of_virtual_class.java
@@ -70,7 +70,7 @@
 //:: elif prop.is_fixed_value:
             // fixed value property ${prop.name} == ${prop.value}
             ${prop.java_type.priv_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=False)};
-            if(${prop.name} != ${prop.value})
+            if(${prop.name} != ${prop.priv_value})
                 throw new OFParseError("Wrong ${prop.name}: Expected=${prop.enum_value}(${prop.value}), got="+${prop.name});
 //:: elif prop.is_length_value:
             ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=True)};
diff --git a/openflow_input/standard-1.0 b/openflow_input/standard-1.0
index d78d5bd..5483ff4 100644
--- a/openflow_input/standard-1.0
+++ b/openflow_input/standard-1.0
@@ -335,7 +335,7 @@
     uint8_t type == 4;
     uint16_t length;
     uint32_t xid;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -525,7 +525,7 @@
 struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -919,7 +919,7 @@
     uint32_t xid;
     uint16_t stats_type == 0xffff;
     uint16_t flags;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -930,7 +930,7 @@
     uint32_t xid;
     uint16_t stats_type == 0xffff;
     uint16_t flags;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index 1047127..a1127b1 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -443,7 +443,7 @@
     uint8_t type == 4;
     uint16_t length;
     uint32_t xid;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -742,7 +742,7 @@
 struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -837,7 +837,7 @@
 struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -1327,7 +1327,7 @@
     uint16_t stats_type == 0xffff;
     uint16_t flags;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     pad(4);
     of_octets_t data;
 };
@@ -1340,7 +1340,7 @@
     uint16_t stats_type == 0xffff;
     uint16_t flags;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     pad(4);
     of_octets_t data;
 };
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index e4c8ec2..bfa9a64 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -483,7 +483,7 @@
     uint8_t type == 4;
     uint16_t length;
     uint32_t xid;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -699,7 +699,7 @@
 struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -753,7 +753,7 @@
 struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -1317,7 +1317,7 @@
     uint16_t stats_type == 0xffff;
     uint16_t flags;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -1330,7 +1330,7 @@
     uint16_t stats_type == 0xffff;
     uint16_t flags;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -1363,7 +1363,7 @@
     uint16_t type == 65535;
     uint16_t len;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     pad(4);
     of_octets_t data;
 };
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index b9c5475..119e7a4 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -608,7 +608,7 @@
     uint8_t type == 4;
     uint16_t length;
     uint32_t xid;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
     of_octets_t data;
 };
@@ -833,7 +833,7 @@
 struct of_action_experimenter : of_action {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -905,7 +905,7 @@
 struct of_instruction_experimenter : of_instruction {
     uint16_t type == 65535;
     uint16_t len;
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     of_octets_t data;
 };
 
@@ -1177,7 +1177,8 @@
     uint16_t priority;
     uint16_t idle_timeout;
     uint16_t hard_timeout;
-    pad(6);
+    uint16_t flags;
+    pad(4);
     uint64_t cookie;
     uint64_t packet_count;
     uint64_t byte_count;
@@ -1770,7 +1771,7 @@
 };
 
 struct of_experimenter_multipart_header {
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     uint32_t subtype;
 };
 
@@ -1802,7 +1803,7 @@
     uint16_t type == 65535;
     uint16_t len;
     pad(4);
-    uint32_t experimenter;
+    uint32_t experimenter == ?;
     pad(4);
     of_octets_t data;
 };
diff --git a/py_gen/codegen.py b/py_gen/codegen.py
index 6570938..540d212 100644
--- a/py_gen/codegen.py
+++ b/py_gen/codegen.py
@@ -54,13 +54,10 @@
 # Create intermediate representation, extended from the LOXI IR
 # HACK the oftype member attribute is replaced with an OFType instance
 def build_ofclasses(version):
-    blacklist = ["of_experimenter", "of_action_experimenter"]
     ofclasses = []
     for ofclass in of_g.ir[version].classes:
         cls = ofclass.name
-        if type_maps.class_is_virtual(cls):
-            continue
-        if cls in blacklist:
+        if ofclass.virtual:
             continue
 
         members = []
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index 6754b94..7158545 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -226,11 +226,6 @@
     const.OFPST_TABLE : table_stats_reply.unpack,
     const.OFPST_PORT : port_stats_reply.unpack,
     const.OFPST_QUEUE : queue_stats_reply.unpack,
-:: if version < of_g.VERSION_1_1:
-    const.OFPST_VENDOR : experimenter_stats_reply.unpack,
-:: else:
-    const.OFPST_EXPERIMENTER : experimenter_stats_reply.unpack,
-:: #endif
 :: if version >= of_g.VERSION_1_1:
     const.OFPST_GROUP : group_stats_reply.unpack,
     const.OFPST_GROUP_DESC : group_desc_stats_reply.unpack,
@@ -247,11 +242,6 @@
     const.OFPST_TABLE : table_stats_request.unpack,
     const.OFPST_PORT : port_stats_request.unpack,
     const.OFPST_QUEUE : queue_stats_request.unpack,
-:: if version < of_g.VERSION_1_1:
-    const.OFPST_VENDOR : experimenter_stats_request.unpack,
-:: else:
-    const.OFPST_EXPERIMENTER : experimenter_stats_request.unpack,
-:: #endif
 :: if version >= of_g.VERSION_1_1:
     const.OFPST_GROUP : group_stats_request.unpack,
     const.OFPST_GROUP_DESC : group_desc_stats_request.unpack,