ONOS-6483 API to check if node exists

Change-Id: I368340bccdfe89a6e95e1068b966acf64b8aa5b4
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 102474d..ec856ad 100755
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
@@ -74,6 +74,15 @@
     Integer getNumberOfChildren(ResourceId path, Filter filter);
 
     /**
+     * Returns whether the requested node exists in the Dynamic Config store.
+     *
+     * @param path data structure with absolute path to the intended node
+     * @return {@code true} if the node existed in the store
+     * {@code false} otherwise
+     */
+    Boolean nodeExist(ResourceId path);
+
+    /**
      * Updates an existing node in the dynamic config store.
      * Any missing children nodes will be created with this request.
      * This method would throw an exception if the requested node or any of the
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 e07a7b7..4049f60 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
@@ -110,4 +110,13 @@
      * {@code FailedException} if the delete request failed
      */
     CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path);
+
+    /**
+     * Returns whether the requested node exists in the Dynamic Config store.
+     *
+     * @param path data structure with absolute path to the intended node
+     * @return future that is completed with {@code true} if the node existed
+     * in the store, {@code false} otherwise
+     */
+    CompletableFuture<Boolean> nodeExist(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 5acdacd..d1359e3 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
@@ -272,48 +272,47 @@
                 DocumentPath.from(spath));
         Map<String, Versioned<DataNode.Type>> entries = null;
         entries = complete(ret);
-        /*if ((entries == null) || (entries.size() == 0)) {
-            throw new FailedException("Inner node cannot have empty children map");
-        }*/
-        entries.forEach((k, v) -> {
-            String[] names = k.split(ResourceIdParser.NM_CHK);
-            String name = names[0];
-            String nmSpc = ResourceIdParser.getNamespace(names[1]);
-            String keyVal = ResourceIdParser.getKeyVal(names[1]);
-            DataNode.Type type = v.value();
-            String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
-            if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
-                superBldr.createChildBuilder(name, nmSpc, readLeaf(tempPath).value())
-                        .type(type)
-                        .exitNode();
-            } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
-                String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
-                LeafNode lfnode = readLeaf(mlpath);
-                superBldr.createChildBuilder(name, nmSpc, lfnode.value())
-                        .type(type)
-                        .addLeafListValue(lfnode.value())
-                        .exitNode();
-                //TODO this alone should be sufficient and take the nm, nmspc too
-            } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
-                DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
-                        .type(type);
-                readInner(tempBldr, tempPath);
-            } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
-                DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
-                        .type(type);
-                tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
-                String[] keys = k.split(ResourceIdParser.KEY_CHK);
-                for (int i = 1; i < keys.length; i++) {
-                    //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
-                    //LeafNode lfnd = readLeaf(curKey);
-                    String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
-                    tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
+        if ((entries != null) && (!entries.isEmpty())) {
+            entries.forEach((k, v) -> {
+                String[] names = k.split(ResourceIdParser.NM_CHK);
+                String name = names[0];
+                String nmSpc = ResourceIdParser.getNamespace(names[1]);
+                String keyVal = ResourceIdParser.getKeyVal(names[1]);
+                DataNode.Type type = v.value();
+                String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
+                if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
+                    superBldr.createChildBuilder(name, nmSpc, readLeaf(tempPath).value())
+                            .type(type)
+                            .exitNode();
+                } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
+                    String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
+                    LeafNode lfnode = readLeaf(mlpath);
+                    superBldr.createChildBuilder(name, nmSpc, lfnode.value())
+                            .type(type)
+                            .addLeafListValue(lfnode.value())
+                            .exitNode();
+                    //TODO this alone should be sufficient and take the nm, nmspc too
+                } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
+                    DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
+                            .type(type);
+                    readInner(tempBldr, tempPath);
+                } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
+                    DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
+                            .type(type);
+                    tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
+                    String[] keys = k.split(ResourceIdParser.KEY_CHK);
+                    for (int i = 1; i < keys.length; i++) {
+                        //String curKey = ResourceIdParser.appendKeyLeaf(tempPath, keys[i]);
+                        //LeafNode lfnd = readLeaf(curKey);
+                        String[] keydata = keys[i].split(ResourceIdParser.NM_CHK);
+                        tempBldr.addKeyLeaf(keydata[0], keydata[1], keydata[2]);
+                    }
+                    readInner(tempBldr, tempPath);
+                } else {
+                    throw new FailedException("Invalid node type");
                 }
-                readInner(tempBldr, tempPath);
-            } else {
-                throw new FailedException("Invalid node type");
-            }
-        });
+            });
+        }
         superBldr.exitNode();
     }
 
@@ -360,6 +359,23 @@
     }
 
     @Override
+    public CompletableFuture<Boolean> nodeExist(ResourceId complete) {
+        Boolean stat = true;
+        List<NodeKey> nodeKeyList = complete.nodeKeys();
+        NodeKey f = nodeKeyList.get(0);
+        if (f.schemaId().name().compareTo("/") == 0) {
+            nodeKeyList.remove(0);
+        }
+        String spath = ResourceIdParser.parseResId(complete);
+        if (spath == null) {
+            stat = false;
+        } else if (completeVersioned(keystore.get(DocumentPath.from(spath))) == null) {
+            stat = false;
+        }
+        return CompletableFuture.completedFuture(stat);
+    }
+
+    @Override
     public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
         throw new FailedException("Not yet implemented");
     }
@@ -374,30 +390,29 @@
                 DocumentPath.from(spath));
         Map<String, Versioned<DataNode.Type>> entries = null;
         entries = complete(ret);
-        /*if ((entries == null) || (entries.size() == 0)) {
-            throw new FailedException("Inner node cannot have empty children map");
-        }*/
-        entries.forEach((k, v) -> {
-            String[] names = k.split(ResourceIdParser.NM_CHK);
-            String name = names[0];
-            String nmSpc = ResourceIdParser.getNamespace(names[1]);
-            String keyVal = ResourceIdParser.getKeyVal(names[1]);
-            DataNode.Type type = v.value();
-            String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
-            if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
-                removeLeaf(tempPath);
-            } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
-                String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
-                removeLeaf(mlpath);
-            } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
-                deleteInner(tempPath);
-            } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
-                tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
-                deleteInner(tempPath);
-            } else {
-                throw new FailedException("Invalid node type");
-            }
-        });
+        if ((entries != null) && (!entries.isEmpty())) {
+            entries.forEach((k, v) -> {
+                String[] names = k.split(ResourceIdParser.NM_CHK);
+                String name = names[0];
+                String nmSpc = ResourceIdParser.getNamespace(names[1]);
+                String keyVal = ResourceIdParser.getKeyVal(names[1]);
+                DataNode.Type type = v.value();
+                String tempPath = ResourceIdParser.appendNodeKey(spath, name, nmSpc);
+                if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
+                    removeLeaf(tempPath);
+                } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
+                    String mlpath = ResourceIdParser.appendLeafList(tempPath, keyVal);
+                    removeLeaf(mlpath);
+                } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
+                    deleteInner(tempPath);
+                } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
+                    tempPath = ResourceIdParser.appendMultiInstKey(tempPath, k);
+                    deleteInner(tempPath);
+                } else {
+                    throw new FailedException("Invalid node type");
+                }
+            });
+        }
         keystore.removeNode(DocumentPath.from(spath));
     }
 
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 9d54e5a..0cda139 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
@@ -98,6 +98,10 @@
         throw new FailedException("Not yet implemented");
     }
 
+    public Boolean nodeExist(ResourceId path) {
+        return store.nodeExist(path).join();
+    }
+
     public void registerHandler(RpcHandler handler, RpcCommand command) {
         throw new FailedException("Not yet implemented");
     }