java_gen: API improvements for BundleMessages.

This commit introducesa BundleId class that models the bundle id,
and enables us to use OFBundleCtrlMsg in our usual writeRequest()
framework (in detail, we make the OFBundleCtrlMessage an OFRequest,
its response type is also OFBundleCtrlMsg).

It would be somewhat cleaner from Java's perspective to Factor
out the individual OFBundleCtrlMessage subtypes into their
own request/responses (like we do with flod_mods).
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index b3c3df0..79cea7a 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -413,6 +413,9 @@
                 reply_name = m.group(1) + "Reply"
                 if model.interface_by_name(reply_name):
                     return ["OFRequest<%s>" % reply_name ]
+            elif self.name == "OFBundleCtrlMsg":
+                reply_name = "OFBundleCtrlMsg"
+                return ["OFRequest<%s>" % reply_name ]
         return []
 
 
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index b23dcd0..a78c572 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -470,6 +470,10 @@
 
 port_speed = JType("PortSpeed")
 error_type = JType("OFErrorType")
+of_message = JType("OFMessage")\
+            .op(read="OFMessageVer$version.READER.readFrom(bb)",
+                write="$name.writeTo(bb)")
+
 of_type = JType("OFType", 'byte') \
             .op(read='bb.readByte()', write='bb.writeByte($name)')
 action_type= gen_enum_jtype("OFActionType")\
@@ -514,6 +518,10 @@
         .op(read='GenTableId.read2Bytes(bb)',
             write='$name.write2Bytes(bb)',
            )
+bundle_id = JType("BundleId") \
+        .op(read='BundleId.read4Bytes(bb)',
+            write='$name.write4Bytes(bb)',
+           )
 udf = JType("UDF") \
          .op(version=ANY, read="UDF.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="UDF.ZERO")
 error_cause_data = JType("OFErrorCauseData") \
@@ -718,6 +726,8 @@
         'of_bsn_log': { 'data': var_string },
 
         'of_features_reply' : { 'auxiliary_id' : of_aux_id},
+
+        'of_bundle_add_msg' : { 'data' : of_message },
 }
 
 
@@ -782,6 +792,8 @@
         return action_type_set
     elif field_name == "table_id" and re.match(r'of_bsn_gentable.*', obj_name):
         return gen_table_id
+    elif field_name == "bundle_id" and re.match(r'of_bundle_.*', obj_name):
+        return bundle_id
     elif c_type in default_mtype_to_jtype_convert_map:
         return default_mtype_to_jtype_convert_map[c_type]
     elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java
new file mode 100644
index 0000000..2cb3583
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerator.java
@@ -0,0 +1,7 @@
+package org.projectfloodlight.openflow.protocol;
+
+import org.projectfloodlight.openflow.types.BundleId;
+
+public interface BundleIdGenerator {
+    BundleId nextBundleId();
+}
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java
new file mode 100644
index 0000000..997e0cd
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/protocol/BundleIdGenerators.java
@@ -0,0 +1,28 @@
+package org.projectfloodlight.openflow.protocol;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.projectfloodlight.openflow.types.BundleId;
+
+public class BundleIdGenerators {
+    private static final BundleIdGenerator GLOBAL_BUNDLE_ID_GENERATOR = create();
+
+    public static BundleIdGenerator create() {
+        return new StandardBundleIdGenerator();
+    }
+
+    public static BundleIdGenerator global() {
+        return GLOBAL_BUNDLE_ID_GENERATOR;
+    }
+}
+
+class StandardBundleIdGenerator implements BundleIdGenerator {
+
+    private final AtomicInteger idGen = new AtomicInteger();
+
+    @Override
+    public BundleId nextBundleId() {
+        return BundleId.of(idGen.incrementAndGet());
+    }
+
+}
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java
new file mode 100644
index 0000000..cccf67e
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/types/BundleId.java
@@ -0,0 +1,92 @@
+package org.projectfloodlight.openflow.types;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+
+import com.google.common.hash.PrimitiveSink;
+import com.google.common.primitives.UnsignedInts;
+
+@Immutable
+public class BundleId implements OFValueType<BundleId> {
+    static final int LENGTH = 4;
+
+    private final static int NONE_VAL = 0;
+    public final static BundleId NONE = new BundleId(NONE_VAL);
+
+    private final static int NO_MASK_VAL = 0xFFFFFFFF;
+    public final static BundleId NO_MASK = new BundleId(NO_MASK_VAL);
+    public final static BundleId FULL_MASK = NONE;
+
+    private final int rawValue;
+
+    private BundleId(final int rawValue) {
+        this.rawValue = rawValue;
+    }
+
+    public static BundleId of(final int raw) {
+        if(raw == NONE_VAL)
+            return NONE;
+        else if(raw == NO_MASK_VAL)
+            return NO_MASK;
+        return new BundleId(raw);
+    }
+
+    public int getInt() {
+        return rawValue;
+    }
+
+    @Override
+    public int getLength() {
+        return LENGTH;
+    }
+
+    @Override
+    public String toString() {
+        return UnsignedInts.toString(rawValue);
+    }
+
+    @Override
+    public BundleId applyMask(BundleId mask) {
+        return BundleId.of(rawValue & mask.rawValue);    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + rawValue;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        BundleId other = (BundleId) obj;
+        if (rawValue != other.rawValue)
+            return false;
+        return true;
+    }
+
+    public void write4Bytes(ChannelBuffer c) {
+        c.writeInt(rawValue);
+    }
+
+    public static BundleId read4Bytes(ChannelBuffer c) {
+        return BundleId.of(c.readInt());
+    }
+
+    @Override
+    public int compareTo(BundleId o) {
+        return UnsignedInts.compare(rawValue, rawValue);
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        sink.putInt(rawValue);
+    }
+}