Implement multiton support for primitives accessed via primitive getters

Change-Id: Ib5eda427f29336c0496780f36a70f9a24ed838ea
diff --git a/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java b/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java
index 4d528e2..8ead51c 100644
--- a/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/store/service/StorageServiceAdapter.java
@@ -70,6 +70,16 @@
     }
 
     @Override
+    public AsyncAtomicCounter getAsyncAtomicCounter(String name) {
+        return null;
+    }
+
+    @Override
+    public AsyncAtomicIdGenerator getAsyncAtomicIdGenerator(String name) {
+        return null;
+    }
+
+    @Override
     public <E> WorkQueue<E> getWorkQueue(String name, Serializer serializer) {
         return null;
     }
diff --git a/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java b/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java
index ab5f2ee..c18457b 100644
--- a/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java
+++ b/core/api/src/test/java/org/onosproject/store/service/TestStorageService.java
@@ -59,6 +59,16 @@
     }
 
     @Override
+    public AsyncAtomicCounter getAsyncAtomicCounter(String name) {
+        return atomicCounterBuilder().withName(name).build();
+    }
+
+    @Override
+    public AsyncAtomicIdGenerator getAsyncAtomicIdGenerator(String name) {
+        return atomicIdGeneratorBuilder().withName(name).build();
+    }
+
+    @Override
     public <T> Topic<T> getTopic(String name, Serializer serializer) {
         return new TestTopic(name);
     }
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DistributedPrimitiveManager.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DistributedPrimitiveManager.java
new file mode 100644
index 0000000..bddae9b
--- /dev/null
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DistributedPrimitiveManager.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.store.primitives.impl;
+
+import java.util.Map;
+import java.util.function.Function;
+
+import com.google.common.collect.Maps;
+import org.onosproject.store.primitives.DistributedPrimitiveCreator;
+import org.onosproject.store.service.AsyncAtomicCounter;
+import org.onosproject.store.service.AsyncAtomicIdGenerator;
+import org.onosproject.store.service.AsyncAtomicValue;
+import org.onosproject.store.service.AsyncConsistentMultimap;
+import org.onosproject.store.service.AsyncConsistentTreeMap;
+import org.onosproject.store.service.AsyncDocumentTree;
+import org.onosproject.store.service.DistributedPrimitive;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.Topic;
+import org.onosproject.store.service.WorkQueue;
+
+/**
+ * Primitive instance manager.
+ */
+public class DistributedPrimitiveManager {
+    private final Map<String, DistributedPrimitive> primitives = Maps.newConcurrentMap();
+    private final DistributedPrimitiveCreator primitiveCreator;
+
+    DistributedPrimitiveManager(DistributedPrimitiveCreator primitiveCreator) {
+        this.primitiveCreator = primitiveCreator;
+    }
+
+    /**
+     * Returns a cached primitive instance.
+     *
+     * @param name    the primitive name
+     * @param factory the primitive factory
+     * @param <T>     the primitive type
+     * @return the primitive instance
+     */
+    @SuppressWarnings("unchecked")
+    private <T extends DistributedPrimitive> T getPrimitive(String name, Function<String, T> factory) {
+        return (T) primitives.computeIfAbsent(name, factory);
+    }
+
+    /**
+     * Returns an instance of {@code AsyncAtomicCounter} with specified name.
+     * @param name counter name
+     *
+     * @return AsyncAtomicCounter instance
+     */
+    public AsyncAtomicCounter getAsyncAtomicCounter(String name) {
+        return getPrimitive(name, primitiveCreator::newAsyncCounter);
+    }
+
+    /**
+     * Returns an instance of {@code AsyncAtomicIdGenerator} with specified name.
+     *
+     * @param name ID generator name
+     * @return AsyncAtomicIdGenerator instance
+     */
+    public AsyncAtomicIdGenerator getAsyncAtomicIdGenerator(String name) {
+        return getPrimitive(name, primitiveCreator::newAsyncIdGenerator);
+    }
+
+    /**
+     * Returns an instance of {@code WorkQueue} with specified name.
+     *
+     * @param <E> work element type
+     * @param name work queue name
+     * @param serializer serializer
+     * @return WorkQueue instance
+     */
+    public <E> WorkQueue<E> getWorkQueue(String name, Serializer serializer) {
+        return getPrimitive(name, n -> primitiveCreator.newWorkQueue(n, serializer));
+    }
+
+    /**
+     * Returns an instance of {@code AsyncDocumentTree} with specified name.
+     *
+     * @param <V> tree node value type
+     * @param name document tree name
+     * @param serializer serializer
+     * @return AsyncDocumentTree instance
+     */
+    public <V> AsyncDocumentTree<V> getDocumentTree(String name, Serializer serializer) {
+        return getPrimitive(name, n -> primitiveCreator.newAsyncDocumentTree(n, serializer));
+    }
+
+    /**
+     * Returns a set backed instance of {@code AsyncConsistentMultimap} with
+     * the specified name.
+     *
+     * @param name       the multimap name
+     * @param serializer serializer
+     * @param <K>        key type
+     * @param <V>        value type
+     * @return set backed {@code AsyncConsistentMultimap} instance
+     */
+    public <K, V> AsyncConsistentMultimap<K, V> getAsyncSetMultimap(String name, Serializer serializer) {
+        return getPrimitive(name, n -> primitiveCreator.newAsyncConsistentSetMultimap(n, serializer));
+    }
+
+    /**
+     * Returns an instance of {@code AsyncConsistentTreeMap} with the specified
+     * name.
+     *
+     * @param name the treemap name
+     * @param serializer serializer
+     * @param <V> value type
+     * @return set backed {@code AsyncConsistentTreeMap} instance
+     */
+    public <V> AsyncConsistentTreeMap<V> getAsyncTreeMap(String name, Serializer serializer) {
+        return getPrimitive(name, n -> primitiveCreator.newAsyncConsistentTreeMap(n, serializer));
+    }
+
+    /**
+     * Returns an instance of {@code Topic} with specified name.
+     *
+     * @param <T> topic message type
+     * @param name topic name
+     * @param serializer serializer
+     *
+     * @return Topic instance
+     */
+    public <T> Topic<T> getTopic(String name, Serializer serializer) {
+        AsyncAtomicValue<T> atomicValue =
+            getPrimitive(name, n -> primitiveCreator.newAsyncAtomicValue("topic-" + n, serializer));
+        return new DefaultDistributedTopic<>(atomicValue);
+    }
+}
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StorageManager.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StorageManager.java
index df54158..64f6c76 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StorageManager.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/StorageManager.java
@@ -41,8 +41,9 @@
 import org.onosproject.store.primitives.PartitionService;
 import org.onosproject.store.primitives.TransactionId;
 import org.onosproject.store.serializers.KryoNamespaces;
-import org.onosproject.store.service.AsyncAtomicValue;
 import org.onosproject.store.service.AsyncDocumentTree;
+import org.onosproject.store.service.AsyncAtomicCounter;
+import org.onosproject.store.service.AsyncAtomicIdGenerator;
 import org.onosproject.store.service.AsyncConsistentMultimap;
 import org.onosproject.store.service.AsyncConsistentTreeMap;
 import org.onosproject.store.service.AtomicCounterBuilder;
@@ -101,6 +102,7 @@
             () -> TransactionId.from(UUID.randomUUID().toString());
     private DistributedPrimitiveCreator federatedPrimitiveCreator;
     private TransactionManager transactionManager;
+    private DistributedPrimitiveManager primitiveManager;
 
     @Activate
     public void activate() {
@@ -110,6 +112,7 @@
             .forEach(id -> partitionMap.put(id, partitionService.getDistributedPrimitiveCreator(id)));
         federatedPrimitiveCreator = new FederatedDistributedPrimitiveCreator(partitionMap, BUCKETS);
         transactionManager = new TransactionManager(this, partitionService, BUCKETS);
+        primitiveManager = new DistributedPrimitiveManager(federatedPrimitiveCreator);
         log.info("Started");
     }
 
@@ -147,8 +150,7 @@
     @Override
     public <K, V> ConsistentMultimapBuilder<K, V> consistentMultimapBuilder() {
         checkPermission(STORAGE_WRITE);
-        return new DefaultConsistentMultimapBuilder<K, V>(
-                federatedPrimitiveCreator);
+        return new DefaultConsistentMultimapBuilder<>(federatedPrimitiveCreator);
     }
 
     @Override
@@ -204,31 +206,47 @@
     }
 
     @Override
+    public AsyncAtomicCounter getAsyncAtomicCounter(String name) {
+        checkPermission(STORAGE_WRITE);
+        return primitiveManager.getAsyncAtomicCounter(name);
+    }
+
+    @Override
+    public AsyncAtomicIdGenerator getAsyncAtomicIdGenerator(String name) {
+        checkPermission(STORAGE_WRITE);
+        return primitiveManager.getAsyncAtomicIdGenerator(name);
+    }
+
+    @Override
     public <E> WorkQueue<E> getWorkQueue(String name, Serializer serializer) {
         checkPermission(STORAGE_WRITE);
-        return federatedPrimitiveCreator.newWorkQueue(name, serializer);
+        return primitiveManager.getWorkQueue(name, serializer);
     }
 
     @Override
     public <V> AsyncDocumentTree<V> getDocumentTree(String name, Serializer serializer) {
         checkPermission(STORAGE_WRITE);
-        return federatedPrimitiveCreator.newAsyncDocumentTree(name, serializer);
+        return primitiveManager.getDocumentTree(name, serializer);
     }
 
     @Override
     public <K, V> AsyncConsistentMultimap<K, V> getAsyncSetMultimap(
             String name, Serializer serializer) {
         checkPermission(STORAGE_WRITE);
-        return federatedPrimitiveCreator.newAsyncConsistentSetMultimap(name,
-                                                                serializer);
+        return primitiveManager.getAsyncSetMultimap(name, serializer);
     }
 
     @Override
     public <V> AsyncConsistentTreeMap<V> getAsyncTreeMap(
             String name, Serializer serializer) {
         checkPermission(STORAGE_WRITE);
-        return federatedPrimitiveCreator.newAsyncConsistentTreeMap(name,
-                                                                   serializer);
+        return primitiveManager.getAsyncTreeMap(name, serializer);
+    }
+
+    @Override
+    public <T> Topic<T> getTopic(String name, Serializer serializer) {
+        checkPermission(STORAGE_WRITE);
+        return primitiveManager.getTopic(name, serializer);
     }
 
     @Override
@@ -278,13 +296,4 @@
                     return new MapInfo(name, map.size());
         }).collect(Collectors.toList());
     }
-
-    @Override
-    public <T> Topic<T> getTopic(String name, Serializer serializer) {
-        AsyncAtomicValue<T> atomicValue = this.<T>atomicValueBuilder()
-                                              .withName("topic-" + name)
-                                              .withSerializer(serializer)
-                                              .build();
-        return new DefaultDistributedTopic<>(atomicValue);
-    }
 }
diff --git a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/util/StorageServiceAdapter.java b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/util/StorageServiceAdapter.java
index 4ba8a2c..5c38e27 100644
--- a/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/util/StorageServiceAdapter.java
+++ b/protocols/pcep/server/ctl/src/test/java/org/onosproject/pcelabelstore/util/StorageServiceAdapter.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.pcelabelstore.util;
 
+import org.onosproject.store.service.AsyncAtomicCounter;
+import org.onosproject.store.service.AsyncAtomicIdGenerator;
 import org.onosproject.store.service.AsyncDocumentTree;
 import org.onosproject.store.service.AsyncConsistentMultimap;
 import org.onosproject.store.service.AsyncConsistentTreeMap;
@@ -91,6 +93,16 @@
     }
 
     @Override
+    public AsyncAtomicCounter getAsyncAtomicCounter(String name) {
+        return null;
+    }
+
+    @Override
+    public AsyncAtomicIdGenerator getAsyncAtomicIdGenerator(String name) {
+        return null;
+    }
+
+    @Override
     public <E> WorkQueue<E> getWorkQueue(String name, Serializer serializer) {
         return null;
     }