java_loxi: big refactoring and clean-up
diff --git a/java_gen/.classpath b/java_gen/.classpath
new file mode 100644
index 0000000..050cd9c
--- /dev/null
+++ b/java_gen/.classpath
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="lib" path="pre-written/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/.project b/java_gen/.project
new file mode 100644
index 0000000..b347bd6
--- /dev/null
+++ b/java_gen/.project
@@ -0,0 +1,17 @@
+<?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/codegen.py b/java_gen/codegen.py
new file mode 100644
index 0000000..a208c0d
--- /dev/null
+++ b/java_gen/codegen.py
@@ -0,0 +1,141 @@
+# Copyright 2013, Big Switch Networks, Inc.
+#
+# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+# the following special exception:
+#
+# LOXI Exception
+#
+# As a special exception to the terms of the EPL, you may distribute libraries
+# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+# that copyright and licensing notices generated by LoxiGen are not altered or removed
+# from the LoxiGen Libraries and the notice provided below is (i) included in
+# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+# documentation for the LoxiGen Libraries, if distributed in binary form.
+#
+# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+#
+# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+# a copy of the EPL at:
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# EPL for the specific language governing permissions and limitations
+# under the EPL.
+
+"""
+@brief Main Java Generation module
+"""
+
+import pdb
+import os
+import shutil
+
+import of_g
+from loxi_ir import *
+import lang_java
+
+import loxi_utils.loxi_utils as loxi_utils
+
+import java_gen.java_model as java_model
+
+def gen_all_java(out, name):
+    target_dir='loxi_output/openflowj'
+    basedir="%s/%s/" % (
+            target_dir,
+            lang_java.file_to_subdir_map['base_java'])
+    srcdir = "%s/src/main/java/" % basedir
+    print "Outputting to %s" % basedir
+    if os.path.exists(basedir):
+        shutil.rmtree(basedir)
+    os.makedirs(basedir)
+    copy_prewrite_tree(basedir)
+
+    gen = JavaGenerator(srcdir)
+    gen.create_of_interfaces()
+    gen.create_of_classes()
+    gen.create_of_const_enums()
+
+    with open('README.java-lang') as readme_src:
+        out.writelines(readme_src.readlines())
+    out.close()
+
+
+class JavaGenerator(object):
+    templates_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
+
+    def __init__(self, basedir):
+        self.basedir = basedir
+        self.java_model = java_model.model
+
+    def render_class(self, clazz, template, **context):
+        context['class_name'] = clazz.name
+        context['package'] = clazz.package
+
+        filename = os.path.join(self.basedir, "%s/%s.java" % (clazz.package.replace(".", "/"), clazz.name))
+        dirname = os.path.dirname(filename)
+        if not os.path.exists(dirname):
+            os.makedirs(dirname)
+        prefix = '//::(?=[ \t]|$)'
+        print "filename: %s" % filename
+        with open(filename, "w") as f:
+            loxi_utils.render_template(f, template, [self.templates_dir], context, prefix=prefix)
+
+    def create_of_const_enums(self):
+        for enum in self.java_model.enums:
+            if enum.name in ["OFPort"]:
+                continue
+            self.render_class(clazz=enum,
+                    template='const.java', enum=enum, all_versions=self.java_model.versions)
+
+    def create_of_interfaces(self):
+        """ Create the base interfaces for of classes"""
+        for interface in self.java_model.interfaces:
+            #if not utils.class_is_message(interface.c_name):
+            #    continue
+            self.render_class(clazz=interface,
+                    template="of_interface.java", msg=interface)
+
+    def create_of_classes(self):
+        """ Create the OF classes with implementations for each of the interfaces and versions """
+        for interface in self.java_model.interfaces:
+            if not loxi_utils.class_is_message(interface.c_name) and not loxi_utils.class_is_oxm(interface.c_name):
+                continue
+            for java_class in interface.versioned_classes:
+                self.render_class(clazz=java_class,
+                        template='of_class.java', version=java_class.version, msg=java_class,
+                        impl_class=java_class.name)
+
+
+def mkdir_p(path):
+    """ Emulates `mkdir -p` """
+    try:
+        os.makedirs(path)
+    except OSError as exc: # Python >2.5
+        if exc.errno == errno.EEXIST:
+            pass
+        else: raise
+
+def copy_file_with_boiler_plate(src_name, dst_name, with_boiler=True):
+    with open("java_gen/pre-written/%s" % src_name, "r") as src:
+        with open(dst_name, "w") as dst:
+            if with_boiler:
+                print_boiler_plate(os.path.basename(dst_name), dst)
+            dst.writelines(src.readlines())
+
+def frob(s, **kwargs):
+    """ Step through string s and for each key in kwargs,
+         replace $key with kwargs[key] in s.
+    """
+    for k,v in kwargs.iteritems():
+        s = s.replace('$%s' % k, v)
+    return s
+
+def copy_prewrite_tree(basedir):
+    """ 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 - . | ( cd ../../%s && tar xvpf - )" % basedir,
+#            shell=True)
diff --git a/java_gen/java_code_gen.py b/java_gen/java_code_gen.py
deleted file mode 100644
index 91c89a7..0000000
--- a/java_gen/java_code_gen.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import of_g
-import pdb
-import os
-
-import lang_java
-
-import loxi_utils.loxi_utils as loxi_utils
-
-import java_gen.msgs as msgs
-import java_gen.java_utils as java_utils
-
-def gen_all_java(out, name):
-    """ Generate all of the java files
-
-    @param out is an open file handle to a file called README
-    @param name should be 'README' and is ignored for the java
-        driver
-    """
-    messages = list()
-    actions = list()
-    instructions = list()
-    matches = list()
-    stat_types = list()
-    queue_prop = list()
-    lists = list()
-    for cls in of_g.unified:
-        print "! Classifying %s" % cls
-        if cls in [ 'of_stats_reply', 'of_flow_mod', 'of_stats_request' ] :
-            continue # doesn't work?!
-        if loxi_utils.class_is_stats_message(cls):
-            stat_types.append(cls)
-        elif loxi_utils.class_is_message(cls):
-            messages.append(cls)
-        elif loxi_utils.class_is_action(cls):
-            actions.append(cls)
-        elif loxi_utils.class_is_instruction(cls):
-            instructions.append(cls)
-        elif loxi_utils.class_is_oxm(cls):
-            matches.append(cls)
-        elif loxi_utils.class_is_queue_prop(cls):
-            queue_prop.append(cls)
-        elif loxi_utils.class_is_list(cls):
-            lists.append(cls)
-        else:
-            print "Skipping Unknown class object %s" % str(cls)
-    print "Parsed "
-    print "  Messages: %d" % len(messages)
-    print "  Actions: %d" % len(actions)
-    print "  Instructions: %d" % len(instructions)
-    print "  OXM matches: %d" % len(matches)
-    print "  Stat types: %d" % len(stat_types)
-    print "  Queue properties: %d" % len(queue_prop)
-    print "  Lists: %d" % len(lists)
-    target_dir='loxi_output/openflowj'
-    basedir="%s/%s/" % (
-            target_dir,
-            lang_java.file_to_subdir_map['base_java'])
-    srcdir = "%s/src/main/java/org/openflow/protocol" % basedir
-    print "Outputting to %s" % basedir
-    if not os.path.exists(basedir):
-        os.makedirs(basedir)
-    java_utils.copy_prewrite_tree(basedir)
-    msgs.create_message_interfaces(messages,srcdir)
-    msgs.create_message_by_version(messages,srcdir)
-    msgs.create_of_type_enum(messages,srcdir)
-    with open('README.java-lang') as readme_src:
-        out.writelines(readme_src.readlines())
-    out.close()
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 062a64d..59df72a 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -1,19 +1,103 @@
+# Copyright 2013, Big Switch Networks, Inc.
+#
+# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+# the following special exception:
+#
+# LOXI Exception
+#
+# As a special exception to the terms of the EPL, you may distribute libraries
+# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+# that copyright and licensing notices generated by LoxiGen are not altered or removed
+# from the LoxiGen Libraries and the notice provided below is (i) included in
+# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+# documentation for the LoxiGen Libraries, if distributed in binary form.
+#
+# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+#
+# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+# a copy of the EPL at:
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# EPL for the specific language governing permissions and limitations
+# under the EPL.
+
 # Prototype of an Intermediate Object model for the java code generator
 # A lot of this stuff could/should probably be merged with the python utilities
 
-import of_g
+import collections
+from collections import namedtuple, defaultdict
+import logging
 import os
 import pdb
 import re
 
+from generic_utils import find, memoize, OrderedSet
+import of_g
+from loxi_ir import *
 import loxi_front_end.type_maps as type_maps
 import loxi_utils.loxi_utils as utils
 import py_gen.util as py_utils
 
-import java_gen.java_utils as java_utils
-ignore_fields = ['version', 'xid', 'length', 'type' ]
+import java_gen.java_type as java_type
 
-protected_fields = ['version', 'length']
+class JavaModel(object):
+    write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)))
+    virtual_interfaces = set(['OFOxm' ])
+
+    @property
+    @memoize
+    def versions(self):
+        return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
+
+    @property
+    @memoize
+    def interfaces(self):
+        version_map_per_class = collections.defaultdict(lambda: {})
+
+        for raw_version, of_protocol in of_g.ir.items():
+            jversion = JavaOFVersion(of_protocol.wire_version)
+
+            for of_class in of_protocol.classes:
+                version_map_per_class[of_class.name][jversion] = of_class
+
+        interfaces = []
+        for class_name, version_map in version_map_per_class.items():
+            interfaces.append(JavaOFInterface(class_name, version_map))
+
+        return interfaces
+
+    @property
+    @memoize
+    def enums(self):
+        enum_entry_version_value_map = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.OrderedDict()))
+
+        for version in self.versions:
+            of_protocol = of_g.ir[version.int_version]
+            for enum in of_protocol.enums:
+                for entry_name, entry_value in enum.values:
+                    enum_entry_version_value_map[enum.name][entry_name][version] = entry_value
+
+        enums = [ JavaEnum(name, entry_version_value_map) for name, entry_version_value_map
+                        in enum_entry_version_value_map.items() ]
+
+        return enums
+
+    @memoize
+    def enum_by_name(self, name):
+        try:
+            return find(self.enums, lambda e: e.name == name)
+        except KeyError:
+            raise KeyError("Could not find enum with name %s" % name)
+
+model = JavaModel()
+
+#######################################################################
+### OFVersion
+#######################################################################
 
 class JavaOFVersion(object):
     """ Models a version of OpenFlow. contains methods to convert the internal
@@ -29,17 +113,193 @@
     def constant_version(self):
         return "OF_" + self.of_version
 
+    def __repr__(self):
+        return "JavaOFVersion(%d)" % self.int_version
+
     def __str__(self):
         return of_g.param_version_names[self.int_version]
 
-class JavaProperty(object):
-    """ Models a property (member) of an openflow class. """
-    def __init__(self, msg, java_type, c_type, name, c_name):
-        self.msg = msg
-        self.java_type = java_type
-        self.c_type = c_type
-        self.name = name
+    def __hash__(self):
+        return hash(self.int_version)
+
+    def __eq__(self, other):
+        if other is None or type(self) != type(other):
+            return False
+        return (self.int_version,) == (other.int_version,)
+
+#######################################################################
+### Interface
+#######################################################################
+
+class JavaOFInterface(object):
+    """ Models an OpenFlow Message class for the purpose of the java class.
+        Version agnostic, in contrast to the loxi_ir python model.
+    """
+    def __init__(self, c_name, version_map):
         self.c_name = c_name
+        self.version_map = version_map
+        self.name = java_type.name_c_to_caps_camel(c_name)
+        self.builder_name = self.name + "Builder"
+        self.constant_name = c_name.upper().replace("OF_", "")
+
+        pck_suffix, parent_interface = 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 class_info(self):
+        if re.match(r'OFFlow(Add|Modify(Strict?)|Deleted(Strict?))', self.name):
+            return ("", "OFFlowMod")
+        elif utils.class_is_message(self.c_name):
+            return ("", "OFMessage")
+        elif utils.class_is_action(self.c_name):
+            return ("action", "OFAction")
+        elif utils.class_is_oxm(self.c_name):
+            return ("oxm", "OFOxm")
+        elif utils.class_is_instruction(self.c_name):
+            return ("instruction", "OFInstruction")
+        elif utils.class_is_meter_band(self.c_name):
+            return ("meterband", "OFMeterBand")
+        else:
+            return ("", None)
+
+    @property
+    @memoize
+    def members(self):
+        all_versions = []
+        member_map = collections.OrderedDict()
+
+        for (version, of_class) in self.version_map.items():
+            for of_member in of_class.members:
+                if isinstance(of_member, OFLengthMember) or \
+                   isinstance(of_member, OFFieldLengthMember) or \
+                   isinstance(of_member, OFPadMember):
+                    continue
+                if of_member.name not in member_map:
+                    member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
+
+        return member_map.values()
+
+    @property
+    @memoize
+    def is_virtual(self):
+        return self.name in model.virtual_interfaces
+
+    @property
+    @memoize
+    def all_versions(self):
+        return self.version_map.keys()
+
+    def versioned_class(self, version):
+        return JavaOFClass(self, version, self.version_map[version])
+
+    @property
+    @memoize
+    def versioned_classes(self):
+        if self.is_virtual:
+            return []
+        else:
+            return [ self.versioned_class(version) for version in self.all_versions ]
+
+#######################################################################
+### (Versioned) Classes
+#######################################################################
+
+class JavaOFClass(object):
+    """ Models an OpenFlow Message class for the purpose of the java class.
+        Version agnostic, in contrast to the loxi_ir python model.
+    """
+    def __init__(self, interface, version, ir_class):
+        self.interface = interface
+        self.ir_class = ir_class
+        self.c_name = self.ir_class.name
+        self.version = version
+        self.constant_name = self.c_name.upper().replace("OF_", "")
+        self.package = "org.openflow.protocol.ver%s" % version.of_version
+
+    @property
+    def name(self):
+        return "%sVer%s" % (self.interface.name, self.version.of_version)
+
+    @property
+    def length(self):
+        if self.is_fixed_length:
+            return self.min_length
+        else:
+            raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
+
+    @property
+    def min_length(self):
+        id_tuple = (self.ir_class.name, self.version.int_version)
+        return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
+
+    @property
+    def is_fixed_length(self):
+        return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length
+
+    def all_properties(self):
+        return self.interface.members
+
+    def get_member(self, name):
+        for m in self.members:
+            if m.name == name:
+                return m
+
+    @property
+    @memoize
+    def data_members(self):
+        return [ prop for prop in self.members if prop.is_data ]
+
+    @property
+    @memoize
+    def fixed_value_members(self):
+        return [ prop for prop in self.members if prop.is_fixed_value ]
+
+    @property
+    @memoize
+    def public_members(self):
+        return [ prop for prop in self.members if prop.is_public ]
+
+    @property
+    @memoize
+    def members(self):
+        members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
+        return members
+
+    def all_versions(self):
+        return [ JavaOFVersion(int_version)
+                 for int_version in of_g.unified[self.c_name]
+                 if int_version != 'union' and int_version != 'object_id' ]
+
+    def version_is_inherited(self, version):
+        return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
+
+    def inherited_from(self, version):
+        return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
+
+    @property
+    def is_virtual(self):
+        return type_maps.class_is_virtual(self.c_name)
+
+    @property
+    def is_extension(self):
+        return type_maps.message_is_extension(self.c_name, -1)
+
+#######################################################################
+### Member
+#######################################################################
+
+
+class JavaMember(object):
+    """ Models a property (member) of an openflow class. """
+    def __init__(self, msg, name, java_type, member):
+        self.msg = msg
+        self.name = name
+        self.java_type = java_type
+        self.member = member
+        self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
 
     @property
     def title_name(self):
@@ -51,13 +311,18 @@
 
     @property
     def default_name(self):
-        return "DEFAULT_"+self.constant_name
+        if self.is_fixed_value:
+            return self.constant_name
+        else:
+            return "DEFAULT_"+self.constant_name
 
     @property
     def default_value(self):
         java_type = self.java_type.public_type;
 
-        if re.match(r'List.*', java_type):
+        if self.is_fixed_value:
+            return self.enum_value
+        elif re.match(r'List.*', java_type):
             return "Collections.emptyList()"
         elif java_type == "boolean":
             return "false";
@@ -67,114 +332,162 @@
             return "null";
 
     @property
+    def enum_value(self):
+        if self.name == "version":
+            return "OFVersion.%s" % self.msg.version.constant_version
+
+        java_type = self.java_type.public_type;
+        try:
+            global model
+            enum = model.enum_by_name(java_type)
+            entry = enum.entry_by_version_value(self.msg.version, self.value)
+            return "%s.%s" % ( enum.name, entry.name)
+        except KeyError, e:
+            print e.message
+            return self.value
+
+    @property
     def is_pad(self):
-        return self.c_name.startswith("pad")
+        return isinstance(self.member, OFPadMember)
+
+    def is_type_value(self, version=None):
+        if(version==None):
+            return any(self.is_type_value(version) for version in self.msg.all_versions)
+        try:
+            return self.c_name in get_type_values(self.msg.c_name, version.int_version)
+        except:
+            return False
+
+    @property
+    def is_field_length_value(self):
+        return isinstance(self.member, OFFieldLengthMember)
+
+    @property
+    def is_length_value(self):
+        return isinstance(self.member, OFLengthMember)
+
+    @property
+    def is_public(self):
+        return not (self.is_pad or self.is_length_value)
+
+    @property
+    def is_data(self):
+        return isinstance(self.member, OFDataMember) and self.name != "version"
+
+    @property
+    def is_fixed_value(self):
+        return hasattr(self.member, "value") or self.name == "version" \
+                or ( self.name == "length" and self.msg.is_fixed_length) \
+                or ( self.name == "len" and self.msg.is_fixed_length)
+
+    @property
+    def value(self):
+        if self.name == "version":
+            return self.msg.version.int_version
+        elif self.name == "length" or self.name == "len":
+            return self.msg.length
+        elif self.java_type.public_type in ("int", "short", "byte") and self.member.value > 100:
+            return "0x%x" % self.member.value
+        else:
+            return self.member.value
+
+    @property
+    def is_writeable(self):
+        return self.is_data and not self.name in model.write_blacklist[self.msg.name]
+
+    def get_type_value_info(self, version):
+        return get_type_values(msg.c_name, version.int_version)[self.c_name]
 
     @property
     def length(self):
-        count, base = utils.type_dec_to_count_base(self.c_type)
-        return of_g.of_base_types[base]['bytes'] * count
+        if hasattr(self.member, "length"):
+            return self.member.length
+        else:
+            count, base = utils.type_dec_to_count_base(self.member.type)
+            return of_g.of_base_types[base]['bytes'] * count
 
     @staticmethod
-    def for_field(msg, field, c_name=None):
-        if not c_name:
-            c_name = field['name']
-
-        name = java_utils.name_c_to_camel(c_name)
-        java_type = java_utils.convert_to_jtype(msg.c_name, c_name, field['m_type'])
-        c_type = field['m_type']
-        return JavaProperty(msg, java_type, c_type, name, c_name)
+    def for_of_member(java_class, member):
+        if isinstance(member, OFPadMember):
+            return JavaMember(None, "", None, member)
+        else:
+            if member.name == 'len':
+                name = 'length'
+            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)
+            return JavaMember(java_class, name, j_type, member)
 
     @property
     def is_universal(self):
+        if not self.msg.c_name in of_g.unified:
+            print("%s not self.unified" % self.msg.c_name)
+            return False
         for version in of_g.unified[self.msg.c_name]:
             if version == 'union' or version =='object_id':
                 continue
             if 'use_version' in of_g.unified[self.msg.c_name][version]:
                 continue
 
-            if not self.c_name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
+            if not self.member.name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
                 return False
         return True
 
-class JavaOFMessage(object):
-    """ Models an OpenFlow Message class """
-    def __init__(self, c_name):
-        self.c_name = c_name
-        self.interface_name = java_utils.name_c_to_caps_camel(c_name)
-        self.builder_name = self.interface_name + "Builder"
-        self.constant_name = c_name.upper().replace("OF_", "")
+    def __hash__(self):
+        return hash(self.name)
 
-    def min_length(self, version):
-        return of_g.base_length[(self.c_name, version.int_version)] if (self.c_name, version.int_version) in of_g.base_length else -1
-
-    def is_fixed_length(self, version):
-        return (self.c_name, version.int_version) in of_g.is_fixed_length
-
-    def class_name_for_version(self, version):
-        return self.interface_name + "Ver"+version.of_version
-
-
-    def all_properties(self, skip_pads=True):
-        if 'union' in of_g.unified[self.c_name]:
-            props = []
-            fields = of_g.unified[self.c_name]['union']
-            for field_name in sorted( fields.keys(), key=lambda k: fields[k]['memid']):
-                if field_name in ignore_fields:
-                    continue
-                if skip_pads and field_name.startswith("pad"):
-                    continue
-
-                java_property = JavaProperty.for_field(self, fields[field_name], c_name=field_name)
-                props.append(java_property)
-            return props
-        else:
-            return []
-
-    def all_versions(self):
-        return [ JavaOFVersion(int_version)
-                 for int_version in of_g.unified[self.c_name]
-                 if int_version != 'union' and int_version != 'object_id' ]
-
-    def property_in_version(self, prop, version):
-        if self.version_is_inherited(version):
-            version = self.inherited_from(version)
-
-        if 'members' not in of_g.unified[self.c_name][version.int_version]:
+    def __eq__(self, other):
+        if other is None or type(self) != type(other):
             return False
-        return prop.c_name in (member['name'] for member in of_g.unified[self.c_name][version.int_version]['members'])
+        return (self.name,) == (other.name,)
 
-    def properties_for_version(self, version, skip_pads=True):
-        props = []
-        if self.version_is_inherited(version):
-            version = self.inherited_from(version)
+#######################################################################
+### Enums
+#######################################################################
 
-        for field in of_g.unified[self.c_name][version.int_version]['members']:
-            if field['name'] in ignore_fields:
-                continue
-            if skip_pads and field['name'].startswith("pad"):
-                continue
+class JavaEnum(object):
+    def __init__(self, c_name, entry_version_value_map):
+        self.c_name = c_name
+        self.name   = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
 
-            java_property = JavaProperty.for_field(self, field, c_name=field['name'])
-            props.append(java_property)
-        return props
+        # Port_features has constants that start with digits
+        self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
 
-    def version_is_inherited(self, version):
-        return 'use_version' in of_g.unified[self.c_name][version.int_version]
+        self.entries = [ JavaEnumEntry(self, name, version_value_map)
+                         for (name, version_value_map) in entry_version_value_map.items() ]
+        self.package = "org.openflow.protocol"
 
-    def inherited_from(self, version):
-        return JavaOFVersion(of_g.unified[self.c_name][version.int_version]['use_version'])
-
-    @property
-    def is_virtual(self):
-        return type_maps.class_is_virtual(self.c_name)
-
-    @property
-    def is_extension(self):
-        return type_maps.message_is_extension(self.c_name, -1)
-
-    def wire_type(self, version):
+    @memoize
+    def entry_by_name(self, name):
         try:
-            return py_utils.primary_wire_type(self.c_name, version.int_version)
-        except ValueError, e:
-            return -1
+            return find(self.entries, lambda e: e.name == name)
+        except KeyError:
+            raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
+
+    @memoize
+    def entry_by_c_name(self, name):
+        try:
+            return find(self.entries, lambda e: e.c_name == name)
+        except KeyError:
+            raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
+
+    @memoize
+    def entry_by_version_value(self, version, value):
+        try:
+            return find(self.entries, lambda e: e.values[version] == value if version in e.values else False )
+        except KeyError:
+            raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
+
+# values: Map JavaVersion->Value
+class JavaEnumEntry(object):
+    def __init__(self, enum, name, values):
+        self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
+        self.values = values
+
+    def value(self, version):
+        res = self.version_value_map[version]
+        return res
+
+    @memoize
+    def all_values(self, versions, not_present=None):
+        return [ self.values[version] if version in self.values else not_present for version in versions ]
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
new file mode 100644
index 0000000..819cc68
--- /dev/null
+++ b/java_gen/java_type.py
@@ -0,0 +1,262 @@
+import os
+import errno
+import re
+import subprocess
+import time
+
+def name_c_to_camel(name):
+    """ 'of_stats_reply' -> 'ofStatsReply' """
+    name = re.sub(r'^_','', name)
+    tokens = name.split('_')
+    for i in range(1, len(tokens)):
+            tokens[i] = tokens[i].title()
+    return "".join(tokens)
+
+def name_c_to_caps_camel(name):
+    """ 'of_stats_reply' to 'OFStatsReply' """
+    camel = name_c_to_camel(name.title())
+    if camel.startswith('Of'):
+        return camel.replace('Of','OF',1)
+    else:
+        return camel
+
+
+class JType(object):
+    """ Wrapper class to hold C to Java type conversion information """
+    def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None):
+        self.pub_type = pub_type    # the type we expose externally, e.g. 'U8'
+        if priv_type is None:
+            priv_type = pub_type
+        self.priv_type = priv_type  # the internal storage type
+        self.size = size            # bytes on the wire; None == variable length or hard to calc
+        if read_op is None:
+            read_op = 'ChannelUtils.read%s(bb)' % self.pub_type
+        if write_op is None:
+            write_op = 'ChannelUtils.write%s(bb, $name)'  % self.pub_type
+        self._read_op = read_op
+        self._write_op = write_op
+
+    @property
+    def public_type(self):
+        """ return the public type """
+        return self.pub_type
+
+    def priv(self):
+        """ return the public type """
+        return self.priv_type
+
+    def has_priv(self):
+        """ Is the private type different from the public one?"""
+        return self.pub_type != self.priv_type
+
+    def read_op(self, version=None, length=None):
+        if length is None:
+            length = "length - bb.readerIndex()";
+
+        if callable(self._read_op):
+            return self._read_op(version)
+        else:
+            return self._read_op.replace("$length", str(length))
+
+    def write_op(self, version=None, name=None):
+        if callable(self._write_op):
+            return self._write_op(version, name)
+        else:
+            return self._write_op.replace("$name", str(name))
+
+hello_elem_list = JType("List<OFHelloElement>",
+        read_op = 'ChannelUtils.readHelloElementList(bb)',
+        write_op = 'ChannelUtils.writeHelloElementList(bb)'
+        )
+u8 =  JType('byte',  size=1, read_op='bb.readByte()',
+        write_op='bb.writeByte($name)')
+u8_list =  JType('List<U8>',  size=1, read_op='bb.readByte()',
+        write_op='bb.writeByte($name)')
+u16 = JType('int', 'int', size=2, read_op='U16.f(bb.readShort())',
+        write_op='bb.writeShort(U16.t($name))')
+u32 = JType('int', 'int',   size=4, read_op='bb.readInt()',
+        write_op='bb.writeInt($name)')
+u32_list = JType('List<U32>', 'int[]',   size=4, read_op='bb.readInt()',
+        write_op='bb.writeInt($name)')
+u64 = JType('U64', 'U64', size=8, read_op='U64.of(bb.readLong())',
+        write_op='bb.writeLong($name.getValue())')
+of_port= JType('OFPort',size=None,
+        read_op=lambda version: 'OFPort.ofShort(bb.readShort())' if version.int_version < 2 else 'OFPort.ofInt(bb.readInt())',
+        write_op=lambda version, name: 'bb.writeShort(%s.getShortPortNumber())' % name if version.int_version < 2 else 'bb.writeInt(%s.getPortNumber())' % name)
+one_byte_array = JType('byte[]', size=1,
+        read_op = 'ChannelUtils.readBytes(bb, 1)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+two_byte_array = JType('byte[]', size=2,
+        read_op = 'ChannelUtils.readBytes(bb, 2)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+three_byte_array = JType('byte[]', size=3,
+        read_op = 'ChannelUtils.readBytes(bb, 3)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+four_byte_array = JType('byte[]', size=4,
+        read_op = 'ChannelUtils.readBytes(bb, 4)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+five_byte_array = JType('byte[]', size=5,
+        read_op = 'ChannelUtils.readBytes(bb, 5)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+six_byte_array = JType('byte[]', size=6,
+        read_op = 'ChannelUtils.readBytes(bb, 6)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+seven_byte_array = JType('byte[]', size=7,
+        read_op = 'ChannelUtils.readBytes(bb, 7)',
+        write_op = 'ChannelUtils.writeBytes(bb, $name)')
+actions_list = JType('List<OFAction>', size='ChannelUtils.calcListSize($name)',
+        read_op = 'ChannelUtils.readActionsList(bb, $length)',
+        write_op = 'ChannelUtils.writeActionsList(bb, $name);')
+instructions_list = JType('List<OFInstruction>', size='ChannelUtils.calcListSize($name)',
+        read_op = 'ChannelUtils.readInstructionsList(bb, $length)',
+        write_op = 'ChannelUtils.writeList(bb, $name)')
+buckets_list = JType('List<OFBucket>', size='ChannelUtils.calcListSize($name)',
+        read_op = 'ChannelUtils.readBucketList(bb, $length)',
+        write_op = 'ChannelUtils.writeList(bb, $name)')
+port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtils.calcListSize($name)',
+        read_op = 'ChannelUtils.readPhysicalPortList(bb, $length)',
+        write_op = 'ChannelUtils.writeList(bb, $name)')
+port_desc = JType('OFPortDesc', size='$name.getLength()',
+        read_op = 'null; // TODO OFPortDescVer$version.READER.read(bb)',
+        write_op = '$name.writeTo(bb)')
+packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtils.calcListSize($name)',
+        read_op = 'ChannelUtils.readPacketQueueList(bb, $length)',
+        write_op = 'ChannelUtils.writeList(bb, $name)')
+octets = JType('byte[]', size="$length",
+        read_op = 'ChannelUtils.readBytes(bb, $length)',
+        write_op = 'bb.writeBytes($name)')
+of_match = JType('Match', size="$name.getLength()",
+        read_op = 'ChannelUtils.readOFMatch(bb)',
+        write_op = 'ChannelUtils.writeOFMatch(bb, $name)')
+flow_mod_cmd = JType('OFFlowModCommand', 'short', size="$name.getLength()",
+        read_op = lambda v: "bb.readShort()" if v.int_version == 1 else "bb.readByte()",
+        write_op = lambda v, name: "bb.writeShort(%s)" % name if v.int_version == 1 else "bb.writeByte(%s)" % name)
+mac_addr = JType('MacAddress', 'byte[]', size=6,
+        read_op = 'MacAddress.readFrom(bb)',
+        write_op = '$name.writeTo(bb)')
+port_name = JType('String', size=16,
+        read_op = 'ChannelUtils.readFixedLengthString(bb, 16)',
+        write_op = 'ChannelUtils.writeFixedLengthString(bb, $name, 16)')
+desc_str = JType('String', size=256,
+        read_op = 'ChannelUtils.readFixedLengthString(bb, 256)',
+        write_op = 'ChannelUtils.writeFixedLengthString(bb, $name, 256)')
+serial_num = JType('String', size=32,
+        read_op = 'ChannelUtils.readFixedLengthString(bb, 32)',
+        write_op = 'ChannelUtils.writeFixedLengthString(bb, $name, 32)')
+table_name = JType('String', size=32,
+        read_op = 'ChannelUtils.readFixedLengthString(bb, 32)',
+        write_op = 'ChannelUtils.writeFixedLengthString(bb, $name, 32)')
+ipv4 = JType("IPv4",
+        read_op = "IPv4.readFrom(bb)",
+        write_op = "$name.writeTo(bb)")
+ipv6 = JType("IPv6",
+        read_op = "IPv6.readFrom(bb)",
+        write_op = "$name.writeTo(bb)")
+
+default_mtype_to_jtype_convert_map = {
+        'uint8_t' : u8,
+        'uint16_t' : u16,
+        'uint32_t' : u32,
+        'uint64_t' : u64,
+        'uint8_t[1]' : one_byte_array,
+        'uint8_t[2]' : two_byte_array,
+        'uint8_t[3]' : three_byte_array,
+        'uint8_t[4]' : four_byte_array,
+        'uint8_t[5]' : five_byte_array,
+        'uint8_t[6]' : six_byte_array,
+        'uint8_t[7]' : seven_byte_array,
+        'of_port_no_t' : of_port,
+        'list(of_action_t)' : actions_list,
+        'list(of_instruction_t)' : instructions_list,
+        'list(of_bucket_t)': buckets_list,
+        'list(of_port_desc_t)' : port_desc_list,
+        'list(of_packet_queue_t)' : packet_queue_list,
+        'list(of_uint32_t)' : u32_list,
+        'list(of_uint8_t)' : u8_list,
+        'of_octets_t' : octets,
+        'of_match_t': of_match,
+        'of_fm_cmd_t': flow_mod_cmd,
+        'of_mac_addr_t': mac_addr,
+        'of_port_desc_t': port_desc,
+        'of_desc_str_t': desc_str,
+        'of_serial_num_t': serial_num,
+        'of_port_name_t': port_name,
+        'of_table_name_t': table_name,
+        'of_ipv4_t': ipv4,
+        'of_ipv6_t': ipv6,
+        'of_wc_bmap_t': JType("Wildcards")
+        }
+
+## This is where we drop in special case handling for certain types
+exceptions = {
+        'OFPacketIn': {
+            'data' : octets
+            },
+}
+
+
+def make_standard_list_jtype(c_type):
+    m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
+    if not m:
+        raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
+    base_name = m.group(1)
+    java_base_name = name_c_to_caps_camel(base_name)
+    return JType("List<OF%s>" % java_base_name,
+        read_op = 'ChannelUtils.read%sList(bb)' % java_base_name,
+        write_op = 'ChannelUtils.write%sList(bb, $name)' % java_base_name
+        )
+
+def convert_to_jtype(obj_name, field_name, c_type):
+    """ Convert from a C type ("uint_32") to a java type ("U32")
+    and return a JType object with the size, internal type, and marshalling functions"""
+    if obj_name in exceptions and field_name in exceptions[obj_name]:
+        return exceptions[obj_name][field_name]
+    elif field_name == "type" and c_type == "uint8_t":
+        return JType("OFType", 'byte', size=1, read_op='bb.readByte()',
+        write_op='bb.writeByte($name)')
+    elif field_name == "type" and re.match(r'of_action.*', obj_name):
+        return JType("OFActionType", 'short', size=2, read_op='bb.readShort()',
+        write_op='bb.writeShort($name)')
+    elif field_name == "version" and c_type == "uint8_t":
+        return JType("OFVersion", 'byte', size=1, read_op='bb.readByte()',
+        write_op='bb.writeByte($name)')
+    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):
+        return make_standard_list_jtype(c_type)
+    else:
+        print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
+        jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
+        return JType(jtype)
+
+
+def mkdir_p(path):
+    """ Emulates `mkdir -p` """
+    try:
+        os.makedirs(path)
+    except OSError as exc: # Python >2.5
+        if exc.errno == errno.EEXIST:
+            pass
+        else: raise
+
+def copy_file_with_boiler_plate(src_name, dst_name, with_boiler=True):
+    with open("java_gen/pre-written/%s" % src_name, "r") as src:
+        with open(dst_name, "w") as dst:
+            if with_boiler:
+                print_boiler_plate(os.path.basename(dst_name), dst)
+            dst.writelines(src.readlines())
+
+def frob(s, **kwargs):
+    """ Step through string s and for each key in kwargs,
+         replace $key with kwargs[key] in s.
+    """
+    for k,v in kwargs.iteritems():
+        s = s.replace('$%s' % k, v)
+    return s
+
+def copy_prewrite_tree(basedir):
+    """ 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 - . | ( cd ../../%s && tar xvpf - )" % basedir,
+#            shell=True)
diff --git a/java_gen/java_utils.py b/java_gen/java_utils.py
deleted file mode 100644
index c55b275..0000000
--- a/java_gen/java_utils.py
+++ /dev/null
@@ -1,215 +0,0 @@
-import os
-import errno
-import re
-import subprocess
-import time
-
-def name_c_to_camel(name):
-    """ 'of_stats_reply' -> 'ofStatsReply' """
-    tokens = name.split('_')
-    for i in range(1, len(tokens)):
-            tokens[i] = tokens[i].title()
-    return "".join(tokens)
-
-def name_c_to_caps_camel(name):
-    """ 'of_stats_reply' to 'OFStatsReply' """
-    camel = name_c_to_camel(name.title())
-    if camel.startswith('Of'):
-        return camel.replace('Of','OF',1)
-    else:
-        return camel
-
-
-class JType(object):
-    """ Wrapper class to hold C to Java type conversion information """
-    def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None):
-        self.pub_type = pub_type    # the type we expose externally, e.g. 'U8'
-        if priv_type is None:
-            priv_type = pub_type
-        self.priv_type = priv_type  # the internal storage type
-        self.size = size            # bytes on the wire; None == variable length or hard to calc
-        if read_op is None:
-            read_op = 'ChannelUtils.read%s(this, "$name", bb)' % self.pub_type
-        if write_op is None:
-            write_op = 'ChannelUtils.write($name)'
-        self._read_op = read_op
-        self.write_op = write_op
-
-    @property
-    def public_type(self):
-        """ return the public type """
-        return self.pub_type
-
-    def priv(self):
-        """ return the public type """
-        return self.priv_type
-
-    def has_priv(self):
-        """ Is the private type different from the public one?"""
-        return self.pub_type != self.priv_type
-
-    def read_op(self, version=None):
-        if callable(self._read_op):
-            return self._read_op(version)
-        else:
-            return self._read_op
-
-hello_elem_list = JType("List<OFHelloElement>",
-        read_op = 'ChannelUtils.readHelloElementList(bb)',
-        write_op = 'ChannelUtils.writeHelloElementList(bb)'
-        )
-
-u8 =  JType('byte',  size=1, read_op='bb.readByte()',
-        write_op='bb.writeByte($name)')
-u16 = JType('int', 'int', size=2, read_op='U16.f(bb.readShort())',
-        write_op='bb.writeShort(U16.t($name))')
-u32 = JType('int', 'int',   size=4, read_op='bb.readInt()',
-        write_op='bb.writeInt($name)')
-u64 = JType('U64', 'U64', size=8, read_op='U64.of(bb.readLong())',
-        write_op='bb.writeLong($name.getLong())')
-of_port= JType('OFPort',size=None,
-        read_op=lambda(version): 'OFPort.ofShort(bb.readShort())' if version.int_version < 2 else 'OFPort.ofInt(bb.readInt())',
-        write_op='$name.writeTo(bb)')
-one_byte_array = JType('byte[]', size=1,
-        read_op = 'ChannelUtils.readBytes(bb, 1)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-two_byte_array = JType('byte[]', size=2,
-        read_op = 'ChannelUtils.readBytes(bb, 2)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-three_byte_array = JType('byte[]', size=3,
-        read_op = 'ChannelUtils.readBytes(bb, 3)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-four_byte_array = JType('byte[]', size=4,
-        read_op = 'ChannelUtils.readBytes(bb, 4)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-five_byte_array = JType('byte[]', size=5,
-        read_op = 'ChannelUtils.readBytes(bb, 5)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-six_byte_array = JType('byte[]', size=6,
-        read_op = 'ChannelUtils.readBytes(bb, 6)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-seven_byte_array = JType('byte[]', size=7,
-        read_op = 'ChannelUtils.readBytes(bb, 7)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-actions_list = JType('List<OFAction>', size='ChannelUtils.calcListSize($name)',
-        read_op = 'ChannelUtils.readActionsList(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeList(this, $name)')
-instructions_list = JType('List<OFInstruction>', size='ChannelUtils.calcListSize($name)',
-        read_op = 'ChannelUtils.readInstructionsList(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeList(this, $name)')
-buckets_list = JType('List<OFBucket>', size='ChannelUtils.calcListSize($name)',
-        read_op = 'ChannelUtils.readBucketList(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeList(this, $name)')
-port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtils.calcListSize($name)',
-        read_op = 'ChannelUtils.readPhysicalPortList(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeList(this, $name)')
-port_desc = JType('OFPhysicalPort', size='$name.getLength()',
-        read_op = 'ChannelUtils.readPhysicalPort(bb)',
-        write_op = 'ChannelUtils.write(this, $name)')
-packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtils.calcListSize($name)',
-        read_op = 'ChannelUtils.readPacketQueueList(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeList(this, $name)')
-octets = JType('byte[]', size="length - MINIMUM_LENGTH",
-        read_op = 'ChannelUtils.readBytes(bb, length - MINIMUM_LENGTH)',
-        write_op = 'ChannelUtils.writeBytes(bb, this.$name)')
-of_match = JType('Match', size="$name.getLength()",
-        read_op = 'ChannelUtils.readOFMatch(bb)',
-        write_op = 'ChannelUtils.writeOFMatch(this, $name)')
-flow_mod_cmd = JType('OFFlowModCmd', size="$name.getLength()",
-        read_op = 'ChannelUtils.readOFFlowModCmd(bb)',
-        write_op = 'ChannelUtils.writeOFFlowModCmd(this, $name)')
-mac_addr = JType('MacAddress', 'byte[]', size=6,
-        read_op = 'MacAddress.readFrom(bb)',
-        write_op = 'ChannelUtils.writeBytes(bb, $name)')
-bsn_interface_list = JType("List<OFBsnInterface>",
-        read_op = 'ChannelUtils.readBsnInterfaceList(bb)',
-        write_op = 'ChannelUtils.writeBsnInterfaceList(bb)'
-        )
-meter_band_list = JType("List<OFMeterBand>",
-        read_op = 'ChannelUtils.readMeterBandList(bb)',
-        write_op = 'ChannelUtils.writeMeterBandList(bb, $name)'
-        )
-
-
-
-
-
-default_mtype_to_jtype_convert_map = {
-        'uint8_t' : u8,
-        'uint16_t' : u16,
-        'uint32_t' : u32,
-        'uint64_t' : u64,
-        'uint8_t[1]' : one_byte_array,
-        'uint8_t[2]' : two_byte_array,
-        'uint8_t[3]' : three_byte_array,
-        'uint8_t[4]' : four_byte_array,
-        'uint8_t[5]' : five_byte_array,
-        'uint8_t[6]' : six_byte_array,
-        'uint8_t[7]' : seven_byte_array,
-        'of_port_no_t' : of_port,
-        'of_list_action_t' : actions_list,
-        'of_list_instruction_t' : instructions_list,
-        'of_list_bucket_t': buckets_list,
-        'of_list_port_desc_t' : port_desc_list,
-        'of_list_packet_queue_t' : packet_queue_list,
-        'of_octets_t' : octets,
-        'of_match_t': of_match,
-        'of_fm_cmd_t': flow_mod_cmd,
-        'of_mac_addr_t': mac_addr,
-        'of_port_desc_t': port_desc,
-        'of_list_bsn_interface_t': bsn_interface_list,
-        'of_list_hello_elem_t': hello_elem_list,
-        'of_list_meter_band_t': meter_band_list
-        }
-
-## This is where we drop in special case handling for certain types
-exceptions = {
-        'OFPacketIn': {
-            'data' : octets
-            },
-        }
-
-
-def convert_to_jtype(obj_name, field_name, c_type):
-    """ Convert from a C type ("uint_32") to a java type ("U32")
-    and return a JType object with the size, internal type, and marshalling functions"""
-    if obj_name in exceptions and field_name in exceptions[obj_name]:
-        return exceptions[obj_name][field_name]
-    elif c_type in default_mtype_to_jtype_convert_map:
-        return default_mtype_to_jtype_convert_map[c_type]
-    else:
-        print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
-        jtype = name_c_to_caps_camel(c_type)      # not sure... try to fake it
-        return JType(jtype)
-
-
-def mkdir_p(path):
-    """ Emulates `mkdir -p` """
-    try:
-        os.makedirs(path)
-    except OSError as exc: # Python >2.5
-        if exc.errno == errno.EEXIST:
-            pass
-        else: raise
-
-def copy_file_with_boiler_plate(src_name, dst_name, with_boiler=True):
-    with open("java_gen/pre-written/%s" % src_name, "r") as src:
-        with open(dst_name, "w") as dst:
-            if with_boiler:
-                print_boiler_plate(os.path.basename(dst_name), dst)
-            dst.writelines(src.readlines())
-
-def frob(s, **kwargs):
-    """ Step through string s and for each key in kwargs,
-         replace $key with kwargs[key] in s.
-    """
-    for k,v in kwargs.iteritems():
-        s = s.replace('$%s' % k, v)
-    return s
-
-def copy_prewrite_tree(basedir):
-    """ 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 - . | ( cd ../../%s && tar xvpf - )" % basedir,
-#            shell=True)
diff --git a/java_gen/msgs.py b/java_gen/msgs.py
deleted file mode 100644
index 3cdef2c..0000000
--- a/java_gen/msgs.py
+++ /dev/null
@@ -1,55 +0,0 @@
-import of_g
-import os
-import pdb
-import re
-
-import loxi_front_end.type_maps as type_maps
-import loxi_utils.loxi_utils as utils
-import py_gen.util as py_utils
-
-import java_gen.java_utils as java_utils
-from java_gen.java_model import *
-ignore_fields = ['version', 'xid', 'length', 'type' ]
-
-protected_fields = ['version', 'length']
-
-
-templates_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
-
-def render_template(out, name, **context):
-    prefix = '//::(?=[ \t]|$)'
-    utils.render_template(out, name, [templates_dir], context, prefix=prefix)
-
-def create_message_interfaces(message_names, basedir):
-    """ Create the base interfaces for OFMessages"""
-    for msg_name in message_names:
-        msg = JavaOFMessage(msg_name)
-
-        filename = os.path.join(basedir, "%s.java" % msg.interface_name)
-        dirname = os.path.dirname(filename)
-        if not os.path.exists(dirname):
-            os.makedirs(dirname)
-
-        with open(filename, "w") as f:
-            render_template(f, "message_interface.java", msg=msg)
-
-def create_of_type_enum(message_names, basedir):
-    all_versions = [ JavaOFVersion(v) for v in of_g.target_version_list ]
-    messages =  sorted(filter(lambda msg: not msg.is_virtual and not msg.is_extension, [ JavaOFMessage(msg_name) for msg_name in message_names ]), key=lambda msg: msg.wire_type(all_versions[-1]))
-    filename = os.path.join(basedir, "../types/OFType.java")
-    dirname = os.path.dirname(filename)
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-    with open(filename, "w") as f:
-        render_template(f, "of_type.java", all_messages=messages, all_versions = all_versions)
-
-def create_message_by_version(message_names, basedir):
-    """ Create the OF Messages for each version that implement the above interfaces"""
-    for msg_name in message_names:
-        msg = JavaOFMessage(msg_name)
-
-        for version in msg.all_versions():
-            filename = os.path.join(basedir, "%s.java" % msg.class_name_for_version(version))
-            with open(filename, "w") as f:
-                   render_template(f, "message_class.java", msg=msg, version=version,
-                            impl_class=msg.class_name_for_version(version))
diff --git a/java_gen/pre-written/.classpath b/java_gen/pre-written/.classpath
new file mode 100644
index 0000000..b6bc6ad
--- /dev/null
+++ b/java_gen/pre-written/.classpath
@@ -0,0 +1,7 @@
+<?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
new file mode 100644
index 0000000..b347bd6
--- /dev/null
+++ b/java_gen/pre-written/.project
@@ -0,0 +1,17 @@
+<?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/build.xml b/java_gen/pre-written/build.xml
new file mode 100644
index 0000000..f66d8bc
--- /dev/null
+++ b/java_gen/pre-written/build.xml
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+
+ <!--
+   Copyright 2011, Big Switch Networks, Inc.
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!--
+    The build uses pregenerated Thrift code by default to reduce build
+    dependencies. To generate it locally run the gen-thrift target.
+    If you change the Thrift files be sure to also commit the updated
+    generated code.
+-->
+
+<project default="dist" name="Floodlight">
+    <property name="target" location="target"/>
+    <property name="build" location="${target}/bin"/>
+    <property name="build-test" location="${target}/bin-test"/>
+    <property name="build-coverage" location="${target}/bin-coverage"/>
+    <property name="test-output" location="${target}/test"/>
+    <property name="coverage-output" location="${target}/coverage"/>
+    <property name="source" location="src/main/java"/>
+    <property name="resources" location="src/main/resources/"/>
+    <property name="source-test" location="src/test/java"/>
+    <property name="python-src" location="src/main/python"/>
+    <property name="docs" location="${target}/docs"/>
+    <property name="main-class" value="net.floodlightcontroller.core.Main"/>
+    <property name="floodlight-jar" location="${target}/floodlight.jar"/>
+    <property name="floodlight-test-jar" location="${target}/floodlight-test.jar"/>
+    <property name="thrift.dir" value="${basedir}/src/main/thrift"/>
+    <property name="thrift.out.dir" value="lib/gen-java"/>
+    <property name="thrift.package" value="net/floodlightcontroller/packetstreamer/thrift"/>
+    <property name="ant.build.javac.source" value="1.6"/>
+    <property name="ant.build.javac.target" value="1.6"/>
+    <property name="lib" location="lib"/>
+
+    <patternset id="lib">
+        <include name="netty-3.2.6.Final.jar"/>
+    </patternset>
+
+    <path id="classpath">
+        <fileset dir="${lib}">
+            <patternset refid="lib"/>
+        </fileset>
+    </path>
+
+    <patternset id="lib-cobertura">
+        <include name="cobertura-1.9.4.1.jar"/>
+        <include name="asm-3.0.jar"/>
+        <include name="asm-tree-3.0.jar"/>
+        <include name="oro/jakarta-oro-2.0.8.jar"/>
+        <include name="log4j-1.2.9.jar"/>
+    </patternset>
+    <path id="classpath-cobertura">
+        <fileset dir="${lib}">
+            <patternset refid="lib-cobertura"/>
+    </fileset>
+    </path>
+
+    <patternset id="lib-test">
+        <include name="junit-4.8.2.jar"/>
+        <include name="org.easymock-3.1.jar"/>
+        <include name="objenesis-1.2.jar"/>  <!-- required by easymock to mock classes -->
+        <include name="cglib-nodep-2.2.2.jar"/>    <!-- required by easymock to mock classes -->
+    </patternset>
+    <path id="classpath-test">
+        <fileset dir="${lib}">
+            <patternset refid="lib-test"/>
+            <patternset refid="lib-cobertura"/>
+            <patternset refid="lib"/>
+        </fileset>
+    </path>
+
+    <target name="init">
+        <mkdir dir="${build}"/>
+        <mkdir dir="${build-test}"/>
+        <mkdir dir="${target}/lib"/>
+        <mkdir dir="${thrift.out.dir}"/>
+        <mkdir dir="${test-output}"/>
+    </target>
+
+    <target name="compile" depends="init">
+        <javac includeAntRuntime="false"
+           classpathref="classpath"
+           debug="true"
+           srcdir="${source}:${thrift.out.dir}"
+           destdir="${build}">
+        </javac>
+    </target>
+
+    <target name="compile-tests" depends="compile-test"/>
+    <target name="compile-test" depends="compile">
+        <fileset dir="${resources}"/>
+        <javac includeAntRuntime="false" debug="true"
+           srcdir="${source-test}"
+           classpath="${build}"
+           classpathref="classpath-test"
+           destdir="${build-test}"/>
+    </target>
+
+    <!-- Thrift build based on http://www.flester.com/blog/2009/04/26/using-thrift-from-ant -->
+    <fileset id="thrift.files" dir="${thrift.dir}">
+        <include name="**/*.thrift"/>
+    </fileset>
+
+    <target name="gen-thrift" depends="init">
+        <pathconvert property="thrift.file.list" refid="thrift.files"
+            pathsep=" " dirsep="/">
+        </pathconvert>
+        <echo message="Running thrift generator on ${thrift.file.list}"/>
+        <exec executable="thrift" dir="${basedir}" failonerror="true">
+            <arg line="--strict -v --gen java -o ${thrift.out.dir}/.. ${thrift.file.list}"/>
+        </exec>
+        <!-- Get rid of annoying warnings in thrift java: at annotations -->
+        <echo message="Adding @SuppressWarning annotations"/>
+        <replaceregexp byline="true">
+            <regexp pattern="^public "/>
+            <substitution expression='@SuppressWarnings("all") public '/>
+            <fileset id="thrift.output.files" dir="${thrift.out.dir}/..">
+                <include name="**/*.java"/>
+            </fileset>
+        </replaceregexp>
+    </target>
+
+    <target name="clean">
+        <delete dir="${target}"/>
+    </target>
+
+    <target name="run" depends="dist">
+        <java fork="true" jar="${floodlight-jar}" classpathref="classpath">
+            <jvmarg value="-server"/>
+            <jvmarg value="-Xms1024M"/>
+            <jvmarg value="-Xmx1024M"/>
+        </java>
+    </target>
+
+    <target name="tests" depends="test"/>
+    <target name="test" depends="compile-test">
+        <junit fork="true" forkmode="once"
+           failureproperty="junit.failure"
+           printsummary="on">
+        <sysproperty key="net.sourceforge.cobertura.datafile"
+             file="${target}/cobertura.ser" />
+            <classpath>
+                <pathelement location="${build-coverage}"/>
+                <pathelement location="${build}"/>
+                <pathelement location="${build-test}"/>
+                <pathelement location="${floodlight-jar}"/>
+                <path refid="classpath-test"/>
+            </classpath>
+            <formatter type="brief" usefile="true" />
+            <batchtest todir="${test-output}">
+                <fileset dir="${source-test}">
+                    <exclude name="**/storage/tests/StorageTest.java"/>
+                    <exclude name="**/test/Mock*"/>
+                    <exclude name="**/core/test/**"/>
+                    <exclude name="**/core/module/**"/>
+                </fileset>
+            </batchtest>
+        </junit>
+        <fail if="junit.failure" message="Unit test(s) failed.  See reports!"/>
+    </target>
+
+    <taskdef classpathref="classpath-cobertura" resource="tasks.properties"/>
+    <target name="clean-instrument">
+        <delete file="${target}/cobertura.ser"/>
+        <delete dir="${build-coverage}"/>
+    </target>
+    <target name="instrument" depends="compile,compile-test,clean-instrument">
+      <cobertura-instrument datafile="${target}/cobertura.ser"
+                todir="${build-coverage}"
+                classpathref="classpath-cobertura">
+    <fileset dir="${build}">
+      <include name="**/*.class"/>
+    </fileset>
+      </cobertura-instrument>
+    </target>
+    <target name="coverage-report">
+        <cobertura-report format="html"
+              datafile="${target}/cobertura.ser"
+              destdir="${coverage-output}"
+              srcdir="${source}"/>
+        <cobertura-report format="xml"
+              datafile="${target}/cobertura.ser"
+              destdir="${coverage-output}"
+              srcdir="${source}"/>
+    </target>
+    <target name="coverage" depends="instrument,test,coverage-report"/>
+
+    <target name="dist" depends="compile,compile-test">
+        <jar destfile="${floodlight-jar}" filesetmanifest="mergewithoutmain">
+            <manifest>
+                <attribute name="Main-Class" value="${main-class}"/>
+                <attribute name="Class-Path" value="."/>
+            </manifest>
+            <fileset dir="${build}"/>
+            <fileset dir="${resources}"/>
+            <fileset dir="${python-src}">
+                <include name="**/*.py"/>
+            </fileset>
+            <zipgroupfileset dir="${lib}">
+                <patternset refid="lib"/>
+            </zipgroupfileset>
+        </jar>
+        <jar destfile="${floodlight-test-jar}" filesetmanifest="mergewithoutmain">
+            <manifest>
+                <attribute name="Class-Path" value="."/>
+            </manifest>
+            <fileset dir="${build-test}"/>
+            <fileset dir="${resources}"/>
+            <zipgroupfileset dir="${lib}">
+                <patternset refid="lib-test"/>
+                <patternset refid="lib-cobertura"/>
+            </zipgroupfileset>
+        </jar>
+    </target>
+
+    <target name="javadoc">
+        <javadoc access="protected"
+            author="true"
+            classpathref="classpath"
+            destdir="${docs}"
+            doctitle="Floodlight"
+            nodeprecated="false"
+            nodeprecatedlist="false"
+            noindex="false"
+            nonavbar="false"
+            notree="false"
+            source="1.6"
+            sourcepath="${source}"
+            splitindex="true"
+            use="true"
+            version="true"/>
+    </target>
+
+    <target name="eclipse" depends="init">
+        <pathconvert property="eclipse-lib">
+            <map from="${basedir}/" to=""/>
+            <fileset dir="${lib}">
+                <patternset refid="lib"/>
+                <patternset refid="lib-test"/>
+            </fileset>
+        </pathconvert>
+        <exec executable="${basedir}/setup-eclipse.sh">
+            <arg value="${main-class}"/>
+            <arg value="${eclipse-lib}"/>
+        </exec>
+    </target>
+
+</project>
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFAbstractMessage.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFAbstractMessage.java
deleted file mode 100644
index bc2218f..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFAbstractMessage.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Copyright 2013, Big Switch Networks, Inc.
- *
- * LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
- * the following special exception:
- *
- * LOXI Exception
- *
- * As a special exception to the terms of the EPL, you may distribute libraries
- * generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
- * that copyright and licensing notices generated by LoxiGen are not altered or removed
- * from the LoxiGen Libraries and the notice provided below is (i) included in
- * the LoxiGen Libraries, if distributed in source code form and (ii) included in any
- * documentation for the LoxiGen Libraries, if distributed in binary form.
- *
- * Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
- *
- * You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
- * a copy of the EPL at:
- *
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * EPL for the specific language governing permissions and limitations
- * under the EPL.
- */
-package org.openflow.protocol;
-
-/**
- * The base interface for all OpenFlow message objects
- */
-
-import org.openflow.types.OFType;
-
-abstract public class OFAbstractMessage implements OFObject {
-    private final OFVersion version;
-    private final OFType type;
-    private int xid;
-
-    public static int MINIMUM_SIZE = 8;
-
-    public OFAbstractMessage(final OFVersion version, final OFType type) {
-        this.version = version;
-        this.type = type;
-    }
-
-    /**
-     * Return the wire format version of this message, e.g., 0x01
-     */
-    OFVersion getVersion() {
-        return version;
-    }
-
-    /**
-     * @return the transction ID for this message
-     */
-    int getXid() {
-        return xid;
-    }
-
-    /**
-     * @param newXid
-     *            Set this transaction ID for this message
-     */
-    void setXid(final int xid) {
-        this.xid = xid;
-    }
-
-    /**
-     * The type that is returned here is agnostic to the underlying wire format
-     *
-     * @return the type of OpenFlow message.
-     */
-    OFType getType() {
-        return type;
-    }
-
-    @Override
-    public int getLength() {
-        return MINIMUM_SIZE;
-    }
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFBsnVportQInQT.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFBsnVportQInQT.java
new file mode 100644
index 0000000..c5b884e
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFBsnVportQInQT.java
@@ -0,0 +1,5 @@
+package org.openflow.protocol;
+
+public class OFBsnVportQInQT {
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMatchBmap.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMatchBmap.java
new file mode 100644
index 0000000..6e4dc5b
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMatchBmap.java
@@ -0,0 +1,5 @@
+package org.openflow.protocol;
+
+public class OFMatchBmap {
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java
index 4f31741..c1e4456 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessage.java
@@ -1,13 +1,13 @@
 package org.openflow.protocol;
 
-import org.openflow.types.OFType;
-
 public interface OFMessage {
     int getXid();
 
-    boolean isXidSet();
-
     OFType getType();
 
     OFVersion getVersion();
+
+    interface Builder {
+
+    }
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageReader.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageReader.java
index 24c3314..3f34d9b 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageReader.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageReader.java
@@ -3,6 +3,6 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.exceptions.OFParseError;
 
-public interface OFMessageReader<T extends OFMessage> {
+public interface OFMessageReader<T> {
     T readFrom(ChannelBuffer bb) throws OFParseError;
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java
new file mode 100644
index 0000000..84e5507
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFMessageWriter.java
@@ -0,0 +1,8 @@
+package org.openflow.protocol;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+
+public interface OFMessageWriter<T> {
+    public int write(ChannelBuffer bb, T message) throws OFParseError;
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
index 21a4607..4a7557f 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFObject.java
@@ -1,5 +1,7 @@
 package org.openflow.protocol;
 
+import org.jboss.netty.buffer.ChannelBuffer;
+
 /**
  *  Base interface of all OpenFlow objects (e.g., messages, actions, stats, etc.)
  *
@@ -10,26 +12,8 @@
  *  malformed packets, for example, for negative testing.
  */
 
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.exceptions.OFParseError;
-import org.openflow.exceptions.OFShortWrite;
 
 public interface OFObject {
-    /**
-     * Return a number equal or greater than zero (and currently in OF less than
-     * 65536)
-     *
-     * @return the number of bytes this object will represent on the wire
-     */
-    public int getLength();
-
-    /**
-     * Automatically calculate any lengths and write an openflow object into the
-     * byte buffer.
-     *
-     * @param bb
-     *            A valid byte buffer with sufficient capacity to hold this
-     *            object/
-     */
-    public void writeTo(ChannelBuffer bb) throws OFParseError, OFShortWrite;
+    void writeTo(ChannelBuffer bb);
+    int getLength();
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFTableFeature.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFTableFeature.java
new file mode 100644
index 0000000..114f638
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFTableFeature.java
@@ -0,0 +1,5 @@
+package org.openflow.protocol;
+
+public class OFTableFeature {
+    // FIXME implement
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFVersion.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFVersion.java
index afc0393..7241647 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFVersion.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFVersion.java
@@ -3,7 +3,7 @@
 public enum OFVersion {
     OF_10(1), OF_11(2), OF_12(3), OF_13(4);
 
-    private final int wireVersion;
+    public final int wireVersion;
 
     OFVersion(final int wireVersion) {
         this.wireVersion = wireVersion;
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java
new file mode 100644
index 0000000..25b2c21
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/Wildcards.java
@@ -0,0 +1,5 @@
+package org.openflow.protocol;
+
+public class Wildcards {
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/XidGenerator.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/XidGenerator.java
new file mode 100644
index 0000000..0819ac2
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/XidGenerator.java
@@ -0,0 +1,5 @@
+package org.openflow.protocol;
+
+public interface XidGenerator {
+    int nextXid();
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/actions/OFAction.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/actions/OFAction.java
deleted file mode 100644
index f01f8fe..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/actions/OFAction.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.openflow.protocol.actions;
-
-import org.openflow.protocol.OFObject;
-
-public interface OFAction extends OFObject {
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/instructions/OFInstruction.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/instructions/OFInstruction.java
deleted file mode 100644
index 8af305c..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/instructions/OFInstruction.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.openflow.protocol.instructions;
-
-import org.openflow.protocol.OFObject;
-
-public interface OFInstruction extends OFObject {
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java
index 19ced8f..f00e1b4 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/MatchBuilderVer10.java
@@ -1,8 +1,6 @@
 package org.openflow.protocol.match;
 
 import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.exceptions.OFParseError;
-import org.openflow.exceptions.OFShortWrite;
 import org.openflow.protocol.types.IpDscp;
 import org.openflow.types.EthType;
 import org.openflow.types.IPv4;
@@ -157,7 +155,7 @@
     }
 
     @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
+    public void writeTo(final ChannelBuffer bb) {
         // TODO Auto-generated method stub
 
     }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/IPv4.java b/java_gen/pre-written/src/main/java/org/openflow/types/IPv4.java
index b4eb8cf..aab6dc2 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/IPv4.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/IPv4.java
@@ -3,7 +3,6 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.exceptions.OFParseError;
 import org.openflow.exceptions.OFShortRead;
-import org.openflow.exceptions.OFShortWrite;
 import org.openflow.protocol.OFObject;
 
 /**
@@ -90,7 +89,7 @@
     }
 
     @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
+    public void writeTo(final ChannelBuffer bb) {
         bb.writeInt(rawValue);
     }
 
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/IPv6.java b/java_gen/pre-written/src/main/java/org/openflow/types/IPv6.java
index 5f51665..f499eac 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/IPv6.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/IPv6.java
@@ -5,7 +5,6 @@
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.exceptions.OFParseError;
 import org.openflow.exceptions.OFShortRead;
-import org.openflow.exceptions.OFShortWrite;
 import org.openflow.protocol.OFObject;
 
 /**
@@ -166,7 +165,7 @@
     }
 
     @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
+    public void writeTo(final ChannelBuffer bb) {
         bb.writeLong(raw1);
         bb.writeLong(raw2);
     }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/MacAddress.java b/java_gen/pre-written/src/main/java/org/openflow/types/MacAddress.java
index 4ce19ab..8806bb3 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/MacAddress.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/MacAddress.java
@@ -2,7 +2,6 @@
 
 import org.jboss.netty.buffer.ChannelBuffer;
 import org.openflow.exceptions.OFParseError;
-import org.openflow.exceptions.OFShortWrite;
 import org.openflow.protocol.OFObject;
 import org.openflow.util.HexString;
 
@@ -84,7 +83,7 @@
     }
 
     @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
+    public void writeTo(final ChannelBuffer bb) {
         bb.writeInt((int) (rawValue >> 16));
         bb.writeShort((int) rawValue & 0xFFFF);
     }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFBsnInterface.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFBsnInterface.java
deleted file mode 100644
index d0afb56..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFBsnInterface.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.openflow.types;
-
-public interface OFBsnInterface {
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFBucket.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFBucket.java
deleted file mode 100644
index 47b403b..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFBucket.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.openflow.types;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.exceptions.OFParseError;
-import org.openflow.exceptions.OFShortWrite;
-import org.openflow.protocol.OFObject;
-
-public class OFBucket implements OFObject {
-
-    @Override
-    public int getLength() {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
-        // TODO Auto-generated method stub
-
-    }
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFPacketQueue.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFPacketQueue.java
deleted file mode 100644
index d74906f..0000000
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFPacketQueue.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.openflow.types;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.exceptions.OFParseError;
-import org.openflow.exceptions.OFShortWrite;
-import org.openflow.protocol.OFObject;
-
-public class OFPacketQueue implements OFObject {
-
-    @Override
-    public int getLength() {
-        // TODO Auto-generated method stub
-        return 0;
-    }
-
-    @Override
-    public void writeTo(final ChannelBuffer bb) throws OFParseError, OFShortWrite {
-        // TODO Auto-generated method stub
-
-    }
-
-}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java b/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
index e8eeebd..dab6ff2 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/util/ChannelUtils.java
@@ -3,17 +3,32 @@
 import java.util.List;
 
 import org.jboss.netty.buffer.ChannelBuffer;
-import org.openflow.protocol.actions.OFAction;
-import org.openflow.protocol.instructions.OFInstruction;
+import org.openflow.protocol.OFBsnInterface;
+import org.openflow.protocol.OFBsnVportQInQ;
+import org.openflow.protocol.OFBsnVportQInQT;
+import org.openflow.protocol.OFBucket;
+import org.openflow.protocol.OFFlowStatsEntry;
+import org.openflow.protocol.OFGroupDescStatsEntry;
+import org.openflow.protocol.OFGroupStatsEntry;
+import org.openflow.protocol.OFHelloElem;
+import org.openflow.protocol.OFMeterFeatures;
+import org.openflow.protocol.OFMeterStats;
+import org.openflow.protocol.OFPacketQueue;
+import org.openflow.protocol.OFPortStatsEntry;
+import org.openflow.protocol.OFQueueStatsEntry;
+import org.openflow.protocol.OFTableFeature;
+import org.openflow.protocol.OFTableFeatures;
+import org.openflow.protocol.OFTableStatsEntry;
+import org.openflow.protocol.action.OFAction;
+import org.openflow.protocol.instruction.OFInstruction;
 import org.openflow.protocol.match.Match;
-import org.openflow.types.OFBsnInterface;
-import org.openflow.types.OFBucket;
 import org.openflow.types.OFFlowModCmd;
 import org.openflow.types.OFHelloElement;
 import org.openflow.types.OFMeterBand;
-import org.openflow.types.OFPacketQueue;
 import org.openflow.types.OFPhysicalPort;
 
+import com.google.common.base.Charsets;
+
 /**
  * Collection of helper functions for reading and writing into ChannelBuffers
  *
@@ -90,4 +105,212 @@
         return null;
     }
 
+    public static void writeOFMatch(ChannelBuffer bb, Match match) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeList(ChannelBuffer bb, List<?> ports) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeOFFlowModCmd(ChannelBuffer bb, OFFlowModCmd command) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static String readFixedLengthString(ChannelBuffer bb, int length) {
+        byte[] dst = new byte[length];
+        bb.readBytes(dst, 0, length);
+        return new String(dst, Charsets.US_ASCII);
+    }
+
+    public static void writeFixedLengthString(ChannelBuffer bb, String string, int length) {
+        int l = string.length();
+        if(l > length) {
+            throw new IllegalArgumentException("Error writing string: length="+l+" > max Length="+length);
+        }
+        bb.writeBytes(string.getBytes(Charsets.US_ASCII));
+        if(l < length) {
+            bb.writeZero(length - l);
+        }
+    }
+
+    public static void writeBsnInterfaceList(ChannelBuffer bb, List<OFBsnInterface> interfaces) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeTableFeatureList(ChannelBuffer bb,
+            List<OFTableFeature> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeBsnInterface(ChannelBuffer bb,
+            List<OFBsnInterface> interfaces) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeFlowStatsEntry(ChannelBuffer bb,
+            List<OFFlowStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFFlowStatsEntry> readFlowStatsEntry(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeTableStatsEntryList(ChannelBuffer bb,
+            List<OFTableStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFTableStatsEntry> readTableStatsEntryList(
+            ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static List<OFFlowStatsEntry> readFlowStatsEntryList(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeFlowStatsEntryList(ChannelBuffer bb,
+            List<OFFlowStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeGroupDescStatsEntryList(ChannelBuffer bb,
+            List<OFGroupDescStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFGroupDescStatsEntry> readGroupDescStatsEntryList(
+            ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeOFBsnVportQInQT(ChannelBuffer bb,
+            OFBsnVportQInQT vport) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void writeMeterBandList(ChannelBuffer bb,
+            List<OFMeterBand> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static int writeActionsList(ChannelBuffer bb, List<OFAction> actions) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    public static OFBsnVportQInQ readOFBsnVportQInQ(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writePortStatsEntryList(ChannelBuffer bb,
+            List<OFPortStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static void write(ChannelBuffer bb, OFPhysicalPort desc) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFPortStatsEntry> readPortStatsEntryList(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeOFBsnVportQInQ(ChannelBuffer bb,
+            OFBsnVportQInQ vport) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFHelloElem> readHelloElemList(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeHelloElemList(ChannelBuffer bb,
+            List<OFHelloElem> elements) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFGroupStatsEntry> readGroupStatsEntryList(
+            ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeGroupStatsEntryList(ChannelBuffer bb,
+            List<OFGroupStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFQueueStatsEntry> readQueueStatsEntryList(
+            ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeQueueStatsEntryList(ChannelBuffer bb,
+            List<OFQueueStatsEntry> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static OFMeterFeatures readOFMeterFeatures(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeOFMeterFeatures(ChannelBuffer bb,
+            OFMeterFeatures features) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFMeterStats> readMeterStatsList(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeMeterStatsList(ChannelBuffer bb,
+            List<OFMeterStats> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public static List<OFTableFeatures> readTableFeaturesList(ChannelBuffer bb) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static void writeTableFeaturesList(ChannelBuffer bb,
+            List<OFTableFeatures> entries) {
+        // TODO Auto-generated method stub
+
+    }
+
+
 }
diff --git a/java_gen/pre-written/src/main/java/org/openflow/util/LengthCountingPseudoChannelBuffer.java b/java_gen/pre-written/src/main/java/org/openflow/util/LengthCountingPseudoChannelBuffer.java
new file mode 100644
index 0000000..bd0adce
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/util/LengthCountingPseudoChannelBuffer.java
@@ -0,0 +1,673 @@
+package org.openflow.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.GatheringByteChannel;
+import java.nio.channels.ScatteringByteChannel;
+import java.nio.charset.Charset;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBufferFactory;
+import org.jboss.netty.buffer.ChannelBufferIndexFinder;
+
+public class LengthCountingPseudoChannelBuffer implements ChannelBuffer {
+
+    int writerIndex = 0;
+    private int markedWriterIndex;
+
+    @Override
+    public ChannelBufferFactory factory() {
+        return null;
+    }
+
+    @Override
+    public int capacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    @Override
+    public ByteOrder order() {
+        return ByteOrder.BIG_ENDIAN;
+    }
+
+    @Override
+    public boolean isDirect() {
+        return true;
+    }
+
+    @Override
+    public int readerIndex() {
+        return 0;
+    }
+
+    @Override
+    public void readerIndex(int readerIndex) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int writerIndex() {
+        return writerIndex;
+    }
+
+    @Override
+    public void writerIndex(int writerIndex) {
+        this.writerIndex = writerIndex;
+    }
+
+    @Override
+    public void setIndex(int readerIndex, int writerIndex) {
+        if(readerIndex != 0)
+            throw new UnsupportedOperationException();
+        this.writerIndex = writerIndex;
+    }
+
+    @Override
+    public int readableBytes() {
+        return writerIndex;
+    }
+
+    @Override
+    public int writableBytes() {
+        return Integer.MAX_VALUE - writerIndex;
+    }
+
+    @Override
+    public boolean readable() {
+        return writerIndex > 0;
+    }
+
+    @Override
+    public boolean writable() {
+        return writerIndex < Integer.MAX_VALUE;
+    }
+
+    @Override
+    public void clear() {
+        writerIndex = 0;
+
+    }
+
+    @Override
+    public void markReaderIndex() {
+    }
+
+    @Override
+    public void resetReaderIndex() {
+    }
+
+    @Override
+    public void markWriterIndex() {
+        markedWriterIndex = writerIndex;
+    }
+
+    @Override
+    public void resetWriterIndex() {
+        writerIndex = markedWriterIndex;
+    }
+
+    @Override
+    public void discardReadBytes() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void ensureWritableBytes(int writableBytes) {
+        if(!((Integer.MAX_VALUE - writableBytes) > writerIndex))
+            throw new IllegalStateException();
+    }
+
+    @Override
+    public byte getByte(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public short getUnsignedByte(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public short getShort(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getUnsignedShort(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getMedium(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getUnsignedMedium(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getInt(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getUnsignedInt(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long getLong(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public char getChar(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public float getFloat(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public double getDouble(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, ChannelBuffer dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, ChannelBuffer dst, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, byte[] dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, byte[] dst, int dstIndex, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, ByteBuffer dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getBytes(int index, OutputStream out, int length)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getBytes(int index, GatheringByteChannel out, int length)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setByte(int index, int value) {
+    }
+
+    @Override
+    public void setShort(int index, int value) {
+    }
+
+    @Override
+    public void setMedium(int index, int value) {
+    }
+
+    @Override
+    public void setInt(int index, int value) {
+    }
+
+    @Override
+    public void setLong(int index, long value) {
+    }
+
+    @Override
+    public void setChar(int index, int value) {
+    }
+
+    @Override
+    public void setFloat(int index, float value) {
+    }
+
+    @Override
+    public void setDouble(int index, double value) {
+    }
+
+    @Override
+    public void setBytes(int index, ChannelBuffer src) {
+    }
+
+    @Override
+    public void setBytes(int index, ChannelBuffer src, int length) {
+    }
+
+    @Override
+    public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
+    }
+
+    @Override
+    public void setBytes(int index, byte[] src) {
+    }
+
+    @Override
+    public void setBytes(int index, byte[] src, int srcIndex, int length) {
+    }
+
+    @Override
+    public void setBytes(int index, ByteBuffer src) {
+
+    }
+
+    @Override
+    public int setBytes(int index, InputStream in, int length)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int setBytes(int index, ScatteringByteChannel in, int length)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setZero(int index, int length) {
+    }
+
+    @Override
+    public byte readByte() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public short readUnsignedByte() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public short readShort() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readUnsignedShort() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readMedium() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readUnsignedMedium() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readInt() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long readUnsignedInt() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public long readLong() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public char readChar() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public float readFloat() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public double readDouble() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer readBytes(int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @Deprecated
+    public ChannelBuffer readBytes(ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer readSlice(int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @Deprecated
+    public
+    ChannelBuffer readSlice(ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(ChannelBuffer dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(ChannelBuffer dst, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(ChannelBuffer dst, int dstIndex, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(byte[] dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(byte[] dst, int dstIndex, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(ByteBuffer dst) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void readBytes(OutputStream out, int length) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int readBytes(GatheringByteChannel out, int length)
+            throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void skipBytes(int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @Deprecated
+    public int skipBytes(ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void writeByte(int value) {
+        writerIndex++;
+    }
+
+    @Override
+    public void writeShort(int value) {
+    writerIndex += 2;
+}
+
+@Override
+public void writeMedium(int value) {
+    writerIndex += 3;
+}
+
+@Override
+public void writeInt(int value) {
+    writerIndex += 4;
+}
+
+@Override
+public void writeLong(long value) {
+    writerIndex += 8;
+}
+
+
+    @Override
+    public void writeChar(int value) {
+        writeShort(value);
+    }
+
+    @Override
+    public void writeFloat(float value) {
+        writeInt(Float.floatToIntBits(value));
+    }
+
+    @Override
+    public void writeDouble(double value) {
+        writeLong(Double.doubleToLongBits(value));
+
+    }
+
+    @Override
+    public void writeBytes(ChannelBuffer src) {
+        writerIndex += src.readableBytes();
+
+    }
+
+    @Override
+    public void writeBytes(ChannelBuffer src, int length) {
+        writerIndex += src.readableBytes();
+
+    }
+
+    @Override
+    public void writeBytes(ChannelBuffer src, int srcIndex, int length) {
+        writerIndex += length;
+    }
+
+    @Override
+    public void writeBytes(byte[] src) {
+        writerIndex += src.length;
+
+    }
+
+    @Override
+    public void writeBytes(byte[] src, int srcIndex, int length) {
+        writerIndex += length;
+    }
+
+    @Override
+    public void writeBytes(ByteBuffer src) {
+        writerIndex += src.remaining();
+
+    }
+
+    @Override
+    public int writeBytes(InputStream in, int length) throws IOException {
+        writerIndex += length;
+        return length;
+    }
+
+    @Override
+    public int writeBytes(ScatteringByteChannel in, int length)
+            throws IOException {
+        writerIndex += length;
+        return length;
+    }
+
+    @Override
+    public void writeZero(int length) {
+        writerIndex += length;
+
+    }
+
+    @Override
+    public int indexOf(int fromIndex, int toIndex, byte value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int indexOf(int fromIndex, int toIndex,
+            ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(byte value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(int length, byte value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(int length, ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(int index, int length, byte value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int bytesBefore(int index, int length,
+            ChannelBufferIndexFinder indexFinder) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer copy() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer copy(int index, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer slice() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer slice(int index, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ChannelBuffer duplicate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ByteBuffer toByteBuffer() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ByteBuffer toByteBuffer(int index, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ByteBuffer[] toByteBuffers() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ByteBuffer[] toByteBuffers(int index, int length) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean hasArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public byte[] array() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int arrayOffset() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString(Charset charset) {
+        return "LengthCountingPseudoChannelBuffer(length="+writerIndex+")";
+    }
+
+    @Override
+    public String toString(int index, int length, Charset charset) {
+        return toString();
+    }
+
+    @Override
+    @Deprecated
+    public String toString(String charsetName) {
+        return toString();
+    }
+
+    @Override
+    @Deprecated
+    public String toString(String charsetName,
+            ChannelBufferIndexFinder terminatorFinder) {
+        return toString();
+    }
+
+    @Override
+    @Deprecated
+    public String toString(int index, int length, String charsetName) {
+        return toString();
+    }
+
+    @Override
+    @Deprecated
+    public
+    String toString(int index, int length, String charsetName,
+            ChannelBufferIndexFinder terminatorFinder) {
+        return toString();
+    }
+
+    @Override
+    public int compareTo(ChannelBuffer buffer) {
+        throw new UnsupportedOperationException();
+
+    }
+
+}
diff --git a/java_gen/templates/_field_accessors.java b/java_gen/templates/_field_accessors.java
new file mode 100644
index 0000000..e8afe47
--- /dev/null
+++ b/java_gen/templates/_field_accessors.java
@@ -0,0 +1,33 @@
+//:: for prop in msg.interface.members:
+    @Override
+    public ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop in msg.members else "throws UnsupportedOperationException"} {
+//:: if prop in msg.members:
+//::    version_prop = msg.get_member(prop.name)
+//::    if version_prop.is_fixed_value:
+        return ${version_prop.enum_value};
+//::    elif version_prop.is_length_value:
+        // FIXME: Hacky and inperformant way to determine a message length. Should be replaced with something better
+        ChannelBuffer c = new LengthCountingPseudoChannelBuffer();
+        WRITER.write(c, ${ "this" if not builder else "({0}) this.getMessage()".format(msg.name) });
+        return c.writerIndex();
+//::    else:
+        return ${version_prop.name};
+//::    #endif
+//:: else:
+        throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
+//:: #endif
+    }
+
+//:: if generate_setters and prop.is_writeable:
+    @Override
+    public ${msg.interface.name}.Builder set${prop.title_name}(${prop.java_type.public_type} ${prop.name})${ "" if prop in msg.members else " throws UnsupportedOperationException"} {
+//:: if prop in msg.members:
+        this.${prop.name} = ${prop.name};
+        this.${prop.name}Set = true;
+        return this;
+//:: else:
+            throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
+//:: #endif
+    }
+//:: #endif
+//:: #endfor
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
new file mode 100644
index 0000000..7700546
--- /dev/null
+++ b/java_gen/templates/_imports.java
@@ -0,0 +1,12 @@
+import java.util.Collections;
+import java.util.List;
+import org.openflow.protocol.*;
+import org.openflow.protocol.action.*;
+import org.openflow.protocol.instruction.*;
+import org.openflow.protocol.match.*;
+import org.openflow.protocol.oxm.*;
+import org.openflow.types.*;
+import org.openflow.types.*;
+import org.openflow.util.*;
+import org.openflow.exceptions.*;
+import org.jboss.netty.buffer.ChannelBuffer;
diff --git a/java_gen/templates/of_type.java b/java_gen/templates/const.java
similarity index 74%
rename from java_gen/templates/of_type.java
rename to java_gen/templates/const.java
index 951a648..7870529 100644
--- a/java_gen/templates/of_type.java
+++ b/java_gen/templates/const.java
@@ -31,21 +31,22 @@
 
 //:: include('_autogen.java')
 
-package org.openflow.types;
+package ${package};
 
 import org.openflow.protocol.OFVersion;
 
-public enum OFType {
-//:: for i, msg in enumerate(all_messages):
-     ${msg.constant_name}(new byte[] { ${ ", ".join( [str(msg.wire_type(version)) for version in all_versions ]) } } )${ ", " if i < len(all_messages)-1 else ";" }
+public enum ${class_name} {
+//:: for i, entry in enumerate(enum.entries):
+//::     values = [ ("0x%x" % val) if val is not None else "-1" for val in entry.all_values(all_versions) ]
+     ${entry.name}(new int[] { ${ ", ".join( values) } } )${ ", " if i < len(enum.entries)-1 else ";" }
 //:: #endfor
 
-    byte[] wireTypes;
-    OFType(byte[] wireTypes) {
-        this.wireTypes = wireTypes;
+    private final int[] wireValues;
+    ${class_name}(int[] wireValues) {
+        this.wireValues = wireValues;
     }
 
-    public byte getWireType(OFVersion version) {
-        return this.wireTypes[version.getWireVersion()];
+    public int getWireValue(OFVersion version) {
+        return this.wireValues[version.getWireVersion()];
     }
 }
diff --git a/java_gen/templates/message_class.java b/java_gen/templates/message_class.java
deleted file mode 100644
index 2b4801c..0000000
--- a/java_gen/templates/message_class.java
+++ /dev/null
@@ -1,258 +0,0 @@
-//:: # Copyright 2013, Big Switch Networks, Inc.
-//:: #
-//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
-//:: # the following special exception:
-//:: #
-//:: # LOXI Exception
-//:: #
-//:: # As a special exception to the terms of the EPL, you may distribute libraries
-//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
-//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
-//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
-//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
-//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
-//:: #
-//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
-//:: #
-//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
-//:: # a copy of the EPL at:
-//:: #
-//:: # http::: #www.eclipse.org/legal/epl-v10.html
-//:: #
-//:: # Unless required by applicable law or agreed to in writing, software
-//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-//:: # EPL for the specific language governing permissions and limitations
-//:: # under the EPL.
-//::
-//:: import itertools
-//:: import of_g
-//:: include('_copyright.java')
-
-//:: include('_autogen.java')
-
-package org.openflow.protocol;
-import java.util.Collections;
-import java.util.List;
-import org.openflow.protocol.actions.OFAction;
-import org.openflow.protocol.instructions.OFInstruction;
-import org.openflow.protocol.match.*;
-import org.openflow.types.*;
-import org.openflow.types.*;
-import org.openflow.util.*;
-import org.openflow.exceptions.*;
-import org.jboss.netty.buffer.ChannelBuffer;
-
-class ${impl_class} implements ${msg.interface_name} {
-//:: if msg.is_fixed_length(version):
-    private static final int LENGTH = ${msg.min_length(version) };
-//:: else:
-    private static final int MINIMUM_LENGTH = ${msg.min_length(version) };
-//:: #endif
-
-//:: for prop in msg.properties_for_version(version):
-    private final static ${prop.java_type.public_type} ${prop.default_name} = ${prop.default_value};
-//:: #end
-    private boolean xidSet;
-    private final int xid;
-
-    // OF message fields
-//:: for prop in msg.properties_for_version(version):
-    private final ${prop.java_type.public_type} ${prop.name};
-//:: #endfor
-
-    // Constructor
-    ${impl_class}(${
-        ", ".join(["int xid" ] + [ "%s %s" %(prop.java_type.public_type, prop.name) for prop in msg.properties_for_version(version) ])}) {
-        this.xidSet = true;
-        this.xid = xid;
-//:: for prop in msg.properties_for_version(version):
-        this.${prop.name} = ${prop.name};
-//:: #endfor
-    }
-
-    ${impl_class}(${
-        ", ".join("%s %s" %(prop.java_type.public_type, prop.name) for prop in msg.properties_for_version(version)) }) {
-        this.xidSet = false;
-        this.xid = 0;
-//:: for prop in msg.properties_for_version(version):
-        this.${prop.name} = ${prop.name};
-//:: #endfor
-    }
-
-    @Override
-    public int getXid() {
-        return xid;
-    }
-
-    @Override
-    public boolean isXidSet() {
-        return xidSet;
-    }
-
-    @Override
-    public OFType getType() {
-        return OFType.${msg.constant_name};
-    }
-
-    @Override
-    public OFVersion getVersion() {
-        return OFVersion.${version.constant_version};
-    }
-
-    // Accessors for OF message fields
-//:: for prop in msg.all_properties():
-    @Override
-    public ${prop.java_type.public_type} get${prop.title_name}()${ "" if msg.property_in_version(prop, version) else "throws UnsupportedOperationException"} {
-//:: if msg.property_in_version(prop, version):
-        return ${prop.name};
-//:: else:
-        throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
-//:: #endif
-    }
-//:: #endfor
-
-    public ${msg.interface_name}.Builder createBuilder() {
-        return new BuilderImplWithParent(this);
-    }
-
-    static class BuilderImplWithParent implements ${msg.interface_name}.Builder {
-        final ${impl_class} parentMessage;
-        private boolean xidSet;
-        private int xid;
-
-        // OF message fields
-//:: for prop in msg.properties_for_version(version):
-        private boolean ${prop.name}Set;
-        private ${prop.java_type.public_type} ${prop.name};
-//:: #endfor
-
-        BuilderImplWithParent(${impl_class} parentMessage) {
-            this.parentMessage = parentMessage;
-        }
-
-//:: for prop in msg.all_properties():
-        @Override
-        public ${prop.java_type.public_type} get${prop.title_name}()${ "" if msg.property_in_version(prop, version) else " throws UnsupportedOperationException"} {
-//:: if msg.property_in_version(prop, version):
-            return ${prop.name};
-//:: else:
-            throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
-//:: #endif
-        }
-        @Override
-        public ${msg.interface_name}.Builder set${prop.title_name}(${prop.java_type.public_type} ${prop.name})${ "" if msg.property_in_version(prop, version) else " throws UnsupportedOperationException"} {
-//:: if msg.property_in_version(prop, version):
-            this.${prop.name} = ${prop.name};
-            this.${prop.name}Set = true;
-            return this;
-//:: else:
-        throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
-//:: #endif
-        }
-//:: #endfor
-        @Override
-        public ${msg.interface_name} getMessage() {
-            if(this.xidSet) {
-                return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "xid" ] +
-                         [ "this.{0}Set ? this.{0} : parentMessage.{0}".format(prop.name)
-                             for prop in msg.properties_for_version(version)])}
-                    );
-            } else {
-                return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "this.{0}Set ? this.{0} : parentMessage.{0}".format(prop.name)
-                             for prop in msg.properties_for_version(version)])}
-                    );
-            }
-        }
-    }
-
-    static class BuilderImpl implements ${msg.interface_name}.Builder {
-        private boolean xidSet;
-        private int xid;
-
-        // OF message fields
-//:: for prop in msg.properties_for_version(version):
-        private boolean ${prop.name}Set;
-        private ${prop.java_type.public_type} ${prop.name};
-//:: #endfor
-
-//:: for prop in msg.all_properties():
-        @Override
-        public ${prop.java_type.public_type} get${prop.title_name}()${ "" if msg.property_in_version(prop, version) else " throws UnsupportedOperationException"} {
-//:: if msg.property_in_version(prop, version):
-            return ${prop.name};
-//:: else:
-            throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
-//:: #endif
-        }
-        @Override
-        public ${msg.interface_name}.Builder set${prop.title_name}(${prop.java_type.public_type} ${prop.name})${ "" if msg.property_in_version(prop, version) else " throws UnsupportedOperationException"} {
-//:: if msg.property_in_version(prop, version):
-            this.${prop.name} = ${prop.name};
-            this.${prop.name}Set = true;
-            return this;
-//:: else:
-        throw new UnsupportedOperationException("Property ${prop.name} not supported in version #{version}");
-//:: #endif
-        }
-//:: #endfor
-        @Override
-        public ${msg.interface_name} getMessage() {
-            if(this.xidSet) {
-                return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "xid" ] +
-                         [ "this.{0}Set ? this.{0} : {1}.{2}".format(prop.name, impl_class, prop.default_name)
-                             for prop in msg.properties_for_version(version)])}
-                    );
-            } else {
-                return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "this.{0}Set ? this.{0} : {1}.{2}".format(prop.name, impl_class, prop.default_name)
-                             for prop in msg.properties_for_version(version)])}
-                    );
-            }
-        }
-    }
-
-    final static Reader READER = new Reader();
-    static class Reader implements OFMessageReader<${msg.interface_name}> {
-        @Override
-        public ${msg.interface_name} readFrom(ChannelBuffer bb) throws OFParseError {
-            byte version = bb.readByte();
-            if (version != (byte) ${version.int_version})
-                throw new OFParseError("Wrong version: Expected=${version.int_version}, got="+version);
-
-            byte type = bb.readByte();
-            if(type != ${msg.wire_type(version)})
-                throw new OFParseError("Wrong message type: Expected=${msg.constant_name}, got="+type);
-
-            int length = bb.readUnsignedShort();
-//:: if msg.is_fixed_length(version):
-            if(length != LENGTH)
-                throw new OFParseError("Wrong message length: Expected="+LENGTH +", got="+length);
-//:: else:
-            if(length < MINIMUM_LENGTH)
-                throw new OFParseError("Insufficient message length: minimum length="+MINIMUM_LENGTH +", got="+length);
-//:: #endif
-            int xid = bb.readInt();
-//:: for prop in msg.properties_for_version(version, skip_pads=False):
-//:: if prop.is_pad:
-            // pad: ${prop.length} bytes
-            bb.skipBytes(${prop.length});
-//:: else:
-            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version)};
-//:: #endif
-//:: #endfor
-                return new ${impl_class}(
-                    ${",\n                      ".join(
-                         [ "xid" ] + [ prop.name for prop in msg.properties_for_version(version)])}
-                    );
-        }
-    }
-
-}
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
new file mode 100644
index 0000000..51fbf5c
--- /dev/null
+++ b/java_gen/templates/of_class.java
@@ -0,0 +1,209 @@
+//:: # Copyright 2013, Big Switch Networks, Inc.
+//:: #
+//:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+//:: # the following special exception:
+//:: #
+//:: # LOXI Exception
+//:: #
+//:: # As a special exception to the terms of the EPL, you may distribute libraries
+//:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+//:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+//:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+//:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+//:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+//:: #
+//:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+//:: #
+//:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+//:: # a copy of the EPL at:
+//:: #
+//:: # http::: #www.eclipse.org/legal/epl-v10.html
+//:: #
+//:: # Unless required by applicable law or agreed to in writing, software
+//:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+//:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+//:: # EPL for the specific language governing permissions and limitations
+//:: # under the EPL.
+//::
+//:: from loxi_ir import *
+//:: import itertools
+//:: import of_g
+//:: include('_copyright.java')
+
+//:: include('_autogen.java')
+
+package ${msg.package};
+
+//:: include("_imports.java", msg=msg)
+
+class ${impl_class} implements ${msg.interface.name} {
+    // version: ${version}
+    private final static byte WIRE_VERSION = ${version.int_version};
+//:: if msg.is_fixed_length:
+    private final static int LENGTH = ${msg.length};
+//:: else:
+    private final static int MINIMUM_LENGTH = ${msg.min_length};
+//:: #endif
+
+//:: for prop in msg.data_members:
+    private final static ${prop.java_type.public_type} ${prop.default_name} = ${prop.default_value};
+//:: #end
+
+    // OF message fields
+//:: for prop in msg.data_members:
+    private final ${prop.java_type.public_type} ${prop.name};
+//:: #endfor
+
+    ${impl_class}(${
+        ", ".join("%s %s" %(prop.java_type.public_type, prop.name) for prop in msg.data_members) }) {
+//:: for prop in msg.data_members:
+        this.${prop.name} = ${prop.name};
+//:: #endfor
+    }
+
+    // Accessors for OF message fields
+//:: include("_field_accessors.java", msg=msg, generate_setters=False, builder=False)
+
+
+    public ${msg.name}.Builder createBuilder() {
+        return new BuilderImplWithParent(this);
+    }
+
+    static class BuilderImplWithParent implements ${msg.interface.name}.Builder {
+        final ${impl_class} parentMessage;
+
+        // OF message fields
+//:: for prop in msg.data_members:
+        private boolean ${prop.name}Set;
+        private ${prop.java_type.public_type} ${prop.name};
+//:: #endfor
+
+        BuilderImplWithParent(${impl_class} parentMessage) {
+            this.parentMessage = parentMessage;
+        }
+
+//:: include("_field_accessors.java", msg=msg, generate_setters=True, builder=True)
+
+        @Override
+        public ${msg.interface.name} getMessage() {
+                return new ${impl_class}(
+                    ${",\n                      ".join(
+                         [ "this.{0}Set ? this.{0} : parentMessage.{0}".format(prop.name)
+                             for prop in msg.data_members])}
+                    );
+        }
+    }
+
+    static class BuilderImpl implements ${msg.interface.name}.Builder {
+        // OF message fields
+//:: for prop in msg.data_members:
+        private boolean ${prop.name}Set;
+        private ${prop.java_type.public_type} ${prop.name};
+//:: #endfor
+
+//:: include("_field_accessors.java", msg=msg, generate_setters=True, builder=True)
+//
+        @Override
+        public ${msg.interface.name} getMessage() {
+            return new ${impl_class}(
+                ${",\n                      ".join(
+                     [ "this.{0}Set ? this.{0} : {1}.{2}".format(prop.name, impl_class, prop.default_name)
+                         for prop in msg.data_members])}
+                );
+        }
+    }
+
+    final static Reader READER = new Reader();
+    static class Reader implements OFMessageReader<${msg.interface.name}> {
+        @Override
+        public ${msg.interface.name} readFrom(ChannelBuffer bb) throws OFParseError {
+//:: fields_with_length_member = {}
+//:: for prop in msg.members:
+//:: if prop.is_data:
+            ${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version,
+                    length=fields_with_length_member[prop.c_name] if prop.c_name in fields_with_length_member else None)};
+//:: elif prop.is_pad:
+            // pad: ${prop.length} bytes
+            bb.skipBytes(${prop.length});
+//:: 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)};
+            if(${prop.name} != ${prop.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)};
+            if(${prop.name} < MINIMUM_LENGTH)
+                throw new OFParseError("Wrong ${prop.name}: Expected to be >= " + MINIMUM_LENGTH + ", was: " + ${prop.name});
+//:: elif prop.is_field_length_value:
+//::        fields_with_length_member[prop.member.field_name] = prop.name
+            int ${prop.name} = ${prop.java_type.read_op(version)};
+//:: else:
+    // fixme: todo ${prop.name}
+//:: #endif
+//:: #endfor
+            return new ${impl_class}(
+                    ${",\n                      ".join(
+                         [ prop.name for prop in msg.data_members])}
+                    );
+        }
+    }
+
+    public int writeTo(ChannelBuffer bb) {
+        return WRITER.write(bb, this);
+    }
+
+    final static Writer WRITER = new Writer();
+    static class Writer implements OFMessageWriter<${impl_class}> {
+        @Override
+        public int write(ChannelBuffer bb, ${impl_class} message) {
+//:: if not msg.is_fixed_length:
+            int startIndex = bb.readerIndex();
+//:: #end
+
+//:: fields_with_length_member = {}
+//:: for prop in msg.members:
+//:: if prop.c_name in fields_with_length_member:
+            int ${prop.name}StartIndex = bb.writerIndex();
+//:: #endif
+//:: if prop.is_data:
+            ${prop.java_type.write_op(version, "message." + prop.name)};
+//:: elif prop.is_pad:
+            // pad: ${prop.length} bytes
+            bb.writeZero(${prop.length});
+//:: elif prop.is_fixed_value:
+            // fixed value property ${prop.name} = ${prop.value}
+            ${prop.java_type.write_op(version, prop.value)};
+//:: elif prop.is_length_value:
+            // ${prop.name} is length of variable message, will be updated at the end
+            ${prop.java_type.write_op(version, 0)};
+//:: elif prop.is_field_length_value:
+//::        fields_with_length_member[prop.member.field_name] = prop.name
+            // ${prop.name} is length indicator for ${prop.member.field_name}, will be
+            // udpated when ${prop.member.field_name} has been written
+            int ${prop.name}Index = bb.writerIndex();
+            ${prop.java_type.write_op(version, 0)};
+//:: else:
+            // FIXME: todo write ${prop.name}
+//:: #endif
+//:: if prop.c_name in fields_with_length_member:
+//::     length_member_name = fields_with_length_member[prop.c_name]
+            // update field length member ${length_member_name}
+            int ${prop.name}Length = bb.writerIndex() - ${prop.name}StartIndex;
+            bb.setShort(${length_member_name}Index, ${prop.name}Length);
+//:: #endif
+//:: #endfor
+
+//:: if msg.is_fixed_length:
+            return LENGTH;
+//:: else:
+            // update length field
+            int length = bb.writerIndex() - startIndex;
+            bb.setShort(startIndex + 2, length);
+            return length;
+//:: #end
+
+        }
+    }
+
+
+}
diff --git a/java_gen/templates/message_interface.java b/java_gen/templates/of_interface.java
similarity index 71%
rename from java_gen/templates/message_interface.java
rename to java_gen/templates/of_interface.java
index 904be95..e8e15c0 100644
--- a/java_gen/templates/message_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -31,32 +31,25 @@
 
 //:: include('_autogen.java')
 
-package org.openflow.protocol;
-import java.util.List;
-import org.openflow.protocol.match.*;
-import org.openflow.protocol.actions.OFAction;
-import org.openflow.protocol.instructions.OFInstruction;
-import org.openflow.types.*;
-import org.openflow.util.*;
-import org.openflow.exceptions.OFUnsupported;
+package ${msg.package};
 
-public interface ${msg.interface_name} extends OFMessage {
-    int getXid();
-    boolean isXidSet();
-    OFType getType();
-    OFVersion getVersion();
+//:: include("_imports.java", msg=msg)
 
-//:: for prop in msg.all_properties():
-    ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else "throws UnsupportedOperationException"};
+public interface ${msg.name} ${"extends %s" % msg.parent_interface if msg.parent_interface else ""} {
+//:: for prop in (prop for prop in msg.members):
+    ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
 //:: #endfor
 
-    Builder createBuilder();
+    int writeTo(ChannelBuffer channelBuffer);
 
-    public interface Builder {
-        ${msg.interface_name} getMessage();
-//:: for prop in msg.all_properties():
-        ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else "throws UnsupportedOperationException"};
+    Builder createBuilder();
+    public interface Builder ${"extends %s.Builder" % msg.parent_interface if msg.parent_interface else ""} {
+        ${msg.name} getMessage();
+//:: for prop in msg.members:
+        ${prop.java_type.public_type} get${prop.title_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"};
+//:: #endif
 //:: #endfor
 
     }
diff --git a/lang_java.py b/lang_java.py
index db23c82..ab711f7 100644
--- a/lang_java.py
+++ b/lang_java.py
@@ -42,11 +42,11 @@
 
 """
 
-import java_gen.java_code_gen as java_code_gen
+import java_gen.codegen as java_codegen
 
 
 targets = {
-    'base_java': java_code_gen.gen_all_java
+    'base_java': java_codegen.gen_all_java
 }
 
 ##
@@ -66,7 +66,7 @@
 # that generates the content of the file
 
 file_gen_map = dict(
-    base_java=java_code_gen.gen_all_java,
+    base_java=java_codegen.gen_all_java,
 )