[ONOS-6537]  Implement LispRadixTreeDatabase with unit tests

Change-Id: I0d3c016432ad90aeb8843ac3653ec5b54cf6e3bf
diff --git a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispRadixTreeDatabase.java b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispRadixTreeDatabase.java
index 0cb9d9e..0826d24 100644
--- a/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispRadixTreeDatabase.java
+++ b/protocols/lisp/ctl/src/main/java/org/onosproject/lisp/ctl/impl/LispRadixTreeDatabase.java
@@ -15,43 +15,114 @@
  */
 package org.onosproject.lisp.ctl.impl;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.lisp.ctl.impl.tree.IpConcurrentRadixTree;
+import org.onosproject.lisp.msg.protocols.DefaultLispProxyMapRecord.DefaultMapWithProxyBuilder;
 import org.onosproject.lisp.msg.protocols.LispEidRecord;
 import org.onosproject.lisp.msg.protocols.LispMapRecord;
+import org.onosproject.lisp.msg.protocols.LispProxyMapRecord;
+import org.slf4j.Logger;
 
 import java.util.List;
 
+import static org.onosproject.lisp.ctl.impl.util.LispMapUtil.cidrfy;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * A radix tree based LISP mapping database.
  */
-public class LispRadixTreeDatabase implements LispMappingDatabase {
+public final class LispRadixTreeDatabase implements LispMappingDatabase {
+
+    private static final Logger log = getLogger(LispRadixTreeDatabase.class);
+
+    private final IpConcurrentRadixTree<LispProxyMapRecord> radixTree =
+            new IpConcurrentRadixTree<>();
+
+    /**
+     * Prevents object instantiation from external.
+     */
+    private LispRadixTreeDatabase() {
+    }
+
+    /**
+     * Obtains a singleton instance.
+     *
+     * @return singleton instance
+     */
+    public static LispRadixTreeDatabase getInstance() {
+        return SingletonHelper.INSTANCE;
+    }
 
     @Override
     public void putMapRecord(LispEidRecord eid, LispMapRecord rloc,
                              boolean proxyMapReply) {
-        //TODO: requires implementation
+        final LispProxyMapRecord mapWithProxy = new DefaultMapWithProxyBuilder()
+                .withMapRecord(rloc)
+                .withIsProxyMapReply(proxyMapReply)
+                .build();
+        radixTree.put(getIpPrefix(eid), mapWithProxy);
+        log.debug("Inserted a new map record for key {}", eid.toString());
     }
 
     @Override
     public void removeMapRecordByEid(LispEidRecord eid) {
-        //TODO: requires implementation
+        if (radixTree.remove(getIpPrefix(eid))) {
+            log.debug("Removed a map record with key {}", eid.toString());
+        }
     }
 
     @Override
     public void removeAllMapRecords() {
-        //TODO: requires implementation
+        radixTree.clear();
+        log.debug("Clear all map records");
     }
 
     @Override
     public LispMapRecord getMapRecordByEidRecord(LispEidRecord eid,
                                                  boolean proxyMapReply) {
-        //TODO: requires implementation
+        final LispProxyMapRecord record =
+                radixTree.getValueForClosestParentAddress(getIpPrefix(eid));
+        if (record != null && record.isProxyMapReply() == proxyMapReply) {
+            return record.getMapRecord();
+        }
         return null;
     }
 
     @Override
     public List<LispMapRecord> getMapRecordByEidRecords(List<LispEidRecord> eids,
                                                         boolean proxyMapReply) {
-        //TODO: requires implementation
-        return null;
+        final List<LispMapRecord> mapRecords = Lists.newArrayList();
+        eids.parallelStream().forEach(eidRecord -> {
+            final LispMapRecord mapRecord =
+                    getMapRecordByEidRecord(eidRecord, proxyMapReply);
+            if (mapRecord != null) {
+                mapRecords.add(mapRecord);
+            }
+        });
+        return ImmutableList.copyOf(mapRecords);
+    }
+
+    /**
+     * Prevents object instantiation from external.
+     */
+    private static final class SingletonHelper {
+        private static final String ILLEGAL_ACCESS_MSG = "Should not instantiate this class.";
+        private static final LispRadixTreeDatabase INSTANCE = new LispRadixTreeDatabase();
+
+        private SingletonHelper() {
+            throw new IllegalAccessError(ILLEGAL_ACCESS_MSG);
+        }
+    }
+
+    /**
+     * Obtains the IP prefix from LISP EID record.
+     *
+     * @param eidRecord LISP EID record
+     * @return IP prefix object
+     */
+    private IpPrefix getIpPrefix(LispEidRecord eidRecord) {
+        return IpPrefix.valueOf(cidrfy(eidRecord));
     }
 }
diff --git a/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispMappingDatabaseTest.java b/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispMappingDatabaseTest.java
index f8d795d..8eb888d 100644
--- a/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispMappingDatabaseTest.java
+++ b/protocols/lisp/ctl/src/test/java/org/onosproject/lisp/ctl/impl/LispMappingDatabaseTest.java
@@ -57,7 +57,8 @@
     private static final String EID_IP_PREFIX_2_32 = "10.1.2.1";
     private static final String EID_IP_PREFIX_2_24 = "10.1.2.0";
 
-    final LispMappingDatabase mapDb = LispExpireMapDatabase.getInstance();
+    private final LispMappingDatabase expireMapDb = LispExpireMapDatabase.getInstance();
+    private final LispMappingDatabase radixTreeDb = LispRadixTreeDatabase.getInstance();
 
     @Before
     public void setup() {
@@ -126,9 +127,13 @@
         builder3.withRecordTtl(60);
         LispMapRecord mapRecord3 = builder3.build();
 
-        mapDb.putMapRecord(eidRecord1, mapRecord1, true);
-        mapDb.putMapRecord(eidRecord2, mapRecord2, true);
-        mapDb.putMapRecord(eidRecord3, mapRecord3, true);
+        expireMapDb.putMapRecord(eidRecord1, mapRecord1, true);
+        expireMapDb.putMapRecord(eidRecord2, mapRecord2, true);
+        expireMapDb.putMapRecord(eidRecord3, mapRecord3, true);
+
+        radixTreeDb.putMapRecord(eidRecord1, mapRecord1, true);
+        radixTreeDb.putMapRecord(eidRecord2, mapRecord2, true);
+        radixTreeDb.putMapRecord(eidRecord3, mapRecord3, true);
     }
 
     @Test
@@ -136,10 +141,14 @@
         byte cidr32 = (byte) 32;
         LispIpv4Address eid = new LispIpv4Address(IpAddress.valueOf(EID_IP_1));
         LispEidRecord record = new LispEidRecord(cidr32, eid);
-        LispMapRecord mapRecord = mapDb.getMapRecordByEidRecord(record, true);
+        LispMapRecord mapRecord1 = expireMapDb.getMapRecordByEidRecord(record, true);
+        LispMapRecord mapRecord2 = radixTreeDb.getMapRecordByEidRecord(record, true);
 
         assertThat("Failed to fetch the RLOCs with /32 EID record",
-                mapRecord.getLocatorCount(), is(3));
+                mapRecord1.getLocatorCount(), is(3));
+
+        assertThat("Failed to fetch the RLOCs with /32 EID record",
+                mapRecord2.getLocatorCount(), is(3));
     }
 
     @Test
@@ -147,17 +156,24 @@
         byte cidr32 = (byte) 32;
         LispIpv4Address eid = new LispIpv4Address(IpAddress.valueOf(EID_IP_PREFIX_2_32));
         LispEidRecord record32 = new LispEidRecord(cidr32, eid);
-        LispMapRecord mapRecord32 = mapDb.getMapRecordByEidRecord(record32, true);
+        LispMapRecord mapRecordExpireMap32 = expireMapDb.getMapRecordByEidRecord(record32, true);
+        LispMapRecord mapRecordRadixTree32 = radixTreeDb.getMapRecordByEidRecord(record32, true);
 
         byte cidr24 = (byte) 24;
         LispIpv4Address eid24 = new LispIpv4Address(IpAddress.valueOf(EID_IP_PREFIX_2_24));
         LispEidRecord record24 = new LispEidRecord(cidr24, eid24);
-        LispMapRecord mapRecord24 = mapDb.getMapRecordByEidRecord(record24, true);
+        LispMapRecord mapRecordExpireMap24 = expireMapDb.getMapRecordByEidRecord(record24, true);
+        LispMapRecord mapRecordRadixTree24 = radixTreeDb.getMapRecordByEidRecord(record32, true);
 
         assertThat("Failed to fetch the RLOCs with /32 EID record",
-                mapRecord32.getLocatorCount(), is(2));
+                mapRecordExpireMap32.getLocatorCount(), is(2));
         assertThat("Failed to fetch the RLOCs with /24 EID record",
-                mapRecord24.getLocatorCount(), is(2));
+                mapRecordExpireMap24.getLocatorCount(), is(2));
+
+        assertThat("Failed to fetch the RLOCs with /32 EID record",
+                mapRecordRadixTree32.getLocatorCount(), is(2));
+        assertThat("Failed to fetch the RLOCs with /24 EID record",
+                mapRecordRadixTree24.getLocatorCount(), is(2));
     }
 
     @Test
@@ -165,23 +181,33 @@
         byte cidr32 = (byte) 32;
         LispIpv4Address eid = new LispIpv4Address(IpAddress.valueOf(EID_IP_PREFIX_1_32));
         LispEidRecord record32 = new LispEidRecord(cidr32, eid);
-        LispMapRecord mapRecord32 = mapDb.getMapRecordByEidRecord(record32, true);
+        LispMapRecord mapRecordExpireMap32 = expireMapDb.getMapRecordByEidRecord(record32, true);
+        LispMapRecord mapRecordRadixTree32 = radixTreeDb.getMapRecordByEidRecord(record32, true);
 
         byte cidr24 = (byte) 24;
         LispIpv4Address eid24 = new LispIpv4Address(IpAddress.valueOf(EID_IP_PREFIX_1_24));
         LispEidRecord record24 = new LispEidRecord(cidr24, eid24);
-        LispMapRecord mapRecord24 = mapDb.getMapRecordByEidRecord(record24, true);
+        LispMapRecord mapRecordExpireMap24 = expireMapDb.getMapRecordByEidRecord(record24, true);
+        LispMapRecord mapRecordRadixTree24 = radixTreeDb.getMapRecordByEidRecord(record32, true);
 
         byte cidr16 = (byte) 16;
         LispIpv4Address eid16 = new LispIpv4Address(IpAddress.valueOf(EID_IP_PREFIX_1_16));
         LispEidRecord record16 = new LispEidRecord(cidr16, eid16);
-        LispMapRecord mapRecord16 = mapDb.getMapRecordByEidRecord(record16, true);
+        LispMapRecord mapRecordExpireMap16 = expireMapDb.getMapRecordByEidRecord(record16, true);
+        LispMapRecord mapRecordRadixTree16 = radixTreeDb.getMapRecordByEidRecord(record16, true);
 
         assertThat("Failed to fetch the RLOCs with /32 EID record",
-                mapRecord32.getLocatorCount(), is(1));
+                mapRecordExpireMap32.getLocatorCount(), is(1));
         assertThat("Failed to fetch the RLOCs with /24 EID record",
-                mapRecord24.getLocatorCount(), is(1));
+                mapRecordExpireMap24.getLocatorCount(), is(1));
         assertThat("Failed to fetch the RLOCs with /16 EID record",
-                mapRecord16.getLocatorCount(), is(1));
+                mapRecordExpireMap16.getLocatorCount(), is(1));
+
+        assertThat("Failed to fetch the RLOCs with /32 EID record",
+                mapRecordRadixTree32.getLocatorCount(), is(1));
+        assertThat("Failed to fetch the RLOCs with /24 EID record",
+                mapRecordRadixTree24.getLocatorCount(), is(1));
+        assertThat("Failed to fetch the RLOCs with /16 EID record",
+                mapRecordRadixTree16.getLocatorCount(), is(1));
     }
 }