ONOS-6078 Netconf active component and integration with store

Change-Id: Ia80f0123f58a8e872de6ef7bf90bdde24f99d00c
diff --git a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
index aaa3812..060c286 100755
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
@@ -146,25 +146,6 @@
     void deleteNodeRecursive(ResourceId path);
 
     /**
-     * Adds a listener to be notified when a leaf or subtree rooted at the
-     * specified path is modified.
-     *
-     * @param path data structure with absolute path to the node being listened to
-     * @param listener listener to be notified
-     * @throws FailedException if the listener could not be added
-     */
-    void addConfigListener(ResourceId path, DynamicConfigListener listener);
-
-    /**
-     * Removes a previously added listener.
-     *
-     * @param path data structure with absolute path to the node being listened to
-     * @param listener listener to unregister
-     * @throws FailedException if the listener could not be removed
-     */
-    void removeConfigListener(ResourceId path, DynamicConfigListener listener);
-
-    /**
      * Registers an RPC handler.
      *
      * @param handler RPC handler
diff --git a/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java b/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
index 25ddf55..9ea34f2 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
@@ -20,7 +20,6 @@
 import org.onosproject.yang.model.ResourceId;
 import org.onosproject.store.Store;
 
-import java.util.Collection;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -137,32 +136,4 @@
      * {@code FailedException} if the delete request failed
      */
     CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path);
-
-    /**
-     * Adds a listener to be notified when a leaf or subtree rooted at the
-     * specified path is modified.
-     *
-     * @param path data structure with absolute path to the node being listened to
-     * @param listener listener to be notified
-     * @throws FailedException if the listener could not be added
-     */
-    void addConfigListener(ResourceId path, DynamicConfigListener listener);
-
-    /**
-     * Removes a previously added listener.
-     *
-     * @param path data structure with absolute path to the node being listened to
-     * @param listener listener to unregister
-     * @throws FailedException if the listener could not be removed
-     */
-    void removeConfigListener(ResourceId path, DynamicConfigListener listener);
-
-    /**
-     * Returns a collection of previously added listeners.
-     *
-     * @param path data structure with absolute path to the node being listened to
-     * @return  a collection of previously added listeners
-     */
-    Collection<? extends DynamicConfigListener> getConfigListener(ResourceId path);
-    //DynamicConfigListener getConfigListener(ResourceId path);
 }
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java b/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
index 1c63258..094d04c 100644
--- a/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
@@ -24,19 +24,15 @@
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.config.DynamicConfigEvent;
-import org.onosproject.config.DynamicConfigListener;
 import org.onosproject.config.DynamicConfigStore;
 import org.onosproject.config.DynamicConfigStoreDelegate;
 import org.onosproject.config.ResourceIdParser;
 import org.onosproject.config.FailedException;
 import org.onosproject.config.Filter;
-//import org.onosproject.config.cfgreceiver.CfgReceiver;
 import org.onosproject.store.AbstractStore;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.AsyncDocumentTree;
 import org.onosproject.store.service.ConsistentMap;
-import org.onosproject.store.service.ConsistentMapException;
-import org.onosproject.store.service.ConsistentMultimap;
 import org.onosproject.store.service.DocumentPath;
 import org.onosproject.store.service.DocumentTreeEvent;
 import org.onosproject.store.service.DocumentTreeListener;
@@ -58,7 +54,7 @@
 import org.onosproject.yang.model.SchemaId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -82,7 +78,6 @@
     protected StorageService storageService;
     private AsyncDocumentTree<DataNode.Type> keystore;
     private ConsistentMap<String, LeafNode> objectStore;
-    private ConsistentMultimap<String, DynamicConfigListener> lstnrStore;
     private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
     private final MapEventListener<String, LeafNode> olistener = new InternalMapListener();
 
@@ -90,7 +85,6 @@
     public void activateStore() {
         KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
                 .register(KryoNamespaces.BASIC)
-                //.register(String.class)
                 .register(java.lang.Class.class)
                 .register(DataNode.Type.class)
                 .register(LeafNode.class)
@@ -98,8 +92,10 @@
                 .register(ResourceId.class)
                 .register(NodeKey.class)
                 .register(SchemaId.class)
+                .register(LeafListKey.class)
+                .register(ListKey.class)
+                .register(KeyLeaf.class)
                 .register(java.util.LinkedHashMap.class);
-                //.register(CfgReceiver.InternalDynamicConfigListener.class);
         keystore = storageService.<DataNode.Type>documentTreeBuilder()
                 .withSerializer(Serializer.using(kryoBuilder.build()))
                 .withName("config-key-store")
@@ -110,11 +106,6 @@
                 .withName("config-object-store")
                 .withRelaxedReadConsistency()
                 .build();
-        lstnrStore = storageService.<String, DynamicConfigListener>consistentMultimapBuilder()
-                .withSerializer(Serializer.using(kryoBuilder.build()))
-                .withName("config-listener-registry")
-                .withRelaxedReadConsistency()
-                .build();
         keystore.addListener(klistener);
         objectStore.addListener(olistener);
         log.info("DyanmicConfig Store Active");
@@ -137,6 +128,13 @@
     public CompletableFuture<Boolean>
     addRecursive(ResourceId complete, DataNode node) {
         CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
+        //Workaround
+        List<NodeKey> nodeKeyList = complete.nodeKeys();
+        NodeKey f = nodeKeyList.get(0);
+        if (f.schemaId().name().compareTo("/") == 0) {
+            nodeKeyList.remove(0);
+        }
+        //Workaround end
         ResourceId path = ResourceIdParser.getParent(complete);
         String spath = ResourceIdParser.parseResId(path);
         if (spath == null) {
@@ -219,6 +217,13 @@
     @Override
     public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
         CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
+        //Workaround
+        List<NodeKey> nodeKeyList = path.nodeKeys();
+        NodeKey f = nodeKeyList.get(0);
+        if (f.schemaId().name().compareTo("/") == 0) {
+            nodeKeyList.remove(0);
+        }
+        //Workaround end
         String spath = ResourceIdParser.parseResId(path);
         DocumentPath dpath = DocumentPath.from(spath);
         DataNode.Type type = null;
@@ -341,6 +346,13 @@
 
     @Override
     public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
+        //Workaround
+        List<NodeKey> nodeKeyList = path.nodeKeys();
+        NodeKey f = nodeKeyList.get(0);
+        if (f.schemaId().name().compareTo("/") == 0) {
+            nodeKeyList.remove(0);
+        }
+        //Workaround end
         String spath = ResourceIdParser.parseResId(path);
         DocumentPath dpath = DocumentPath.from(spath);
         DataNode.Type type = null;
@@ -357,45 +369,6 @@
         }
     }
 
-    @Override
-    public void addConfigListener(ResourceId path, DynamicConfigListener listener) {
-        String lpath = ResourceIdParser.parseResId(path);
-        try {
-            lstnrStore.put(lpath, listener);
-        } catch (ConsistentMapException e) {
-            throw new FailedException(e.getCause().getMessage());
-        }
-    }
-
-    @Override
-    public void removeConfigListener(ResourceId path, DynamicConfigListener listener) {
-        String lpath = ResourceIdParser.parseResId(path);
-        try {
-            lstnrStore.remove(lpath, listener);
-        } catch (ConsistentMapException e) {
-            throw new FailedException(e.getCause().getMessage());
-        }
-    }
-
-    @Override
-    public Collection<? extends DynamicConfigListener> getConfigListener(ResourceId path) {
-        String lpath = ResourceIdParser.parseResId(path);
-        try {
-            Versioned<Collection<? extends DynamicConfigListener>> ls = lstnrStore.get(lpath);
-            if (ls != null) {
-                return ls.value();
-            } else {
-                log.info("STORE: no Listeners!!");
-                return null;
-            }
-        } catch (ConsistentMapException e) {
-            //throw new FailedException(e.getCause().getMessage());
-            throw new FailedException("getConfigListener failed");
-        } catch (NullPointerException e) {
-            throw new FailedException(e.getCause().getMessage());
-        }
-    }
-
     public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
         @Override
         public void event(DocumentTreeEvent<DataNode.Type> event) {
diff --git a/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java b/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
index c79d42a..938734d 100644
--- a/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
@@ -37,11 +37,8 @@
 import org.onosproject.yang.model.DataNode;
 import org.onosproject.yang.model.ResourceId;
 import org.onosproject.event.AbstractListenerManager;
-import org.onosproject.event.EventDeliveryService;
 import org.slf4j.Logger;
 
-import java.util.Collection;
-
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -57,19 +54,19 @@
     private final Logger log = getLogger(getClass());
     private final DynamicConfigStoreDelegate storeDelegate = new InternalStoreDelegate();
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected EventDeliveryService eventDispatcher;
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DynamicConfigStore store;
 
     @Activate
     public void activate() {
         store.setDelegate(storeDelegate);
+        eventDispatcher.addSink(DynamicConfigEvent.class, listenerRegistry);
         log.info("DynamicConfigService Started");
     }
 
     @Deactivate
     public void deactivate() {
         store.unsetDelegate(storeDelegate);
+        eventDispatcher.removeSink(DynamicConfigEvent.class);
         log.info("DynamicConfigService Stopped");
     }
 
@@ -106,16 +103,10 @@
     public void replaceNode(ResourceId path, DataNode node) {
         throw new FailedException("Not yet implemented");
     }
+
     public Integer getNumberOfChildren(ResourceId path, Filter filter) {
         throw new FailedException("Not yet implemented");
     }
-    public void addConfigListener(ResourceId path, DynamicConfigListener listener) {
-        store.addConfigListener(path, listener);
-    }
-
-    public void removeConfigListener(ResourceId path, DynamicConfigListener listener) {
-        store.removeConfigListener(path, listener);
-    }
 
     public void registerHandler(RpcHandler handler, RpcCommand command) {
         throw new FailedException("Not yet implemented");
@@ -138,15 +129,7 @@
      */
     private class InternalStoreDelegate implements DynamicConfigStoreDelegate {
         public void notify(DynamicConfigEvent event) {
-            ResourceId path = event.subject();
-            Collection<? extends DynamicConfigListener> lstnrs = store.getConfigListener(path);
-            if (lstnrs != null) {
-                for (DynamicConfigListener l : lstnrs) {
-                    l.event(event);
-                }
-            } else {
-                log.info("InternalStoreDelegate: no Listeners");
-            }
+            post(event);
         }
     }
 }
\ No newline at end of file
diff --git a/apps/netconf/BUCK b/apps/netconf/BUCK
index c619118..f4cc35c 100644
--- a/apps/netconf/BUCK
+++ b/apps/netconf/BUCK
@@ -1,5 +1,6 @@
 BUNDLES = [
   '//apps/netconf/client:onos-apps-netconf-client',
+  '//apps/netconf/storeadapter:onos-apps-netconf-storeadapter',
 ]
 
 onos_app (
diff --git a/apps/netconf/storeadapter/BUCK b/apps/netconf/storeadapter/BUCK
new file mode 100644
index 0000000..b58c1d8
--- /dev/null
+++ b/apps/netconf/storeadapter/BUCK
@@ -0,0 +1,26 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+    '//lib:onos-yang-model',
+    '//lib:onos-yang-runtime',
+    '//apps/config:onos-apps-config',
+]
+
+osgi_jar_with_tests (
+  deps = COMPILE_DEPS,
+)
+
+BUNDLES = [
+  '//apps/netconf/client:onos-apps-netconf-client',
+  '//apps/netconf/storeadapter:onos-apps-netconf-storeadapter',
+]
+
+onos_app (
+  app_name = 'org.onosproject.netconf',
+  title = 'NETCONF Application Module',
+  category = 'Utility',
+  url = 'http://onosproject.org',
+  description = """This application provides an interface for monitoring and modifying datastores
+                   of NETCONF devices using Yang data. It uses the YangRuntime to serialize outbound
+                   messages from Yang into NETCONF and deserialize received messages.""",
+  included_bundles = BUNDLES,
+)
diff --git a/apps/netconf/storeadapter/src/main/java/org/onosproject/netconf/storeadapter/NetConfListener.java b/apps/netconf/storeadapter/src/main/java/org/onosproject/netconf/storeadapter/NetConfListener.java
new file mode 100644
index 0000000..a268c35
--- /dev/null
+++ b/apps/netconf/storeadapter/src/main/java/org/onosproject/netconf/storeadapter/NetConfListener.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * 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.netconf.storeadapter;
+
+import com.google.common.annotations.Beta;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigListener;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.config.Filter;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.ResourceId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Beta
+@Component(immediate = true)
+public class NetConfListener implements DynamicConfigListener {
+
+    private static final Logger log = LoggerFactory.getLogger(NetConfListener.class);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DynamicConfigService cfgServcie;
+    public static final String DEVNMSPACE = "namespace1";
+
+    private ResourceId resId = new ResourceId.Builder()
+            .addBranchPointSchema("device", DEVNMSPACE )
+            .build();
+    @Activate
+    protected void activate() {
+        cfgServcie.addListener(this);
+        log.info("NetConfListener Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        cfgServcie.removeListener(this);
+        log.info("NetConfListener Stopped");
+    }
+
+    public boolean isRelevant(DynamicConfigEvent event) {
+        if (event.subject().equals(resId)) {
+            log.info("isRelevant {} = {}", resId, event.subject());
+                return true;
+            } else {
+            log.info("isRelevant {} != {}", resId, event.subject());
+            return false;
+        }
+    }
+
+    public void event(DynamicConfigEvent event) {
+        if (!isRelevant(event)) {
+            log.info("event is not relevanyt!!!! {} != {}", resId, event.subject());
+            return;
+        }
+        switch (event.type()) {
+            case NODE_ADDED:
+                log.info("NetConfListener: RXD NODE_ADDED event");
+                Filter filt = new Filter();
+                DataNode node = cfgServcie.readNode(event.subject(), filt);
+                //call netconf passive
+                break;
+            case NODE_UPDATED:
+                log.info("NetConfListener: RXD NODE_UPDATED event");
+                break;
+            case NODE_REPLACED:
+                log.info("NetConfListener: RXD NODE_REPLACED event");
+                break;
+            case NODE_DELETED:
+                log.info("NetConfListener: RXD NODE_DELETED event");
+                break;
+            case UNKNOWN_OPRN:
+            default:
+                log.warn("NetConfListener: unknown event: {}", event.type());
+                break;
+        }
+    }
+}
\ No newline at end of file