Merge into master from pull request #47:
Java_gen: Richer OXM support, factory reorganization (https://github.com/floodlight/loxigen/pull/47)
diff --git a/java_gen/codegen.py b/java_gen/codegen.py
index bc9b9a0..1e68acd 100644
--- a/java_gen/codegen.py
+++ b/java_gen/codegen.py
@@ -147,11 +147,11 @@
test_data=unit_test.test_data)
def create_of_factories(self):
- factory = self.java_model.of_factory
- self.render_class(clazz=factory, template="of_factory_interface.java", factory=factory)
- for factory_class in factory.factory_classes:
- self.render_class(clazz=factory_class, template="of_factory_class.java", factory=factory_class, model=self.java_model)
- self.render_class(clazz=java_model.OFGenericClass(package="org.openflow.protocol", name="OFFactories"), template="of_factories.java", versions=self.java_model.versions)
+ for factory in self.java_model.of_factories:
+ self.render_class(clazz=factory, template="of_factory_interface.java", factory=factory)
+ for factory_class in factory.factory_classes:
+ self.render_class(clazz=factory_class, template="of_factory_class.java", factory=factory_class, model=self.java_model)
+ self.render_class(clazz=java_model.OFGenericClass(package="org.openflow.protocol", name="OFFactories"), template="of_factories.java", versions=self.java_model.versions)
def copy_prewrite_tree(basedir):
""" Recursively copy the directory structure from ./java_gen/pre-write
diff --git a/java_gen/java_model.py b/java_gen/java_model.py
index 66eeacd..944b536 100644
--- a/java_gen/java_model.py
+++ b/java_gen/java_model.py
@@ -44,6 +44,7 @@
import test_data
import java_gen.java_type as java_type
+from java_gen.java_type import erase_type_annotation
class JavaModel(object):
enum_blacklist = set(("OFDefinitions",))
@@ -53,6 +54,9 @@
write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )))
virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
+ OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
+ oxm_map = { "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True) }
+
@property
@memoize
def versions(self):
@@ -80,6 +84,10 @@
return interfaces
+ @memoize
+ def interface_by_name(self, name):
+ return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
+
@property
@memoize
def all_classes(self):
@@ -111,11 +119,40 @@
@property
@memoize
- def of_factory(self):
- return OFFactory(
- package="org.openflow.protocol",
+ def of_factories(self):
+ prefix = "org.openflow.protocol"
+
+ factories = OrderedDict()
+
+ sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
+ for base_class in sub_factory_classes:
+ package = base_class[2:].lower()
+ remove_prefix = base_class[2].lower() + base_class[3:]
+
+ # HACK need to have a better way to deal with parameterized base classes
+ annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
+
+ factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
+ name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
+
+ factories[""] = OFFactory(
+ package=prefix,
name="OFFactory",
- members=self.interfaces)
+ remove_prefix="",
+ members=[], base_class="OFMessage", sub_factories=OrderedDict(
+ ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
+
+ for i in self.interfaces:
+ for n, factory in factories.items():
+ if n == "":
+ factory.members.append(i)
+ break
+ else:
+ super_class = self.interface_by_name(n)
+ if i.is_instance_of(super_class):
+ factory.members.append(i)
+ break
+ return factories.values()
def generate_class(self, clazz):
""" return wether or not to generate implementation class clazz.
@@ -139,19 +176,39 @@
return True
-class OFFactory(namedtuple("OFFactory", ("package", "name", "members"))):
+class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
@property
def factory_classes(self):
return [ OFFactoryClass(
package="org.openflow.protocol.ver{}".format(version.of_version),
- name="OFFactoryVer{}".format(version.of_version),
+ name="{}Ver{}".format(self.name, version.of_version),
interface=self,
version=version
) for version in model.versions ]
+ def method_name(self, member, builder=True):
+ n = member.variable_name
+ if n.startswith(self.remove_prefix):
+ n = n[len(self.remove_prefix):]
+ n = n[0].lower() + n[1:]
+ if builder:
+ return "build" + n[0].upper() + n[1:]
+ else:
+ return n
OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
-OFFactoryClass = namedtuple("OFFactory", ("package", "name", "interface", "version"))
+class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
+ @property
+ def base_class(self):
+ return self.interface.base_class
+
+ @property
+ def versioned_base_class(self):
+ base_class_interface = model.interface_by_name(self.interface.base_class)
+ if base_class_interface and base_class_interface.has_version(self.version):
+ return base_class_interface.versioned_class(self.version)
+ else:
+ return None
model = JavaModel()
@@ -206,60 +263,106 @@
self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
# variable_name name to use for variables of this type. i.e., flowAdd
self.variable_name = self.name[2].lower() + self.name[3:]
+ self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
# name for use in constants: FLOW_ADD
self.constant_name = c_name.upper().replace("OF_", "")
- pck_suffix, parent_interface = self.class_info()
+ pck_suffix, parent_interface, self.type_annotation = 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 is_instance_of(self, other_class):
+ if self == other_class:
+ return True
+ parent = self.super_class
+ if parent is None:
+ return False
+ else:
+ return parent.is_instance_of(other_class)
+
+ @property
+ def super_class(self):
+ if not self.parent_interface:
+ return None
+ else:
+ return model.interface_by_name(self.parent_interface)
+
+
+ def inherited_declaration(self, type_spec="?"):
+ if self.type_annotation:
+ return "%s<%s>" % (self.name, type_spec)
+ else:
+ return "%s" % self.name
+
+ @property
+ def type_variable(self):
+ if self.type_annotation:
+ return "<T>"
+ else:
+ return "";
+
def class_info(self):
""" return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
# FIXME: This duplicates inheritance information that is now available in the loxi_ir
# model (note, that the loxi model is on versioned classes). Should check/infer the
# inheritance information from the versioned lox_ir classes.
if re.match(r'OF.+StatsRequest$', self.name):
- return ("", "OFStatsRequest")
+ return ("", "OFStatsRequest", None)
elif re.match(r'OF.+StatsReply$', self.name):
- return ("", "OFStatsReply")
+ return ("", "OFStatsReply", None)
elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
- return ("", "OFFlowMod")
+ return ("", "OFFlowMod", None)
elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name):
- return ("", "OFBsnHeader")
+ return ("", "OFBsnHeader", None)
elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name):
- return ("", "OFNiciraHeader")
+ return ("", "OFNiciraHeader", None)
elif re.match(r'OFMatch.*', self.name):
- return ("", "Match")
+ return ("", "Match", None)
elif loxi_utils.class_is_message(self.c_name):
- return ("", "OFMessage")
+ return ("", "OFMessage", None)
elif loxi_utils.class_is_action(self.c_name):
- if re.match(r'OFActionBsn.*', self.name):
- return ("action", "OFActionBsn")
- elif re.match(r'OFActionNicira.*', self.name):
- return ("action", "OFActionNicira")
+ if re.match(r'OFActionBsn.+', self.name):
+ return ("action", "OFActionBsn", None)
+ elif re.match(r'OFActionNicira.+', self.name):
+ return ("action", "OFActionNicira", None)
else:
- return ("action", "OFAction")
+ return ("action", "OFAction", None)
elif re.match(r'OFBsnVport.+$', self.name):
- return ("", "OFBsnVport")
+ return ("", "OFBsnVport", None)
+ elif self.name == "OFOxm":
+ return ("oxm", None, "T extends OFValueType<T>")
elif loxi_utils.class_is_oxm(self.c_name):
- return ("oxm", "OFOxm")
+ if self.name in model.oxm_map:
+ return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
+ else:
+ return ("oxm", "OFOxm", None)
elif loxi_utils.class_is_instruction(self.c_name):
- return ("instruction", "OFInstruction")
+ return ("instruction", "OFInstruction", None)
elif loxi_utils.class_is_meter_band(self.c_name):
- return ("meterband", "OFMeterBand")
+ return ("meterband", "OFMeterBand", None)
elif loxi_utils.class_is_queue_prop(self.c_name):
- return ("queueprop", "OFQueueProp")
+ return ("queueprop", "OFQueueProp", None)
elif loxi_utils.class_is_hello_elem(self.c_name):
- return ("", "OFHelloElem")
+ return ("", "OFHelloElem", None)
else:
- return ("", None)
+ return ("", None, None)
+
+ @property
+ @memoize
+ def writeable_members(self):
+ return [ m for m in self.members if m.is_writeable ]
@property
@memoize
def members(self):
+ return self.ir_model_members + self.virtual_members
+
+ @property
+ @memoize
+ def ir_model_members(self):
"""return a list of all members to be exposed by this interface. Corresponds to
the union of the members of the vesioned classes without length, fieldlength
and pads (those are handled automatically during (de)serialization and not exposed"""
@@ -275,7 +378,33 @@
if of_member.name not in member_map:
member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
- return member_map.values()
+ return tuple(member_map.values())
+
+ @property
+ def virtual_members(self):
+ if self.name == "OFOxm":
+ return (
+ JavaVirtualMember(self, "value", java_type.generic_t),
+ JavaVirtualMember(self, "mask", java_type.generic_t),
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
+ JavaVirtualMember(self, "masked", java_type.boolean),
+ )
+ elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
+ field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
+ if self.name in model.oxm_map \
+ else java_type.make_match_field_jtype()
+
+ return (
+ JavaVirtualMember(self, "matchField", field_type),
+ JavaVirtualMember(self, "masked", java_type.boolean),
+ ) \
+ + \
+ (
+ ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
+ ()
+ )
+ else:
+ return ()
@property
@memoize
@@ -384,8 +513,29 @@
@property
@memoize
def members(self):
+ return self.ir_model_members + self.virtual_members
+
+ @property
+ def ir_model_members(self):
members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
- return members
+ return tuple(members)
+
+ @property
+ def virtual_members(self):
+ if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
+ if self.interface.name in model.oxm_map:
+ oxm_entry = model.oxm_map[self.interface.name]
+ return (
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
+ JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
+ )
+ else:
+ return (
+ JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
+ JavaVirtualMember(self, "masked", java_type.boolean, "false"),
+ )
+ else:
+ return ()
def all_versions(self):
return [ JavaOFVersion(int_version)
@@ -447,6 +597,14 @@
return self.c_name.upper()
@property
+ def getter_name(self):
+ return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
+
+ @property
+ def setter_name(self):
+ return "set" + self.title_name
+
+ @property
def default_name(self):
if self.is_fixed_value:
return self.constant_name
@@ -459,10 +617,14 @@
if self.is_fixed_value:
return self.enum_value
+ elif java_type == "OFOxmList":
+ return "OFOxmList.EMPTY"
elif re.match(r'List.*', java_type):
return "Collections.emptyList()"
elif java_type == "boolean":
return "false";
+ elif self.java_type.is_array:
+ return "new %s[0]" % java_type[:-2]
elif java_type in ("byte", "char", "short", "int", "long"):
return "({0}) 0".format(java_type);
else:
@@ -562,6 +724,8 @@
else:
if member.name == 'len':
name = 'length'
+ elif member.name == 'value_mask':
+ name = 'mask'
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)
@@ -582,6 +746,10 @@
return False
return True
+ @property
+ def is_virtual(self):
+ return False
+
def __hash__(self):
return hash(self.name)
@@ -590,6 +758,32 @@
return False
return (self.name,) == (other.name,)
+class JavaVirtualMember(JavaMember):
+ """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
+ def __init__(self, msg, name, java_type, value=None):
+ JavaMember.__init__(self, msg, name, java_type, member=None)
+ self._value = value
+
+ @property
+ def is_fixed_value(self):
+ return True
+
+ @property
+ def value(self):
+ return self._value
+
+ @property
+ def priv_value(self):
+ return self._value
+
+
+ @property
+ def is_universal(self):
+ return True
+
+ @property
+ def is_virtual(self):
+ return True
#######################################################################
### Unit Test
diff --git a/java_gen/java_type.py b/java_gen/java_type.py
index 35503e5..e7f2201 100644
--- a/java_gen/java_type.py
+++ b/java_gen/java_type.py
@@ -5,6 +5,13 @@
import subprocess
import time
+def erase_type_annotation(class_name):
+ m=re.match(r'(.*)<.*>', class_name)
+ if m:
+ return m.group(1)
+ else:
+ return class_name
+
def name_c_to_camel(name):
""" 'of_stats_reply' -> 'ofStatsReply' """
name = re.sub(r'^_','', name)
@@ -212,7 +219,7 @@
u32obj = JType('U32', 'U32') \
.op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())')
u64 = JType('U64', 'U64') \
- .op(read='U64.of(bb.readLong())', write='bb.writeLong($name.getValue())')
+ .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())')
of_port = JType("OFPort") \
.op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") \
.op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)")
@@ -288,11 +295,20 @@
.op(read="IPv6FlowLabel.read4Bytes(bb)", write="$name.write4Bytes(bb)")
metadata = JType("OFMetadata")\
.op(read="OFMetadata.read8Bytes(bb)", write="$name.write8Bytes(bb)")
-oxm = JType("OFOxm")\
- .op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+oxm = JType("OFOxm<?>")\
+ .op( read="OFOxmVer$version.READER.readFrom(bb)",
+ write="$name.writeTo(bb)")
+oxm_list = JType("OFOxmList") \
+ .op(
+ read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
+ write='$name.writeTo(bb)')
meter_features = JType("OFMeterFeatures")\
.op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
+boolean = JType("boolean")
+
+generic_t = JType("T")
+
default_mtype_to_jtype_convert_map = {
'uint8_t' : u8,
@@ -307,6 +323,7 @@
'list(of_packet_queue_t)' : packet_queue_list,
'list(of_uint32_t)' : u32_list,
'list(of_uint8_t)' : u8_list,
+ 'list(of_oxm_t)' : oxm_list,
'of_octets_t' : octets,
'of_match_t': of_match,
'of_fm_cmd_t': flow_mod_cmd,
@@ -376,6 +393,9 @@
'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
}
+def make_match_field_jtype(sub_type_name="?"):
+ return JType("MatchField<{}>".format(sub_type_name))
+
# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
def make_standard_list_jtype(c_type):
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java
new file mode 100644
index 0000000..d9ede81
--- /dev/null
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/OFOxmList.java
@@ -0,0 +1,128 @@
+package org.openflow.protocol;
+
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.match.MatchField;
+import org.openflow.protocol.match.MatchFields;
+import org.openflow.protocol.oxm.OFOxm;
+import org.openflow.types.OFValueType;
+import org.openflow.util.ChannelUtils;
+
+import com.google.common.collect.ImmutableMap;
+
+public class OFOxmList implements Iterable<OFOxm<?>>, Writeable {
+ private final Map<MatchFields, OFOxm<?>> oxmMap;
+
+ public final static OFOxmList EMPTY = new OFOxmList(ImmutableMap.<MatchFields, OFOxm<?>>of());
+
+ private OFOxmList(Map<MatchFields, OFOxm<?>> oxmMap) {
+ this.oxmMap = oxmMap;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends OFValueType<T>> OFOxm<T> get(MatchField<T> matchField) {
+ return (OFOxm<T>) oxmMap.get(matchField.id);
+ }
+
+ public static class Builder {
+ private final Map<MatchFields, OFOxm<?>> oxmMap;
+
+ public Builder() {
+ oxmMap = new EnumMap<MatchFields, OFOxm<?>>(MatchFields.class);
+ }
+
+ public Builder(EnumMap<MatchFields, OFOxm<?>> oxmMap) {
+ this.oxmMap = oxmMap;
+ }
+
+ public <T extends OFValueType<T>> void set(OFOxm<T> oxm) {
+ oxmMap.put(oxm.getMatchField().id, oxm);
+ }
+
+ public <T extends OFValueType<T>> void unset(MatchField<T> matchField) {
+ oxmMap.remove(matchField.id);
+ }
+
+ public OFOxmList build() {
+ return new OFOxmList(oxmMap);
+ }
+ }
+
+ @Override
+ public Iterator<OFOxm<?>> iterator() {
+ return oxmMap.values().iterator();
+ }
+
+ public static OFOxmList ofList(List<OFOxm<?>> oxmList) {
+ Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+ MatchFields.class);
+ for (OFOxm<?> o : oxmList) {
+ // TODO: if fully masked, ignore oxm.
+ map.put(o.getMatchField().id, o);
+ }
+ return new OFOxmList(map);
+ }
+
+ public static OFOxmList of(OFOxm<?>... oxms) {
+ Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+ MatchFields.class);
+ for (OFOxm<?> o : oxms) {
+ // TODO: if fully masked, ignore oxm.
+ map.put(o.getMatchField().id, o);
+ }
+ return new OFOxmList(map);
+ }
+
+ public static OFOxmList readFrom(ChannelBuffer bb, int length,
+ OFMessageReader<OFOxm<?>> reader) throws OFParseError {
+ return ofList(ChannelUtils.readList(bb, length, reader));
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer bb) {
+ for (OFOxm<?> o : this) {
+ o.writeTo(bb);
+ }
+ }
+
+ public org.openflow.protocol.OFOxmList.Builder createBuilder() {
+ return new OFOxmList.Builder(new EnumMap<MatchFields, OFOxm<?>>(oxmMap));
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((oxmMap == null) ? 0 : oxmMap.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ OFOxmList other = (OFOxmList) obj;
+ if (oxmMap == null) {
+ if (other.oxmMap != null)
+ return false;
+ } else if (!oxmMap.equals(other.oxmMap))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "OFOxmList" + oxmMap;
+ }
+
+
+}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
index 8f17845..cdb34e5 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/protocol/match/Match.java
@@ -32,20 +32,20 @@
* On prerequisites:<br>
* From the OF1.1 spec, page 28, the OF1.0 spec failed to explicitly specify this, but it
* is the behavior of OF1.0 switches:
- * "Protocol-specific fields within ofp_match will be ignored within a single table when
- * the corresponding protocol is not specified in the match. The MPLS match fields will
- * be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and
- * transport header fields will be ignored unless the Ethertype is specified as either
- * IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol
- * specified is as TCP, UDP or SCTP. Fields that are ignored donÕt need to be wildcarded
+ * "Protocol-specific fields within ofp_match will be ignored within a single table when
+ * the corresponding protocol is not specified in the match. The MPLS match fields will
+ * be ignored unless the Ethertype is specified as MPLS. Likewise, the IP header and
+ * transport header fields will be ignored unless the Ethertype is specified as either
+ * IPv4 or ARP. The tp_src and tp_dst fields will be ignored unless the network protocol
+ * specified is as TCP, UDP or SCTP. Fields that are ignored don�t need to be wildcarded
* and should be set to 0."
* <br><br>
- * This interface uses generics to assure type safety in users code. However, implementing classes may have to suppress
+ * This interface uses generics to assure type safety in users code. However, implementing classes may have to suppress
* 'unchecked cast' warnings while making sure they correctly cast base on their implementation details.
- *
+ *
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
-public interface Match extends OFObject {
+public interface Match extends OFObject {
/**
* Returns a value for the given field if:
@@ -55,7 +55,7 @@
* <li>Prerequisites are ok
* </ul>
* If one of the above conditions does not hold, returns null. Value is returned masked if partially wildcarded.
- *
+ *
* @param field Match field to retrieve
* @return Value of match field (may be masked), or <code>null</code> if field is one of the conditions above does not hold.
* @throws UnsupportedOperationException If field is not supported.
@@ -66,7 +66,7 @@
* Returns the masked value for the given field from this match, along with the mask itself.
* Prerequisite: field is partially masked.
* If prerequisite is not met, a <code>null</code> is returned.
- *
+ *
* @param field Match field to retrieve.
* @return Masked value of match field or null if no mask is set.
* @throws UnsupportedOperationException If field is not supported.
@@ -75,7 +75,7 @@
/**
* Returns true if and only if this match object supports the given match field.
- *
+ *
* @param field Match field
* @return true if field is supported, false otherwise.
*/
@@ -84,7 +84,7 @@
/**
* Returns true if and only if this match object supports partially bitmasking of the given field.
* (note: not all possible values of this bitmask have to be acceptable)
- *
+ *
* @param field Match field.
* @return true if field can be partially masked, false otherwise.
* @throws UnsupportedOperationException If field is not supported.
@@ -94,7 +94,7 @@
/**
* Returns true if and only if this field is currently specified in the match with an exact value and
* no mask. I.e., the specified match will only select packets that match the exact value of getValue(field).
- *
+ *
* @param field Match field.
* @return true if field has a specific exact value, false if not.
* @throws UnsupportedOperationException If field is not supported.
@@ -102,10 +102,10 @@
public boolean isExact(MatchField<?> field) throws UnsupportedOperationException;
/**
- * True if and only if this field is currently logically unspecified in the match, i.e, the
- * value returned by getValue(f) has no impact on whether a packet will be selected
+ * True if and only if this field is currently logically unspecified in the match, i.e, the
+ * value returned by getValue(f) has no impact on whether a packet will be selected
* by the match or not.
- *
+ *
* @param field Match field.
* @return true if field is fully wildcarded, false if not.
* @throws UnsupportedOperationException If field is not supported.
@@ -113,16 +113,16 @@
public boolean isFullyWildcarded(MatchField<?> field) throws UnsupportedOperationException;
/**
- * True if and only if this field is currently partially specified in the match, i.e, the
+ * True if and only if this field is currently partially specified in the match, i.e, the
* match will only select packets that match (p.value & getMask(field)) == getValue(field),
* and getMask(field) != 0.
- *
+ *
* @param field Match field.
* @return true if field is partially masked, false if not.
* @throws UnsupportedOperationException If field is not supported.
*/
public boolean isPartiallyMasked(MatchField<?> field) throws UnsupportedOperationException;
-
+
/**
* Returns a builder to build new instances of this type of match object.
* @return Match builder
@@ -135,17 +135,17 @@
* corresponds to. The builder uses the same notation of wildcards and masks, and can also throw
* <code>UnsupportedOperationException</code> if it is asked to create some matching that is not supported in
* the version it represents.
- *
+ *
* While used, MatchBuilder may not be consistent in terms of field prerequisites. However, user must
* solve these before using the generated Match object as these prerequisites should be enforced in the
- * getters.
- *
+ * getters.
+ *
* @author Yotam Harchol (yotam.harchol@bigswitch.com)
*/
interface Builder extends Match {
/**
* Sets a specific exact value for a field.
- *
+ *
* @param field Match field to set.
* @param value Value of match field.
* @return the Builder instance used.
@@ -155,7 +155,7 @@
/**
* Sets a masked value for a field.
- *
+ *
* @param field Match field to set.
* @param value Value of field.
* @param mask Mask value.
@@ -166,7 +166,7 @@
/**
* Sets a masked value for a field.
- *
+ *
* @param field Match field to set.
* @param valueWithMask Compound Masked object contains the value and the mask.
* @return the Builder instance used.
@@ -176,7 +176,7 @@
/**
* Unsets any value given for the field and wildcards it so that it matches any value.
- *
+ *
* @param field Match field to unset.
* @return the Builder instance used.
* @throws UnsupportedOperationException If field is not supported.
@@ -185,9 +185,9 @@
/**
* Returns the match created by this builder.
- *
+ *
* @return a Match object.
*/
- public Match getMatch();
+ public Match build();
}
}
\ No newline at end of file
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java b/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java
index e27679c..e82bc40 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/OFMetadata.java
@@ -2,36 +2,43 @@
import org.jboss.netty.buffer.ChannelBuffer;
-public class OFMetadata extends U64 implements OFValueType<OFMetadata> {
-
+public class OFMetadata implements OFValueType<OFMetadata> {
+
private static int LENGTH = 8;
- public static final OFMetadata NO_MASK = OFMetadata.of(0xFFFFFFFFFFFFFFFFl);
- public static final OFMetadata FULL_MASK = OFMetadata.of(0x0);
+ private final U64 u64;
- protected OFMetadata(long raw) {
- super(raw);
+ public static final OFMetadata NO_MASK = OFMetadata.of(U64.ofRaw(0xFFFFFFFFFFFFFFFFl));
+ public static final OFMetadata FULL_MASK = OFMetadata.of(U64.ofRaw(0x0));
+
+ public OFMetadata(U64 ofRaw) {
+ u64 = ofRaw;
}
- public static OFMetadata of(long raw) {
- return new OFMetadata(raw);
+ public static OFMetadata of(U64 u64) {
+ return new OFMetadata(u64);
}
-
+
+ public static OFMetadata ofRaw(long raw) {
+ return new OFMetadata(U64.ofRaw(raw));
+ }
+
public static OFMetadata read8Bytes(ChannelBuffer cb) {
- return OFMetadata.of(cb.readLong());
+ return OFMetadata.ofRaw(cb.readLong());
}
-
+
public void write8Bytes(ChannelBuffer cb) {
- cb.writeLong(super.getValue());
+ u64.writeTo(cb);
}
@Override
public int getLength() {
- return LENGTH;
+ return u64.getLength();
}
@Override
public OFMetadata applyMask(OFMetadata mask) {
- return OFMetadata.of(this.getValue() & mask.getValue());
+ return OFMetadata.of(this.u64.applyMask(mask.u64));
}
+
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U16.java b/java_gen/pre-written/src/main/java/org/openflow/types/U16.java
index 5884adc..54e72c1 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U16.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U16.java
@@ -17,7 +17,12 @@
package org.openflow.types;
-public class U16 {
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.exceptions.OFParseError;
+import org.openflow.protocol.OFMessageReader;
+import org.openflow.protocol.Writeable;
+
+public class U16 implements Writeable, OFValueType<U16> {
public static int f(final short i) {
return i & 0xffff;
}
@@ -25,4 +30,79 @@
public static short t(final int l) {
return (short) l;
}
+
+ private final short raw;
+
+ private U16(short raw) {
+ this.raw = raw;
+ }
+
+ public static final U16 of(int value) {
+ return new U16(t(value));
+ }
+
+ public static final U16 ofRaw(short value) {
+ return new U16(value);
+ }
+
+ public int getValue() {
+ return f(raw);
+ }
+
+ public short getRaw() {
+ return raw;
+ }
+
+ @Override
+ public String toString() {
+ return "" + f(raw);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + raw;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ U16 other = (U16) obj;
+ if (raw != other.raw)
+ return false;
+ return true;
+ }
+
+
+ @Override
+ public void writeTo(ChannelBuffer bb) {
+ bb.writeShort(raw);
+ }
+
+
+ public final static Reader READER = new Reader();
+
+ private static class Reader implements OFMessageReader<U16> {
+ @Override
+ public U16 readFrom(ChannelBuffer bb) throws OFParseError {
+ return ofRaw(bb.readShort());
+ }
+ }
+
+ @Override
+ public int getLength() {
+ return 2;
+ }
+
+ @Override
+ public U16 applyMask(U16 mask) {
+ return ofRaw( (short) (raw & mask.raw));
+ }
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U32.java b/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
index 527e778..9cd181c 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U32.java
@@ -22,7 +22,7 @@
import org.openflow.protocol.OFMessageReader;
import org.openflow.protocol.Writeable;
-public class U32 implements Writeable {
+public class U32 implements Writeable, OFValueType<U32> {
private final int raw;
private U32(int raw) {
@@ -69,6 +69,7 @@
U32 other = (U32) obj;
if (raw != other.raw)
return false;
+
return true;
}
@@ -94,4 +95,14 @@
}
}
+ @Override
+ public int getLength() {
+ return 4;
+ }
+
+ @Override
+ public U32 applyMask(U32 mask) {
+ return ofRaw(raw & mask.raw);
+ }
+
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
index 7871445..5c69a7c 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U64.java
@@ -19,7 +19,10 @@
import java.math.BigInteger;
-public class U64 {
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.openflow.protocol.Writeable;
+
+public class U64 implements Writeable, OFValueType<U64> {
private static final long UNSIGNED_MASK = 0x7fffffffffffffffL;
private final long raw;
@@ -28,7 +31,11 @@
this.raw = raw;
}
- public static U64 of(final long raw) {
+ public static U64 of(long raw) {
+ return ofRaw(raw);
+ }
+
+ public static U64 ofRaw(final long raw) {
return new U64(raw);
}
@@ -87,4 +94,19 @@
return true;
}
+ @Override
+ public int getLength() {
+ return 8;
+ }
+
+ @Override
+ public U64 applyMask(U64 mask) {
+ return ofRaw(raw & mask.raw);
+ }
+
+ @Override
+ public void writeTo(ChannelBuffer bb) {
+ bb.writeLong(raw);
+ }
+
}
diff --git a/java_gen/pre-written/src/main/java/org/openflow/types/U8.java b/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
index 2bd34bf..c15be0e 100644
--- a/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
+++ b/java_gen/pre-written/src/main/java/org/openflow/types/U8.java
@@ -22,7 +22,7 @@
import org.openflow.protocol.OFMessageReader;
import org.openflow.protocol.Writeable;
-public class U8 implements Writeable {
+public class U8 implements Writeable, OFValueType<U8> {
private final byte raw;
private U8(byte raw) {
@@ -96,4 +96,14 @@
}
}
+ @Override
+ public int getLength() {
+ return 1;
+ }
+
+ @Override
+ public U8 applyMask(U8 mask) {
+ return ofRaw( (byte) (raw & mask.raw));
+ }
+
}
diff --git a/java_gen/pre-written/src/test/java/org/openflow/types/U64Test.java b/java_gen/pre-written/src/test/java/org/openflow/types/U64Test.java
index 16d3d3e..aefd193 100644
--- a/java_gen/pre-written/src/test/java/org/openflow/types/U64Test.java
+++ b/java_gen/pre-written/src/test/java/org/openflow/types/U64Test.java
@@ -11,16 +11,16 @@
@Test
public void testPositiveRaws() {
for(long positive: new long[] { 0, 1, 100, Long.MAX_VALUE }) {
- assertEquals(positive, U64.of(positive).getValue());
- assertEquals(BigInteger.valueOf(positive), U64.of(positive).getBigInteger());
+ assertEquals(positive, U64.ofRaw(positive).getValue());
+ assertEquals(BigInteger.valueOf(positive), U64.ofRaw(positive).getBigInteger());
}
}
@Test
public void testNegativeRaws() {
long minus_1 = 0xFFffFFffFFffFFffL;
- assertEquals(minus_1, U64.of(minus_1).getValue());
- assertEquals(new BigInteger("FFffFFffFFffFFff", 16), U64.of(minus_1).getBigInteger());
- assertEquals(new BigInteger("18446744073709551615"), U64.of(minus_1).getBigInteger());
+ assertEquals(minus_1, U64.ofRaw(minus_1).getValue());
+ assertEquals(new BigInteger("FFffFFffFFffFFff", 16), U64.ofRaw(minus_1).getBigInteger());
+ assertEquals(new BigInteger("18446744073709551615"), U64.ofRaw(minus_1).getBigInteger());
}
}
diff --git a/java_gen/templates/_field_accessors.java b/java_gen/templates/_field_accessors.java
index e8afe47..b64b29b 100644
--- a/java_gen/templates/_field_accessors.java
+++ b/java_gen/templates/_field_accessors.java
@@ -1,6 +1,6 @@
//:: 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"} {
+ public ${prop.java_type.public_type} ${prop.getter_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:
@@ -20,7 +20,7 @@
//:: 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"} {
+ public ${msg.interface.name}.Builder ${prop.setter_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;
diff --git a/java_gen/templates/_imports.java b/java_gen/templates/_imports.java
index 5b86571..a4c564c 100644
--- a/java_gen/templates/_imports.java
+++ b/java_gen/templates/_imports.java
@@ -1,6 +1,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.openflow.protocol.*;
import org.openflow.protocol.action.*;
import org.openflow.protocol.meterband.*;
diff --git a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
index 634c46e..ba739bc 100644
--- a/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
+++ b/java_gen/templates/custom/OFMatchV1Ver10.Builder.java
@@ -71,12 +71,6 @@
}
@Override
- public Match getMatch() {
- // FIXME yotam - please replace with real implementation
- return null;
- }
-
- @Override
public Builder createBuilder() {
return this;
}
diff --git a/java_gen/templates/custom/OFMatchV2Ver11.Builder.java b/java_gen/templates/custom/OFMatchV2Ver11.Builder.java
index 634c46e..ba739bc 100644
--- a/java_gen/templates/custom/OFMatchV2Ver11.Builder.java
+++ b/java_gen/templates/custom/OFMatchV2Ver11.Builder.java
@@ -71,12 +71,6 @@
}
@Override
- public Match getMatch() {
- // FIXME yotam - please replace with real implementation
- return null;
- }
-
- @Override
public Builder createBuilder() {
return this;
}
diff --git a/java_gen/templates/custom/OFMatchV3Ver12.Builder.java b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
index 634c46e..ba739bc 100644
--- a/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
+++ b/java_gen/templates/custom/OFMatchV3Ver12.Builder.java
@@ -71,12 +71,6 @@
}
@Override
- public Match getMatch() {
- // FIXME yotam - please replace with real implementation
- return null;
- }
-
- @Override
public Builder createBuilder() {
return this;
}
diff --git a/java_gen/templates/custom/OFMatchV3Ver13.Builder.java b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
index 2c00a91..81e8d4e 100644
--- a/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
+++ b/java_gen/templates/custom/OFMatchV3Ver13.Builder.java
@@ -71,12 +71,6 @@
}
@Override
- public Match getMatch() {
- // FIXME yotam - please replace with real implementation
- return null;
- }
-
- @Override
public Builder createBuilder() {
return this;
}
diff --git a/java_gen/templates/of_class.java b/java_gen/templates/of_class.java
index 43d9893..bcaf961 100644
--- a/java_gen/templates/of_class.java
+++ b/java_gen/templates/of_class.java
@@ -37,7 +37,7 @@
//:: include("_imports.java", msg=msg)
-class ${impl_class} implements ${msg.interface.name} {
+class ${impl_class} implements ${msg.interface.inherited_declaration()} {
// version: ${version}
private final static byte WIRE_VERSION = ${version.int_version};
//:: if msg.is_fixed_length:
@@ -55,20 +55,29 @@
private final ${prop.java_type.public_type} ${prop.name};
//:: #endfor
+ //:: if msg.data_members:
+ // package private constructor - used by readers, builders, and factory
${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
}
+ //:: else:
+ final static ${impl_class} INSTANCE = new ${impl_class}();
+ // private empty constructor - use shared instance!
+ private ${impl_class}() {
+ }
+ //:: #endif
// Accessors for OF message fields
-//:: include("_field_accessors.java", msg=msg, generate_setters=False, builder=False)
+ //:: include("_field_accessors.java", msg=msg, generate_setters=False, builder=False)
//:: if os.path.exists("%s/custom/%s.java" % (template_dir, msg.name)):
//:: include("custom/%s.java" % msg.name, msg=msg)
//:: #endif
+ //:: if msg.data_members:
public ${msg.interface.name}.Builder createBuilder() {
return new BuilderWithParent(this);
}
@@ -89,7 +98,7 @@
//:: include("_field_accessors.java", msg=msg, generate_setters=True, builder=True)
@Override
- public ${msg.interface.name} getMessage() {
+ public ${msg.interface.name} build() {
return new ${impl_class}(
${",\n ".join(
[ "this.{0}Set ? this.{0} : parentMessage.{0}".format(prop.name)
@@ -112,7 +121,7 @@
//:: include("_field_accessors.java", msg=msg, generate_setters=True, builder=True)
//
@Override
- public ${msg.interface.name} getMessage() {
+ public ${msg.interface.name} build() {
return new ${impl_class}(
${",\n ".join(
[ "this.{0}Set ? this.{0} : {1}.{2}".format(prop.name, impl_class, prop.default_name)
@@ -124,6 +133,13 @@
//:: #endif
}
+ //:: else:
+ // no data members - do not support builder
+ public ${msg.interface.name}.Builder createBuilder() {
+ throw new UnsupportedOperationException("${impl_class} has no mutable properties -- builder unneeded");
+ }
+ //:: #endif
+
final static Reader READER = new Reader();
static class Reader implements OFMessageReader<${msg.interface.name}> {
@@ -132,7 +148,9 @@
int start = bb.readerIndex();
//:: fields_with_length_member = {}
//:: for prop in msg.members:
-//:: if prop.is_data:
+//:: if prop.is_virtual:
+//:: continue
+//:: elif prop.is_data:
${prop.java_type.public_type} ${prop.name} = ${prop.java_type.read_op(version, pub_type=True,
length=fields_with_length_member[prop.c_name] if prop.c_name in fields_with_length_member else None)};
//:: elif prop.is_pad:
@@ -159,10 +177,14 @@
bb.skipBytes(((length + ${msg.align-1})/${msg.align} * ${msg.align} ) - length );
//:: #endif
+ //:: if msg.data_members:
return new ${impl_class}(
${",\n ".join(
[ prop.name for prop in msg.data_members])}
);
+ //:: else:
+ return INSTANCE;
+ //:: #endif
}
}
@@ -180,7 +202,9 @@
//:: if prop.c_name in fields_with_length_member:
int ${prop.name}StartIndex = bb.writerIndex();
//:: #endif
-//:: if prop.is_data:
+//:: if prop.is_virtual:
+//:: continue
+//:: elif prop.is_data:
${prop.java_type.write_op(version, "message." + prop.name, pub_type=True)};
//:: elif prop.is_pad:
// pad: ${prop.length} bytes
diff --git a/java_gen/templates/of_factories.java b/java_gen/templates/of_factories.java
index cce134d..9225510 100644
--- a/java_gen/templates/of_factories.java
+++ b/java_gen/templates/of_factories.java
@@ -40,7 +40,7 @@
switch(version) {
//:: for v in versions:
case ${v.constant_version}:
- return org.openflow.protocol.ver${v.of_version}.OFFactoryVer${v.of_version}.getInstance();
+ return org.openflow.protocol.ver${v.of_version}.OFFactoryVer${v.of_version}.INSTANCE;
//:: #endfor
default:
throw new IllegalArgumentException("Unknown version: "+version);
diff --git a/java_gen/templates/of_factory_class.java b/java_gen/templates/of_factory_class.java
index fec0bcf..e83344b 100644
--- a/java_gen/templates/of_factory_class.java
+++ b/java_gen/templates/of_factory_class.java
@@ -36,25 +36,53 @@
//:: include("_imports.java")
public class ${factory.name} implements ${factory.interface.name} {
+ public final static ${factory.name} INSTANCE = new ${factory.name}();
+ private ${factory.name}() {}
+
+ //:: for name, clazz in factory.interface.sub_factories.items():
+ public ${clazz} ${name}() {
+ return ${clazz}Ver${factory.version.of_version}.INSTANCE;
+ }
+ //:: #endfor
+
//:: for i in factory.interface.members:
//:: if i.is_virtual:
//:: continue
//:: #endif
-//:: if i.has_version(factory.version) and model.generate_class(i.versioned_class(factory.version)):
- public ${i.name}.Builder create${i.name[2:]}Builder() {
+ //:: if len(i.writeable_members) > 0:
+ public ${i.name}.Builder ${factory.interface.method_name(i, builder=True)}() {
+ //:: if i.has_version(factory.version) and model.generate_class(i.versioned_class(factory.version)):
return new ${i.versioned_class(factory.version).name}.Builder();
- }
-//:: else:
- public ${i.name}.Builder create${i.name[2:]}Builder() throws UnsupportedOperationException {
+ //:: else:
throw new UnsupportedOperationException("${i.name} not supported in version ${factory.version}");
+ //:: #endif
}
-//:: #endif
+ //:: #endif
+ //:: if len(i.writeable_members) <= 2:
+ public ${i.name} ${factory.interface.method_name(i, builder=False)}(${", ".join("%s %s" % (p.java_type.public_type, p.name) for p in i.writeable_members)}) {
+ //:: if i.has_version(factory.version) and model.generate_class(i.versioned_class(factory.version)):
+ //:: if len(i.writeable_members) > 0:
+ return new ${i.versioned_class(factory.version).name}(
+ ${",\n ".join(
+ [ prop.name for prop in i.versioned_class(factory.version).data_members])}
+ );
+ //:: else:
+ return ${i.versioned_class(factory.version).name}.INSTANCE;
+ //:: #endif
+ //:: else:
+ throw new UnsupportedOperationException("${i.name} not supported in version ${factory.version}");
+ //:: #endif
+ }
+ //:: #endif
//:: #endfor
- public OFMessageReader<OFMessage> getMessageReader() {
- return OFMessageVer${factory.version.of_version}.READER;
+ public OFMessageReader<${factory.base_class}> getReader() {
+//:: if factory.versioned_base_class:
+ return ${factory.versioned_base_class.name}.READER;
+//:: else:
+ throw new UnsupportedOperationException("Reader<${factory.base_class}> not supported in version ${factory.version}");
+//:: #endif
}
- //:: include("_singleton.java", msg=factory)
}
diff --git a/java_gen/templates/of_factory_interface.java b/java_gen/templates/of_factory_interface.java
index 39432a8..fcb690f 100644
--- a/java_gen/templates/of_factory_interface.java
+++ b/java_gen/templates/of_factory_interface.java
@@ -31,17 +31,27 @@
//:: include('_autogen.java')
-package org.openflow.protocol;
+package ${factory.package};
//:: include("_imports.java")
public interface ${factory.name} {
+ // Subfactories
+//:: for name, clazz in factory.sub_factories.items():
+ ${clazz} ${name}();
+//:: #endfor
+
//:: for i in factory.members:
//:: if i.is_virtual:
//:: continue
//:: #endif
- ${i.name}.Builder create${i.name[2:]}Builder()${ "" if i.is_universal else " throws UnsupportedOperationException"};
+ //:: if len(i.writeable_members) > 0:
+ ${i.name}.Builder ${factory.method_name(i, builder=True)}()${ "" if i.is_universal else " throws UnsupportedOperationException"};
+ //:: #endif
+ //:: if len(i.writeable_members) <= 2:
+ ${i.name} ${factory.method_name(i, builder=False )}(${", ".join("%s %s" % (p.java_type.public_type, p.name) for p in i.writeable_members)});
+ //:: #endif
//:: #endfor
- OFMessageReader<OFMessage> getMessageReader();
+ OFMessageReader<${factory.base_class}> getReader();
}
diff --git a/java_gen/templates/of_interface.java b/java_gen/templates/of_interface.java
index 4dec92f..8ddaba3 100644
--- a/java_gen/templates/of_interface.java
+++ b/java_gen/templates/of_interface.java
@@ -26,6 +26,7 @@
//:: # under the EPL.
//::
//:: import itertools
+//:: import re
//:: import of_g
//:: include('_copyright.java')
@@ -35,20 +36,21 @@
//:: include("_imports.java", msg=msg)
-public interface ${msg.name} extends OFObject${", %s" % msg.parent_interface if msg.parent_interface else ""}{
+public interface ${msg.name}${ "<%s>" % msg.type_annotation if msg.type_annotation else ""} extends OFObject${", %s" % msg.parent_interface if msg.parent_interface else ""}{
//:: for prop in msg.members:
- ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
+ ${prop.java_type.public_type} ${prop.getter_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
//:: #endfor
void writeTo(ChannelBuffer channelBuffer);
- Builder createBuilder();
- public interface Builder ${"extends %s.Builder" % msg.parent_interface if msg.parent_interface else ""} {
- ${msg.name} getMessage();
+ Builder${msg.type_variable} createBuilder();
+ //:: simple_type, annotation = re.match(r'(\w+)(<.*>)?', msg.parent_interface).groups() if msg.parent_interface else ("", "")
+ public interface Builder${ "<%s>" % msg.type_annotation if msg.type_annotation else ""} ${"extends %s.Builder" % simple_type if msg.parent_interface else ""}${annotation if annotation else ""} {
+ ${msg.name}${msg.type_variable} build();
//:: for prop in msg.members:
- ${prop.java_type.public_type} get${prop.title_name}()${ "" if prop.is_universal else " throws UnsupportedOperationException"};
+ ${prop.java_type.public_type} ${prop.getter_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"};
+ Builder ${prop.setter_name}(${prop.java_type.public_type} ${prop.name})${ "" if prop.is_universal else " throws UnsupportedOperationException"};
//:: #endif
//:: #endfor
}
diff --git a/java_gen/templates/of_virtual_class.java b/java_gen/templates/of_virtual_class.java
index f1ac849..fe5c66c 100644
--- a/java_gen/templates/of_virtual_class.java
+++ b/java_gen/templates/of_virtual_class.java
@@ -37,7 +37,7 @@
//:: include("_imports.java", msg=msg)
-abstract class ${msg.name} implements ${msg.interface.name} {
+abstract class ${msg.name} {
// version: ${version}
private final static byte WIRE_VERSION = ${version.int_version};
//:: if msg.is_fixed_length:
@@ -49,7 +49,7 @@
public final static ${msg.name}.Reader READER = new Reader();
- static class Reader implements OFMessageReader<${msg.interface.name}> {
+ static class Reader implements OFMessageReader<${msg.interface.inherited_declaration()}> {
@Override
public ${msg.interface.name} readFrom(ChannelBuffer bb) throws OFParseError {
int start = bb.readerIndex();
diff --git a/java_gen/templates/unit_test.java b/java_gen/templates/unit_test.java
index 45472f2..47dcc24 100644
--- a/java_gen/templates/unit_test.java
+++ b/java_gen/templates/unit_test.java
@@ -55,9 +55,9 @@
//:: if "java" in test_data:
@Test
public void testWrite() {
- ${var_type}.Builder builder = factory.create${var_type[2:]}Builder();
+ ${var_type}.Builder builder = factory.build${var_type[2:]}();
${test_data["java"]};
- ${var_type} ${var_name} = builder.getMessage();
+ ${var_type} ${var_name} = builder.build();
ChannelBuffer bb = ChannelBuffers.dynamicBuffer();
${var_name}.writeTo(bb);
byte[] written = new byte[bb.readableBytes()];
@@ -68,9 +68,9 @@
@Test
public void testRead() throws Exception {
- ${var_type}.Builder builder = factory.create${var_type[2:]}Builder();
+ ${var_type}.Builder builder = factory.build${var_type[2:]}();
${test_data["java"]};
- ${var_type} ${var_name}Built = builder.getMessage();
+ ${var_type} ${var_name}Built = builder.build();
ChannelBuffer input = ChannelBuffers.copiedBuffer(${msg.constant_name}_SERIALIZED);
diff --git a/test_data/of13/flow_add.data b/test_data/of13/flow_add.data
index d01c209..10b3d2f 100644
--- a/test_data/of13/flow_add.data
+++ b/test_data/of13/flow_add.data
@@ -62,11 +62,11 @@
.setOutPort(OFPort.of(6))
.setOutGroup(8)
.setFlags(0)
- .setMatch(factory.createMatchV3Builder().getMessage()) // FIXME: @yotam: replace once we have generic ofmatch
+ .setMatch(factory.buildMatchV3().build()) // FIXME: @yotam: replace once we have generic ofmatch
.setInstructions(
ImmutableList.<OFInstruction>of(
- factory.createInstructionGotoTableBuilder().setTableId((byte) 4).getMessage(),
- factory.createInstructionGotoTableBuilder().setTableId((byte) 7).getMessage()
+ factory.instructions().gotoTable((short) 4),
+ factory.instructions().gotoTable((short) 7)
)
);
diff --git a/test_data/of13/packet_in.data b/test_data/of13/packet_in.data
index 71e17b1..951f212 100644
--- a/test_data/of13/packet_in.data
+++ b/test_data/of13/packet_in.data
@@ -30,6 +30,8 @@
ofp.oxm.in_port_masked(value=4, value_mask=5)]),
data="abc")
-- java
+OFOxms oxms = factory.oxms();
+
builder
.setXid(0x12345678)
.setBufferId(100)
@@ -38,12 +40,12 @@
.setTableId((byte) 20)
.setCookie(U64.parseHex("FEDCBA9876543210"))
.setMatch(
- factory.createMatchV3Builder().setOxmList(
- ImmutableList.of(
- factory.createOxmArpOpBuilder().setValue(1).getMessage(),
- factory.createOxmInPortMaskedBuilder().setValue(OFPort.of(4)).setValueMask(OFPort.of(5)).getMessage()
+ factory.buildMatchV3().setOxmList(
+ OFOxmList.of(
+ oxms.arpOp(ArpOpcode.ARP_OPCODE_REQUEST),
+ oxms.inPortMasked(OFPort.of(4), OFPort.of(5))
)
- ).getMessage()
+ ).build()
)
.setData(new byte[] { 97, 98, 99 } );