initial import

Change-Id: Ief25aef0066ea96bd2c329ccef974c072b3a5a73
diff --git a/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java
new file mode 100644
index 0000000..7f66110
--- /dev/null
+++ b/of/lib/src/main/java/org/projectfloodlight/openflow/protocol/OFOxmList.java
@@ -0,0 +1,154 @@
+package org.projectfloodlight.openflow.protocol;
+
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.projectfloodlight.openflow.exceptions.OFParseError;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.match.MatchFields;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.types.OFValueType;
+import org.projectfloodlight.openflow.types.PrimitiveSinkable;
+import org.projectfloodlight.openflow.util.ChannelUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.hash.PrimitiveSink;
+
+public class OFOxmList implements Iterable<OFOxm<?>>, Writeable, PrimitiveSinkable {
+    private static final Logger logger = LoggerFactory.getLogger(OFOxmList.class);
+
+    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 OFOxmList.ofList(oxmMap.values());
+        }
+    }
+
+    @Override
+    public Iterator<OFOxm<?>> iterator() {
+        return oxmMap.values().iterator();
+    }
+
+    public static OFOxmList ofList(Iterable<OFOxm<?>> oxmList) {
+        Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+                MatchFields.class);
+        for (OFOxm<?> o : oxmList) {
+            OFOxm<?> canonical = o.getCanonical();
+
+            if(logger.isDebugEnabled() && !Objects.equal(o, canonical)) {
+                logger.debug("OFOxmList: normalized non-canonical OXM {} to {}", o, canonical);
+            }
+
+            if(canonical != null)
+                map.put(canonical.getMatchField().id, canonical);
+
+        }
+        return new OFOxmList(map);
+    }
+
+    public static OFOxmList of(OFOxm<?>... oxms) {
+        Map<MatchFields, OFOxm<?>> map = new EnumMap<MatchFields, OFOxm<?>>(
+                MatchFields.class);
+        for (OFOxm<?> o : oxms) {
+            OFOxm<?> canonical = o.getCanonical();
+
+            if(logger.isDebugEnabled() && !Objects.equal(o, canonical)) {
+                logger.debug("OFOxmList: normalized non-canonical OXM {} to {}", o, canonical);
+            }
+
+            if(canonical != null)
+                map.put(canonical.getMatchField().id, canonical);
+        }
+        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 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;
+    }
+
+    @Override
+    public void putTo(PrimitiveSink sink) {
+        for (OFOxm<?> o : this) {
+            o.putTo(sink);
+        }
+    }
+
+
+}