Added NASId, IP Address for a device and auto pick data from external or ONOS configuration

Change-Id: Ib3ecd911c43dd1cd0d03cef3916b1e513f9bbdaf
diff --git a/src/main/java/org/opencord/sadis/SadisConfig.java b/src/main/java/org/opencord/sadis/SadisConfig.java
index ab6128d..fd9689f 100644
--- a/src/main/java/org/opencord/sadis/SadisConfig.java
+++ b/src/main/java/org/opencord/sadis/SadisConfig.java
@@ -22,6 +22,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.config.Config;
@@ -58,7 +59,9 @@
  *             "nasportid"          : string,
  *             "port"               : int,
  *             "slot"               : int,
- *             "hardwareidentifier" : string
+ *             "hardwareidentifier" : string,
+ *             "ipAddress"          : string,
+ *             "nasId"              : string
  *         }, ...
  *     ]
  * }
@@ -151,6 +154,7 @@
         ObjectMapper mapper = new ObjectMapper();
         SimpleModule module = new SimpleModule();
         module.addDeserializer(VlanId.class, new VlanIdDeserializer());
+        module.addDeserializer(Ip4Address.class, new Ip4AddressDeserializer());
         mapper.registerModule(module);
         final JsonNode entries = this.object.path(SADIS_ENTRIES);
         entries.forEach(entry -> {
@@ -173,4 +177,14 @@
             return VlanId.vlanId((short) node.asInt());
         }
     }
+
+    public class Ip4AddressDeserializer extends JsonDeserializer<Ip4Address> {
+        @Override
+        public Ip4Address deserialize(JsonParser jp, DeserializationContext ctxt)
+                throws IOException, JsonProcessingException {
+            ObjectCodec oc = jp.getCodec();
+            JsonNode node = oc.readTree(jp);
+            return Ip4Address.valueOf((String) node.asText());
+        }
+    }
 }
diff --git a/src/main/java/org/opencord/sadis/SadisManager.java b/src/main/java/org/opencord/sadis/SadisManager.java
index 7d060c3..e638d9e 100644
--- a/src/main/java/org/opencord/sadis/SadisManager.java
+++ b/src/main/java/org/opencord/sadis/SadisManager.java
@@ -102,6 +102,8 @@
         this.log.info("Cache Mac Size: {}", cfg.getCacheMaxSize());
         this.log.info("Cache TTL:      {}", cfg.getCacheTtl().getSeconds());
         this.log.info("Entries:        {}", cfg.getEntries());
+
+        configure(cfg);
     }
 
     /**
diff --git a/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java b/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
index 72cbfa0..266f25a 100644
--- a/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
+++ b/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformation.java
@@ -15,6 +15,7 @@
  */
 package org.opencord.sadis;
 
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
@@ -38,14 +39,20 @@
     String nasPortId;
 
     @JsonProperty(value = "port")
-    int port;
+    int port = -1;
 
     @JsonProperty(value = "slot")
-    int slot;
+    int slot = -1;
 
     @JsonProperty(value = "hardwareIdentifier")
     MacAddress hardwareIdentifier;
 
+    @JsonProperty(value = "ipAddress")
+    Ip4Address ipAddress;
+
+    @JsonProperty(value = "nasId")
+    String nasId;
+
     SubscriberAndDeviceInformation() {
     }
 
@@ -105,6 +112,21 @@
         this.hardwareIdentifier = hardwareIdentifier;
     }
 
+    public final Ip4Address ipAddress() {
+        return this.ipAddress;
+    }
+
+    public final void setIPAddress(final Ip4Address ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public final String nasId() {
+        return this.nasId;
+    }
+
+    public final void setNasId(final String nasId) {
+        this.nasId = nasId;
+    }
     /*
      * (non-Javadoc)
      *
@@ -121,6 +143,8 @@
         result = prime * result + this.port;
         result = prime * result + (this.sTag == null ? 0 : this.sTag.hashCode());
         result = prime * result + this.slot;
+        result = prime * result + (this.ipAddress == null ? 0 : this.ipAddress.hashCode());
+        result = prime * result + (this.nasId == null ? 0 : this.nasId.hashCode());
         return result;
     }
 
@@ -169,6 +193,20 @@
         } else if (!this.nasPortId.equals(other.nasPortId)) {
             return false;
         }
+        if (this.nasId == null) {
+            if (other.nasId != null) {
+                return false;
+            }
+        } else if (!this.nasId.equals(other.nasId)) {
+            return false;
+        }
+        if (this.ipAddress == null) {
+            if (other.ipAddress != null) {
+                return false;
+            }
+        } else if (!this.ipAddress.equals(other.ipAddress())) {
+            return false;
+        }
         if (this.port != other.port) {
             return false;
         }
@@ -208,6 +246,10 @@
         buf.append(this.slot);
         buf.append(",hardwareIdentifier:");
         buf.append(this.hardwareIdentifier);
+        buf.append(",ipaddress:");
+        buf.append(this.ipAddress);
+        buf.append(",nasId:");
+        buf.append(this.nasId);
         buf.append(']');
 
         return buf.toString();
diff --git a/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformationAdapter.java b/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformationAdapter.java
index c131704..56e60c5 100644
--- a/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformationAdapter.java
+++ b/src/main/java/org/opencord/sadis/SubscriberAndDeviceInformationAdapter.java
@@ -17,14 +17,24 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.Maps;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 
 public abstract class SubscriberAndDeviceInformationAdapter implements SubscriberAndDeviceInformationService {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
     private static final int DEFAULT_MAXIMUM_CACHE_SIZE = 0;
     private static final long DEFAULT_TTL = 0;
 
@@ -33,17 +43,46 @@
     private int maxiumCacheSize = DEFAULT_MAXIMUM_CACHE_SIZE;
     private long cacheEntryTtl = DEFAULT_TTL;
 
+    private Map<String, SubscriberAndDeviceInformation> localCfgData = null;
+
     public SubscriberAndDeviceInformationAdapter() {
         cache = CacheBuilder.newBuilder().maximumSize(maxiumCacheSize)
                 .expireAfterAccess(cacheEntryTtl, TimeUnit.SECONDS).build();
     }
 
-    public void configure(String url, int maximumCacheSeize, long cacheEntryTtl) {
+    /**
+     * Configures the Adapter for data source and cache parameters.
+     *
+     * @param cfg Configuration data.
+     */
+    public void configure(SadisConfig cfg) {
+        String url = null;
+        try {
+            // if the url is not present then assume data is in netcfg
+            if (cfg.getUrl() != null) {
+                url = cfg.getUrl().toString();
+            } else {
+                localCfgData = Maps.newConcurrentMap();
+
+                cfg.getEntries().forEach(entry -> {
+                    localCfgData.put(entry.id(), entry);
+                });
+                log.info("url is null, data source is local netcfg data");
+            }
+        } catch (MalformedURLException mUrlEx) {
+            log.error("Invalid URL specified: {}", mUrlEx);
+        }
+
+        int maximumCacheSeize = cfg.getCacheMaxSize();
+        long cacheEntryTtl = cfg.getCacheTtl().getSeconds();
+
         // Rebuild cache if needed
-        if (url != this.url || maximumCacheSeize != this.maxiumCacheSize || cacheEntryTtl != this.cacheEntryTtl) {
-            this.url = url;
+        if ((url != null && url != this.url) || maximumCacheSeize != this.maxiumCacheSize ||
+                cacheEntryTtl != this.cacheEntryTtl) {
             this.maxiumCacheSize = maximumCacheSeize;
             this.cacheEntryTtl = cacheEntryTtl;
+            this.url = url;
+
             Cache<String, SubscriberAndDeviceInformation> newCache = CacheBuilder.newBuilder()
                     .maximumSize(maxiumCacheSize).expireAfterAccess(cacheEntryTtl, TimeUnit.SECONDS).build();
             Cache<String, SubscriberAndDeviceInformation> oldCache = cache;
@@ -89,29 +128,35 @@
 
         /*
          * Not in cache, if we have a URL configured we can attempt to get it
-         * from there.
+         * from there, else check for it in the locally configured data
          */
         if (this.url == null) {
-            return null;
-        }
+            info = localCfgData.get(id);
 
-        // Augment URL with query parameters
-        StringBuilder buf = new StringBuilder(this.url);
-        if (buf.charAt(buf.length() - 1) != '/') {
-            buf.append('/');
-        }
+            if (info != null) {
+                local.put(id, info);
+                return info;
+            }
+        } else {
+            // Augment URL with query parameters
+            StringBuilder buf = new StringBuilder(this.url);
+            if (buf.charAt(buf.length() - 1) != '/') {
+                buf.append('/');
+            }
 
-        buf.append(id);
+            buf.append(id);
 
-        try (InputStream io = new URL(buf.toString()).openStream()) {
-            ObjectMapper mapper = new ObjectMapper();
-            info = mapper.readValue(io, SubscriberAndDeviceInformation.class);
-            local.put(id, info);
-            return info;
-        } catch (IOException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            try (InputStream io = new URL(buf.toString()).openStream()) {
+                ObjectMapper mapper = new ObjectMapper();
+                info = mapper.readValue(io, SubscriberAndDeviceInformation.class);
+                local.put(id, info);
+                return info;
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
         }
+        log.error("Data not found for id {}", id);
         return null;
     }
 }
diff --git a/src/main/resources/config.json b/src/main/resources/config.json
index e01da23..eff6202 100644
--- a/src/main/resources/config.json
+++ b/src/main/resources/config.json
@@ -19,7 +19,9 @@
 			"nasPortId": "1/1/2",
 			"port": 125,
 			"slot": 3,
-			"hardwareIdentifier": "aa:bb:cc:dd:ee:ff"
+			"hardwareIdentifier": "aa:bb:cc:dd:ee:ff",
+			"ipAddress":"10.10.10.10",
+			"nasId":"XXX-NASID"
 		},
 
 		{
@@ -29,7 +31,16 @@
 			"nasPortId": "1/1/2",
 			"port": 129,
 			"slot": 4,
-			"hardwareIdentifier": "aa:bb:cc:dd:ee:ff"
+			"hardwareIdentifier": "aa:bb:cc:dd:ee:ff",
+			"ipAddress":"1.1.1.1",
+			"nasId":"YYY-NASID"
+		},
+
+		{
+			"id": "cc:dd:ee:ff:aa:bb",
+			"hardwareIdentifier": "cc:dd:ee:ff:aa:bb",
+			"ipAddress":"12.12.12.12",
+			"nasId":"CCC-NASID"
 		}
 	]
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/opencord/sadis/SadisManagerTest.java b/src/test/java/org/opencord/sadis/SadisManagerTest.java
index cf0f2e6..0ea58bb 100644
--- a/src/test/java/org/opencord/sadis/SadisManagerTest.java
+++ b/src/test/java/org/opencord/sadis/SadisManagerTest.java
@@ -27,6 +27,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.ApplicationId;
@@ -77,11 +78,14 @@
         assertEquals(50, config.getCacheMaxSize());
         assertEquals(Duration.parse("PT1m"), config.getCacheTtl());
         List<SubscriberAndDeviceInformation> entries = config.getEntries();
-        assertEquals(2, entries.size());
+        assertEquals(3, entries.size());
         assertEquals(SubscriberAndDeviceInformationBuilder.build("1", (short) 2, (short) 2, "1/1/2", (short) 125,
-                (short) 3, "aa:bb:cc:dd:ee:ff"), entries.get(0));
+                (short) 3, "aa:bb:cc:dd:ee:ff", "XXX-NASID", "10.10.10.10"), entries.get(0));
         assertEquals(SubscriberAndDeviceInformationBuilder.build("2", (short) 4, (short) 4, "1/1/2", (short) 129,
-                (short) 4, "aa:bb:cc:dd:ee:ff"), entries.get(1));
+                (short) 4, "aa:bb:cc:dd:ee:ff", "YYY-NASID", "1.1.1.1"), entries.get(1));
+        assertEquals(SubscriberAndDeviceInformationBuilder.build("cc:dd:ee:ff:aa:bb", (short) -1, (short) -1, null,
+                (short) -1,
+                (short) -1, "cc:dd:ee:ff:aa:bb", "CCC-NASID", "12.12.12.12"), entries.get(2));
 
     }
 
@@ -90,15 +94,25 @@
     private static final class SubscriberAndDeviceInformationBuilder extends SubscriberAndDeviceInformation {
 
         public static SubscriberAndDeviceInformation build(String id, short cTag, short sTag, String nasPortId,
-                short port, short slot, String mac) {
+                short port, short slot, String mac, String nasId, String ipAddress) {
             SubscriberAndDeviceInformation info = new SubscriberAndDeviceInformation();
             info.setId(id);
-            info.setCTag(VlanId.vlanId(cTag));
-            info.setSTag(VlanId.vlanId(sTag));
+            if (cTag != -1) {
+                info.setCTag(VlanId.vlanId(cTag));
+            }
+            if (sTag != -1) {
+                info.setSTag(VlanId.vlanId(sTag));
+            }
             info.setNasPortId(nasPortId);
-            info.setPort(port);
-            info.setSlot(slot);
+            if (port != -1) {
+                info.setPort(port);
+            }
+            if (slot != -1) {
+                info.setSlot(slot);
+            }
             info.setHardwareIdentifier(MacAddress.valueOf(mac));
+            info.setIPAddress(Ip4Address.valueOf(ipAddress));
+            info.setNasId(nasId);
             return info;
         }
     }