group_mod: add subclass structure

the subclass structure is hidden from the c_gen of_g
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 5fe8097..d1a9e67 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -328,6 +328,8 @@
         .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
             write='$name.writeTo(bb)',
             default="OFFactoryVer$version.MATCH_WILDCARD_ALL");
+group_mod_cmd = JType('OFGroupModCommand', 'short') \
+        .op(version=ANY, read="bb.readShort()", write="bb.writeShort($name)")
 flow_mod_cmd = JType('OFFlowModCommand', 'short') \
         .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
         .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
@@ -603,6 +605,13 @@
         'of_action_set_tp_src': { 'tp_port': transport_port },
         'of_action_set_vlan_pcp': { 'vlan_pcp': vlan_pcp },
         'of_action_set_vlan_vid': { 'vlan_vid': vlan_vid },
+
+        'of_group_mod' : { 'command' : group_mod_cmd },
+        'of_group_add' : { 'command' : group_mod_cmd },
+        'of_group_modify' : { 'command' : group_mod_cmd },
+        'of_group_delete' : { 'command' : group_mod_cmd },
+
+        'of_bucket' : { 'watch_group': of_group },
 }
 
 
diff --git a/openflow_input/standard-1.1 b/openflow_input/standard-1.1
index 9b72e8c..906519c 100644
--- a/openflow_input/standard-1.1
+++ b/openflow_input/standard-1.1
@@ -984,8 +984,44 @@
     uint8_t type == 15;
     uint16_t length;
     uint32_t xid;
-    uint16_t command;
-    uint8_t group_type;
+    enum ofp_group_mod_command command == ?;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_add : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 0;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_modify : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 1;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_delete : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 2;
+    enum ofp_group_type group_type;
     pad(1);
     uint32_t group_id;
     list(of_bucket_t) buckets;
diff --git a/openflow_input/standard-1.2 b/openflow_input/standard-1.2
index e9d915a..9a48154 100644
--- a/openflow_input/standard-1.2
+++ b/openflow_input/standard-1.2
@@ -898,8 +898,44 @@
     uint8_t type == 15;
     uint16_t length;
     uint32_t xid;
-    uint16_t command;
-    uint8_t group_type;
+    enum ofp_group_mod_command command == ?;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_add : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 0;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_modify : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 1;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_delete : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 2;
+    enum ofp_group_type group_type;
     pad(1);
     uint32_t group_id;
     list(of_bucket_t) buckets;
diff --git a/openflow_input/standard-1.3 b/openflow_input/standard-1.3
index db7ff0d..e7a1362 100644
--- a/openflow_input/standard-1.3
+++ b/openflow_input/standard-1.3
@@ -1058,8 +1058,44 @@
     uint8_t type == 15;
     uint16_t length;
     uint32_t xid;
-    uint16_t command;
-    uint8_t group_type;
+    enum ofp_group_mod_command command == ?;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_add : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 0;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_modify : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 1;
+    enum ofp_group_type group_type;
+    pad(1);
+    uint32_t group_id;
+    list(of_bucket_t) buckets;
+};
+
+struct of_group_delete : of_group_mod {
+    uint8_t version;
+    uint8_t type == 15;
+    uint16_t length;
+    uint32_t xid;
+    enum ofp_group_mod_command command == 2;
+    enum ofp_group_type group_type;
     pad(1);
     uint32_t group_id;
     list(of_bucket_t) buckets;
diff --git a/py_gen/templates/message.py b/py_gen/templates/message.py
index 96b68cc..23f28dc 100644
--- a/py_gen/templates/message.py
+++ b/py_gen/templates/message.py
@@ -147,6 +147,18 @@
     else:
         raise loxi.ProtocolError("unexpected flow mod cmd %u" % cmd)
 
+:: if version >= OFVersions.VERSION_1_0:
+def parse_group_mod(buf):
+:: offset = 8
+    if len(buf) < ${offset} + 2:
+        raise loxi.ProtocolError("message too short")
+    cmd, = struct.unpack_from("!H", buf, ${offset})
+    if cmd in flow_mod_parsers:
+        return group_mod_parsers[cmd](buf)
+    else:
+        raise loxi.ProtocolError("unexpected group mod cmd %u" % cmd)
+:: #endif
+
 def parse_stats_reply(buf):
     if len(buf) < 8 + 2:
         raise loxi.ProtocolError("message too short")
@@ -228,6 +240,14 @@
     const.OFPFC_DELETE_STRICT : flow_delete_strict.unpack,
 }
 
+:: if version >= OFVersions.VERSION_1_1:
+group_mod_parsers = {
+    const.OFPGC_ADD : group_add.unpack,
+    const.OFPGC_MODIFY : group_modify.unpack,
+    const.OFPGC_DELETE : group_delete.unpack,
+}
+:: #endif
+
 stats_reply_parsers = {
     const.OFPST_DESC : desc_stats_reply.unpack,
     const.OFPST_FLOW : flow_stats_reply.unpack,
diff --git a/test_data/of13/group_mod.data b/test_data/of13/group_modify.data
similarity index 65%
rename from test_data/of13/group_mod.data
rename to test_data/of13/group_modify.data
index 8f25b57..87eee29 100644
--- a/test_data/of13/group_mod.data
+++ b/test_data/of13/group_modify.data
@@ -37,9 +37,8 @@
 00 00 # buckets[1].actions[1].max_len
 00 00 00 00 00 00 # pad
 -- python
-ofp.message.group_mod(
+ofp.message.group_modify(
     xid=0x12345678,
-    command=ofp.OFPGC_MODIFY,
     group_type=ofp.OFPGT_FF,
     group_id=5,
     buckets=[
@@ -57,3 +56,31 @@
             actions=[
                 ofp.action.output(port=5, max_len=0),
                 ofp.action.output(port=6, max_len=0)])])
+-- java
+    OFActions actions = factory.actions();
+    builder
+      .setXid(0x12345678)
+      .setGroupType(OFGroupType.FF)
+      .setGroup(OFGroup.of(5))
+      .setBuckets(ImmutableList.<OFBucket>of(
+        factory.buildBucket()
+          .setWeight(1)
+          .setWatchPort(OFPort.of(5))
+          .setWatchGroup(OFGroup.ANY)
+          .setActions(ImmutableList.<OFAction>of(
+            actions.output(OFPort.of(5), 0),
+            actions.output(OFPort.of(6), 0)
+          ))
+          .build(),
+        factory.buildBucket()
+          .setWeight(1)
+          .setWatchPort(OFPort.of(6))
+          .setWatchGroup(OFGroup.ANY)
+          .setActions(ImmutableList.<OFAction>of(
+            actions.output(OFPort.of(5), 0),
+            actions.output(OFPort.of(6), 0)
+          ))
+          .build()
+         )
+      )
+      .build();