Support allowed_address_pairs

Change-Id: Id897c1833e18d1b3885394159f6beae240b3f52b
diff --git a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java
index f9a5916..a7ae7cb 100644
--- a/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java
+++ b/apps/openstackswitching/api/src/main/java/org/onosproject/openstackswitching/OpenstackPort.java
@@ -15,12 +15,14 @@
  */
 package org.onosproject.openstackswitching;
 
+import com.google.common.collect.Maps;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.Map;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -38,8 +40,7 @@
 
     private PortStatus status;
     private String name;
-    // FIX_ME
-    private String allowedAddressPairs;
+    private Map<IpAddress, MacAddress> allowedAddressPairs;
     private boolean adminStateUp;
     private String networkId;
     private String tenantId;
@@ -51,13 +52,13 @@
     private Collection<String> securityGroups;
     private String deviceId;
 
-    private OpenstackPort(PortStatus status, String name, boolean adminStateUp,
-                          String networkId, String tenantId, String deviceOwner,
-                          MacAddress macAddress, HashMap fixedIps, String id,
-                          Collection<String> securityGroups, String deviceId) {
-
+    private OpenstackPort(PortStatus status, String name, Map<IpAddress, MacAddress> allowedAddressPairs,
+                          boolean adminStateUp, String networkId, String tenantId,
+                          String deviceOwner, MacAddress macAddress, HashMap fixedIps,
+                          String id, Collection<String> securityGroups, String deviceId) {
         this.status = status;
         this.name = name;
+        this.allowedAddressPairs = checkNotNull(allowedAddressPairs);
         this.adminStateUp = adminStateUp;
         this.networkId = checkNotNull(networkId);
         this.tenantId = checkNotNull(tenantId);
@@ -99,6 +100,15 @@
     }
 
     /**
+     * Returns allowed address pairs.
+     *
+     * @return map of ip address and mac address, or empty map
+     */
+    public Map<IpAddress, MacAddress> allowedAddressPairs() {
+        return allowedAddressPairs;
+    }
+
+    /**
      * Returns whether admin state up or not.
      *
      * @return true if admin state up, false otherwise
@@ -170,27 +180,6 @@
         return deviceId;
     }
 
-    // TODO : Implement the following functions when necessary
-    //@Override
-    //public void equals(Object that) {
-    //
-    //}
-    //
-    //@Override
-    //public int hashCode() {
-    //
-    //}
-
-    @Override
-    public Object clone() {
-        OpenstackPort op = new OpenstackPort(this.status, this.name, this.adminStateUp,
-                this.networkId, this.tenantId, this.deviceOwner, this.macAddress,
-                (HashMap) this.fixedIps.clone(), this.id,
-                Collections.unmodifiableCollection(this.securityGroups), this.deviceId);
-
-        return op;
-    }
-
     /**
      * OpenstackPort Builder class.
      */
@@ -198,8 +187,7 @@
 
         private PortStatus status;
         private String name;
-        // FIX_ME
-        private String allowedAddressPairs;
+        private Map<IpAddress, MacAddress> allowedAddressPairs;
         private boolean adminStateUp;
         private String networkId;
         private String tenantId;
@@ -212,7 +200,8 @@
         private String deviceId;
 
         Builder() {
-            fixedIps = new HashMap<>();
+            fixedIps = Maps.newHashMap();
+            allowedAddressPairs = Maps.newHashMap();
         }
 
         /**
@@ -240,6 +229,17 @@
         }
 
         /**
+         * Sets allowed address pairs.
+         *
+         * @param addrPairs map of ip address and mac address
+         * @return Builder object
+         */
+        public Builder allowedAddressPairs(Map<IpAddress, MacAddress> addrPairs) {
+            this.allowedAddressPairs.putAll(addrPairs);
+            return this;
+        }
+
+        /**
          * Sets whether admin state up or not.
          *
          * @param isAdminStateUp true if admin state is up, false otherwise
@@ -352,8 +352,9 @@
          * @return OpenstackPort objecet
          */
         public OpenstackPort build() {
-            return new OpenstackPort(status, name, adminStateUp, networkId, networkId,
-                    deviceOwner, macAddress, fixedIps, id, securityGroups, deviceId);
+            return new OpenstackPort(status, name, allowedAddressPairs, adminStateUp,
+                                     networkId, networkId, deviceOwner, macAddress, fixedIps,
+                                     id, securityGroups, deviceId);
         }
     }
 }
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java
index 99f1f80..b29b389 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortCodec.java
@@ -19,7 +19,9 @@
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
@@ -29,6 +31,7 @@
 
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Encodes and decodes the OpenstackPort.
@@ -54,6 +57,7 @@
     private static final String ID = "id";
     private static final String SECURITY_GROUPS = "security_groups";
     private static final String DEVICE_ID = "device_id";
+    private static final String NA = "N/A";
 
     @Override
     public OpenstackPort decode(ObjectNode json, CodecContext context) {
@@ -86,9 +90,19 @@
         securityGroupList.forEach(securityGroup -> securityGroupIdList.add(securityGroup.asText()));
         String deviceId = portInfo.path(DEVICE_ID).asText();
 
+        Map<IpAddress, MacAddress> addressPairs = Maps.newHashMap();
+        for (JsonNode addrPair : (ArrayNode) portInfo.path(ADDRESS_PAIR)) {
+            try {
+                addressPairs.put(IpAddress.valueOf(addrPair.path(IP_ADDRESS).asText()),
+                                 MacAddress.valueOf(addrPair.path(MAC_ADDRESS).asText()));
+            } catch (IllegalArgumentException e) {
+                log.debug("Invalid address pair {}", addrPair.toString());
+            }
+        }
+
         OpenstackPort.Builder openstackPortBuilder = OpenstackPort.builder();
         OpenstackPort.PortStatus portStatus =
-                status.equals("N/A") ? OpenstackPort.PortStatus.NA :
+                status.equals(NA) ? OpenstackPort.PortStatus.NA :
                         OpenstackPort.PortStatus.valueOf(status);
 
         openstackPortBuilder.portStatus(portStatus)
@@ -103,6 +117,9 @@
                 .deviceId(deviceId)
                 .securityGroup(securityGroupIdList);
 
+        if (!addressPairs.isEmpty()) {
+            openstackPortBuilder.allowedAddressPairs(addressPairs);
+        }
 
         OpenstackPort openstackPort = openstackPortBuilder.build();