Merge "BUG 1839 - HTTP delete of non existing data"
[controller.git] / opendaylight / sal / api / src / main / java / org / opendaylight / controller / sal / match / Match.java
index 30c25af57f688539c7bf569aa4ecccf0f804af26..a00c3dcb3422d6e20c619bd35d616b62fb6bbab3 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
  *
@@ -15,17 +14,22 @@ import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.IPProtocols;
 import org.opendaylight.controller.sal.utils.NetUtils;
@@ -51,7 +55,9 @@ public class Match implements Cloneable, Serializable {
         reversableMatches = Collections.unmodifiableMap(map);
     }
     private Map<MatchType, MatchField> fields;
-    private int matches; // concise way to tell which fields the match is set for (may remove if not needed)
+    private int matches; // concise way to tell which fields the match
+                         // is set for (may remove if not needed)
+    private ConcurrentMap<String, Property> props;
 
     public Match() {
         fields = new HashMap<MatchType, MatchField>();
@@ -63,6 +69,81 @@ public class Match implements Cloneable, Serializable {
         matches = match.matches;
     }
 
+    /**
+     * Gets the list of metadata currently registered with this match
+     *
+     * @return List of metadata currently registered
+     */
+    public List <Property> getMetadatas() {
+        if (this.props != null) {
+            // Return all the values in the map
+            Collection res = this.props.values();
+            if (res == null) {
+                return Collections.emptyList();
+            }
+            return new ArrayList<Property>(res);
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * Gets the metadata registered with a name if present
+     *
+     * @param name the name of the property to be extracted
+     *
+     * @return List of metadata currently registered
+     */
+    public Property getMetadata(String name) {
+        if (name == null) {
+            return null;
+        }
+        if (this.props != null) {
+            // Return the Property associated to the name
+            return this.props.get(name);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the metadata associated to a name. If the name or prop is NULL,
+     * an exception NullPointerException will be raised.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     */
+    public void setMetadata(String name, Property prop) {
+        if (this.props == null) {
+            props = new ConcurrentHashMap<String, Property>();
+        }
+
+        if (this.props != null) {
+            this.props.put(name, prop);
+        }
+    }
+
+    /**
+     * Remove the metadata associated to a name. If the name is NULL,
+     * nothing will be removed.
+     *
+     * @param name the name of the property to be set
+     * @param prop, property to be set
+     *
+     * @return List of metadata currently registered
+     */
+    public void removeMetadata(String name) {
+        if (this.props == null) {
+            return;
+        }
+
+        if (this.props != null) {
+            this.props.remove(name);
+        }
+        // It's intentional to keep the this.props still allocated
+        // till the parent data structure will be alive, so to avoid
+        // unnecessary allocation/deallocation, even if it's holding
+        // nothing
+    }
+
     /**
      * Generic setter for frame/packet/message's header fields against which to match
      * Note: For MAC addresses, please pass the cloned value to this function
@@ -354,7 +435,7 @@ public class Match implements Cloneable, Serializable {
                         .getSubnetMaskLength(thisMask);
                 int otherMaskLen = (otherMask == null) ? ((otherAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
                         .getSubnetMaskLength(otherMask);
-                if (otherMaskLen < thisMaskLen) {
+                if (thisMaskLen < otherMaskLen) {
                     intersection.setField(new MatchField(type, NetUtils.getSubnetPrefix(otherAddress, otherMaskLen),
                             otherMask));
                 } else {
@@ -441,7 +522,20 @@ public class Match implements Cloneable, Serializable {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((fields == null) ? 0 : fields.hashCode());
+        if (this.fields == null) {
+            result = prime * result;
+        } else {
+            // use a tree map as the order of hashMap is not guaranteed.
+            // 2 Match objects with fields in different order are still equal.
+            // Hence the hashCode should be the same too.
+            TreeMap<MatchType, MatchField> tm = new TreeMap<MatchType, MatchField>(this.fields);
+            for (MatchType field : tm.keySet()) {
+                MatchField f = tm.get(field);
+                int fieldHashCode = (field==null ? 0 : field.calculateConsistentHashCode()) ^
+                             (f==null ? 0 : f.hashCode());
+                result = prime * result + fieldHashCode;
+            }
+        }
         result = prime * result + matches;
         return result;
     }
@@ -473,6 +567,13 @@ public class Match implements Cloneable, Serializable {
 
     @Override
     public String toString() {
-        return "Match[" + fields.values() + "]";
+        StringBuilder builder = new StringBuilder();
+        builder.append("Match [fields=");
+        builder.append(fields);
+        builder.append(", matches=");
+        builder.append(matches);
+        builder.append("]");
+        return builder.toString();
     }
+
 }