ONOS-5960 Dynamic Config Svc: Datachange Notifications
Change-Id: I46b999530d985b5f9d2bf611f685c1397353997b
diff --git a/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java b/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java
index 8b6a305..9d1b387 100755
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java
@@ -50,7 +50,12 @@
/**
* Signifies that dynamic configuration instance was removed.
*/
- NODE_DELETED
+ NODE_DELETED,
+
+ /**
+ * Signifies an unknown and hence invalid store opeartion.
+ */
+ UNKNOWN_OPRN
}
/**
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 9ea34f2..25ddf55 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
@@ -20,6 +20,7 @@
import org.onosproject.yang.model.ResourceId;
import org.onosproject.store.Store;
+import java.util.Collection;
import java.util.concurrent.CompletableFuture;
/**
@@ -136,4 +137,32 @@
* {@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/ResourceIdParser.java b/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
index 7b7f5bd..23c107d 100755
--- a/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
+++ b/apps/config/src/main/java/org/onosproject/config/ResourceIdParser.java
@@ -16,35 +16,199 @@
package org.onosproject.config;
import java.util.Iterator;
+
+import java.util.List;
+
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.ListKey;
import org.onosproject.yang.model.NodeKey;
import org.onosproject.yang.model.ResourceId;
/**
- * Representation of an entity which identifies a resource in the logical tree
- * data store. It is a list of node keys to identify the branch point
- * hierarchy to reach a resource in the instance tree.
+ * Utilities to work on the ResourceId.
*/
public final class ResourceIdParser {
+ public static final String ROOT = "root";
+ public static final String NM_SEP = "#";
+ public static final String VAL_SEP = "@";
+ public static final String KEY_SEP = "$";
+ public static final String EL_SEP = ".";
+
+
+
private ResourceIdParser() {
}
- public static String asString(ResourceId path) {
+
+ public static ResourceId getParent(ResourceId path) {
+ int last = path.nodeKeys().size();
+ path.nodeKeys().remove(last - 1);
+ return path;
+ }
+
+ public static NodeKey getInstanceKey(ResourceId path) {
+ int last = path.nodeKeys().size();
+ NodeKey ret = path.nodeKeys().get(last - 1);
+ if (ret instanceof NodeKey) {
+ return ret;
+ } else {
+ return null;
+ }
+ }
+
+ public static NodeKey getMultiInstanceKey(ResourceId path) {
+ int last = path.nodeKeys().size();
+ NodeKey ret = path.nodeKeys().get(last - 1);
+ if (ret instanceof ListKey) {
+ return ret;
+ } else {
+ return null;
+ }
+ }
+
+ public static String appendMultiInstKey(String path, String leaf) {
+ return (path + leaf.substring(leaf.indexOf(KEY_SEP)));
+ }
+
+ public static String appendKeyLeaf(String path, String key) {
+ return (path + EL_SEP + key);
+ }
+
+ //DONE
+ public static String appendKeyLeaf(String path, KeyLeaf key) {
StringBuilder bldr = new StringBuilder();
- bldr.append("root.");
- Iterator<NodeKey> iter = path.nodeKeys().iterator();
- NodeKey key;
- while (iter.hasNext()) {
- key = iter.next();
- //log.info("Iter: key {}", key.toString());
- bldr.append(key.schemaId().name());
- bldr.append("#");
- bldr.append(key.schemaId().namespace());
- if (iter.hasNext()) {
- bldr.append(".");
- }
- }
+ bldr.append(key.leafSchema().name());
+ bldr.append(NM_SEP);
+ bldr.append(key.leafSchema().namespace());
+ bldr.append(NM_SEP);
+ bldr.append(key.leafValue().toString());
+ return (path + EL_SEP + bldr.toString());
+ }
+
+ public static String appendNodeKey(String path, NodeKey key) {
+ return (path + EL_SEP + key.schemaId().name() + NM_SEP + key.schemaId().namespace());
+ }
+
+ public static String appendNodeKey(String path, String name, String nmSpc) {
+ return (path + EL_SEP + name + NM_SEP + nmSpc);
+ }
+
+ public static String appendLeafList(String path, LeafListKey key) {
+ return (path + NM_SEP + key.asString());
+ }
+
+ public static String appendLeafList(String path, String val) {
+ return (path + NM_SEP + val);
+ }
+
+ public static String appendKeyList(String path, ListKey key) {
+ StringBuilder bldr = new StringBuilder();
+ for (KeyLeaf keyLeaf : key.keyLeafs()) {
+ bldr.append(KEY_SEP);
+ bldr.append(keyLeaf.leafSchema().name());
+ bldr.append(NM_SEP);
+ bldr.append(keyLeaf.leafSchema().namespace());
+ bldr.append(NM_SEP);
+ bldr.append(keyLeaf.leafValue().toString());
+ }
+ return (path + bldr.toString());
+ }
+
+ public static String parseNodeKey(NodeKey key) {
+ if (key == null) {
+ return null;
+ }
+ StringBuilder bldr = new StringBuilder();
+ if (key instanceof LeafListKey) {
+ parseLeafList((LeafListKey) key, bldr);
+ } else if (key instanceof ListKey) {
+ parseKeyList((ListKey) key, bldr);
+ } else {
+ parseNodeKey(key, bldr);
+ }
return bldr.toString();
}
+
+ public static String parseResId(ResourceId path) {
+ StringBuilder bldr = new StringBuilder();
+ bldr.append(ROOT);
+ if (path == null) {
+ return bldr.toString();
+ }
+ List<NodeKey> nodeKeyList = path.nodeKeys();
+ for (NodeKey key : nodeKeyList) {
+ bldr.append(EL_SEP);
+ if (key instanceof LeafListKey) {
+ parseLeafList((LeafListKey) key, bldr);
+ } else if (key instanceof ListKey) {
+ parseKeyList((ListKey) key, bldr);
+ } else {
+ parseNodeKey(key, bldr);
+ }
+ }
+ return bldr.toString();
+ }
+
+ private static void parseLeafList(LeafListKey key, StringBuilder bldr) {
+ bldr.append(key.schemaId().name());
+ bldr.append(NM_SEP);
+ bldr.append(key.schemaId().namespace());
+ bldr.append(NM_SEP);
+ bldr.append(key.asString());
+ }
+
+ private static void parseKeyList(ListKey key, StringBuilder bldr) {
+ bldr.append(key.schemaId().name());
+ bldr.append(NM_SEP);
+ bldr.append(key.schemaId().namespace());
+ bldr.append(NM_SEP);
+ Iterator<KeyLeaf> iter = key.keyLeafs().iterator();
+ KeyLeaf next;
+ while (iter.hasNext()) {
+ next = iter.next();
+ bldr.append(KEY_SEP);
+ bldr.append(next.leafSchema().name());
+ bldr.append(NM_SEP);
+ bldr.append(next.leafSchema().namespace());
+ bldr.append(NM_SEP);
+ bldr.append(next.leafValue().toString());
+ }
+ }
+
+ private static void parseNodeKey(NodeKey key, StringBuilder bldr) {
+ bldr.append(key.schemaId().name());
+ bldr.append(NM_SEP);
+ bldr.append(key.schemaId().namespace());
+ }
+
+ public static ResourceId getResId(List<String> dpath) {
+ ResourceId.Builder resBldr = new ResourceId.Builder();
+ Iterator<String> itr = dpath.iterator();
+ itr.next();
+ while (itr.hasNext()) {
+ String name = itr.next();
+ if (name.contains(VAL_SEP)) {
+ resBldr.addLeafListBranchPoint(name.substring(0, name.indexOf(NM_SEP)),
+ name.substring(name.indexOf(NM_SEP) + 1, name.indexOf(VAL_SEP)),
+ name.substring(name.indexOf(VAL_SEP) + 1));
+ } else if (name.contains(KEY_SEP)) {
+ resBldr.addBranchPointSchema(name.substring(0, name.indexOf(NM_SEP)),
+ name.substring(name.indexOf(NM_SEP) + 1, name.indexOf(KEY_SEP)));
+ String[] keys = name.split(KEY_SEP);
+ for (int i = 1; i < keys.length; i++) {
+ String key = keys[i];
+ resBldr.addKeyLeaf(key.substring(0, key.indexOf(NM_SEP)),
+ key.substring(key.indexOf(NM_SEP) + 1, key.lastIndexOf(NM_SEP)),
+ key.substring(name.lastIndexOf(NM_SEP) + 1));
+ }
+ } else {
+ resBldr.addBranchPointSchema(name.substring(0, name.indexOf(NM_SEP)),
+ name.substring(name.indexOf(NM_SEP) + 1));
+ }
+ }
+ return resBldr.build();
+ }
}
\ 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 741ae97..1c63258 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,38 +24,50 @@
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.ResourceIdParser;
-import org.onosproject.store.service.IllegalDocumentModificationException;
-import org.onosproject.store.service.NoSuchDocumentPathException;
-import org.onosproject.yang.model.DataNode;
-import org.onosproject.yang.model.InnerNode;
-import org.onosproject.yang.model.LeafNode;
-import org.onosproject.yang.model.NodeKey;
-import org.onosproject.yang.model.ResourceId;
-import org.onosproject.yang.model.SchemaId;
+//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;
+import org.onosproject.store.service.IllegalDocumentModificationException;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.NoSuchDocumentPathException;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.Versioned;
+import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.InnerNode;
+import org.onosproject.yang.model.KeyLeaf;
+import org.onosproject.yang.model.LeafListKey;
+import org.onosproject.yang.model.LeafNode;
+import org.onosproject.yang.model.ListKey;
+import org.onosproject.yang.model.NodeKey;
+import org.onosproject.yang.model.ResourceId;
+import org.onosproject.yang.model.SchemaId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
+import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_ADDED;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_UPDATED;
+import static org.onosproject.config.DynamicConfigEvent.Type.NODE_DELETED;
+import static org.onosproject.config.DynamicConfigEvent.Type.UNKNOWN_OPRN;
+
/**
* Implementation of the dynamic config store.
*/
@@ -70,6 +82,7 @@
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();
@@ -77,7 +90,7 @@
public void activateStore() {
KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
.register(KryoNamespaces.BASIC)
- .register(String.class)
+ //.register(String.class)
.register(java.lang.Class.class)
.register(DataNode.Type.class)
.register(LeafNode.class)
@@ -86,6 +99,7 @@
.register(NodeKey.class)
.register(SchemaId.class)
.register(java.util.LinkedHashMap.class);
+ //.register(CfgReceiver.InternalDynamicConfigListener.class);
keystore = storageService.<DataNode.Type>documentTreeBuilder()
.withSerializer(Serializer.using(kryoBuilder.build()))
.withName("config-key-store")
@@ -96,6 +110,11 @@
.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");
@@ -115,86 +134,214 @@
}
@Override
+ public CompletableFuture<Boolean>
+ addRecursive(ResourceId complete, DataNode node) {
+ CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(true);
+ ResourceId path = ResourceIdParser.getParent(complete);
+ String spath = ResourceIdParser.parseResId(path);
+ if (spath == null) {
+ throw new FailedException("Invalid RsourceId, cannot create Node");
+ }
+ /*if (keystore.get(DocumentPath.from(spath)).join() == null) {
+ ////TODO is recursively creating missing parents required?
+ throw new FailedException("Some of the parents in the path " +
+ "are not present, creation not supported currently");
+ }*/
+ spath = ResourceIdParser.appendNodeKey(spath, node.key());
+ parseNode(spath, node);
+ return eventFuture;
+ }
+
+ private void parseNode(String path, DataNode node) {
+ if (keystore.get(DocumentPath.from(path)).join() != null) {
+ throw new FailedException("Requested node already present in the" +
+ " store, please use an update method");
+ }
+ if (node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
+ addLeaf(path, (LeafNode) node);
+ } else if (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
+ path = ResourceIdParser.appendLeafList(path, (LeafListKey) node.key());
+ if (keystore.get(DocumentPath.from(path)).join() != null) {
+ throw new FailedException("Requested node already present in the" +
+ " store, please use an update method");
+ }
+ addLeaf(path, (LeafNode) node);
+ } else if (node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
+ traverseInner(path, (InnerNode) node);
+ } else if (node.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
+ path = ResourceIdParser.appendKeyList(path, (ListKey) node.key());
+ if (keystore.get(DocumentPath.from(path)).join() != null) {
+ throw new FailedException("Requested node already present in the" +
+ " store, please use an update method");
+ }
+ traverseInner(path, (InnerNode) node);
+ } else {
+ throw new FailedException("Invalid node type");
+ }
+ }
+
+ private void traverseInner(String path, InnerNode node) {
+ addKey(path, node.type());
+ Map<NodeKey, DataNode> entries = node.childNodes();
+ if (entries.size() == 0) {
+ throw new FailedException("Inner node cannot have empty children map");
+ }
+ entries.forEach((k, v) -> {
+ String tempPath;
+ tempPath = ResourceIdParser.appendNodeKey(path, v.key());
+ if (v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
+ addLeaf(tempPath, (LeafNode) v);
+ } else if (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
+ tempPath = ResourceIdParser.appendLeafList(tempPath, (LeafListKey) v.key());
+ addLeaf(tempPath, (LeafNode) v);
+ } else if (v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) {
+ traverseInner(tempPath, (InnerNode) v);
+ } else if (v.type() == DataNode.Type.MULTI_INSTANCE_NODE) {
+ tempPath = ResourceIdParser.appendKeyList(tempPath, (ListKey) v.key());
+ traverseInner(path, (InnerNode) v);
+ } else {
+ throw new FailedException("Invalid node type");
+ }
+ });
+ }
+
+ private Boolean addLeaf(String path, LeafNode node) {
+ objectStore.put(path, node);
+ return addKey(path, node.type());
+ }
+
+ private Boolean addKey(String path, DataNode.Type type) {
+ Boolean stat = false;
+ CompletableFuture<Boolean> ret = keystore.create(DocumentPath.from(path), type);
+ return complete(ret);
+ }
+
+ @Override
public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
- DocumentPath dpath = DocumentPath.from(ResourceIdParser.asString(path));
- DataNode.Type type;
- type = keystore.get(dpath).join().value();
+ String spath = ResourceIdParser.parseResId(path);
+ DocumentPath dpath = DocumentPath.from(spath);
+ DataNode.Type type = null;
+ CompletableFuture<Versioned<DataNode.Type>> ret = keystore.get(dpath);
+ type = completeVersioned(ret);
if (type == null) {
throw new FailedException("Requested node or some of the parents" +
- "are not present in the requested path");
+ "are not present in the requested path");
}
DataNode retVal = null;
- //TODO handle single and multi instances differently
- if ((type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) ||
- (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE)) {
- retVal = readLeaf(path);
- } else {
- int last = path.nodeKeys().size();
- NodeKey key = path.nodeKeys().get(last - 1);
- DataNode.Builder superBldr = InnerNode.builder(key.schemaId().name(),
- key.schemaId().namespace()).type(type);
- readInner(superBldr, path);
+ if (type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) {
+ retVal = readLeaf(spath);
+ } else if (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE) {
+ retVal = readLeaf(spath);
+ } else if (type == DataNode.Type.SINGLE_INSTANCE_NODE) {
+ NodeKey key = ResourceIdParser.getInstanceKey(path);
+ if (key == null) {
+ throw new FailedException("Key type did not match node type");
+ }
+ DataNode.Builder superBldr = InnerNode
+ .builder(key.schemaId().name(), key.schemaId().namespace())
+ .type(type);
+ readInner(superBldr, spath);
retVal = superBldr.build();
+ } else if (type == DataNode.Type.MULTI_INSTANCE_NODE) {
+ NodeKey key = ResourceIdParser.getMultiInstanceKey(path);
+ if (key == null) {
+ throw new FailedException("Key type did not match node type");
+ }
+ DataNode.Builder superBldr = InnerNode
+ .builder(key.schemaId().name(), key.schemaId().namespace())
+ .type(type);
+ for (KeyLeaf keyLeaf : ((ListKey) key).keyLeafs()) {
+ String tempPath = ResourceIdParser.appendKeyLeaf(spath, keyLeaf);
+ LeafNode lfnd = readLeaf(tempPath);
+ superBldr.addKeyLeaf(keyLeaf.leafSchema().name(),
+ keyLeaf.leafSchema().namespace(), lfnd.value());
+ }
+ readInner(superBldr, spath);
+ retVal = superBldr.build();
+ } else {
+ throw new FailedException("Invalid node type");
}
if (retVal != null) {
eventFuture = CompletableFuture.completedFuture(retVal);
} else {
- log.info("STORE: FAILED to READ node @@@@");
+ log.info("STORE: FAILED to READ node");
}
return eventFuture;
}
- @Override
- public CompletableFuture<Boolean>
- addRecursive(ResourceId path, DataNode node) {
- CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(false);
- Boolean stat = false;
- DocumentPath dpath = DocumentPath.from(ResourceIdParser.asString(path));
- if (keystore.get(dpath).join() == null) {
- //recursivley craete all missing aprents
- }
- if (keystore.get(dpath).join() != null) {
- throw new FailedException("Requested node already present " +
- "in the store, please use an update method");
- }
- //TODO single instance and multi instance need to be handled differently
- if ((node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) ||
- (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE)) {
- stat = addLeaf(path, (LeafNode) node);
- } else {
- stat = (traverseInner(path, (InnerNode) node));
- }
- if (stat) {
- eventFuture = CompletableFuture.completedFuture(true);
- } else {
- log.info("STORE: FAILED to create node @@@@");
- }
- return eventFuture;
- }
+ private void readInner(DataNode.Builder superBldr, String spath) {
+ CompletableFuture<Map<String, Versioned<DataNode.Type>>> ret = keystore.getChildren(
+ 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_SEP);
+ String name = names[0];
+ String nmSpc = 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, names[2]);
+ 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_SEP);
+ 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_SEP);
+ superBldr.addKeyLeaf(keydata[0], keydata[1], lfnd.value());
+ }
+ readInner(tempBldr, tempPath);
+ } else {
+ throw new FailedException("Node type should either be LEAF or INNERNODE");
+ }
+ });
+ superBldr.exitNode();
+ }
+
+ private LeafNode readLeaf(String path) {
+ return objectStore.get(path).value();
+ }
@Override
public CompletableFuture<Boolean> updateNode(ResourceId path, DataNode node) {
throw new FailedException("Not yet implemented");
}
@Override
- public CompletableFuture<Boolean>
- updateNodeRecursive(ResourceId path, DataNode node) {
+ public CompletableFuture<Boolean> updateNodeRecursive(ResourceId path, DataNode node) {
throw new FailedException("Not yet implemented");
}
@Override
- public CompletableFuture<Boolean>
- replaceNode(ResourceId path, DataNode node) {
+ public CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node) {
throw new FailedException("Not yet implemented");
}
@Override
- public CompletableFuture<Boolean>
- deleteNode(ResourceId path) {
+ public CompletableFuture<Boolean> deleteNode(ResourceId path) {
throw new FailedException("Not yet implemented");
}
+
@Override
- public CompletableFuture<Boolean>
- deleteNodeRecursive(ResourceId path) {
- String spath = ResourceIdParser.asString(path);
+ public CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path) {
+ String spath = ResourceIdParser.parseResId(path);
DocumentPath dpath = DocumentPath.from(spath);
DataNode.Type type = null;
CompletableFuture<Versioned<DataNode.Type>> vtype = keystore.removeNode(dpath);
@@ -208,123 +355,71 @@
} else {
return CompletableFuture.completedFuture(true);
}
-
}
- private Boolean addLeaf(ResourceId path, LeafNode node) {
- objectStore.put(ResourceIdParser.asString(path), node);
- return (keystore.create(DocumentPath.from(ResourceIdParser.asString(path)), node.type()).join());
- }
-
- private Boolean addKey(ResourceId path, DataNode.Type type) {
- return (keystore.create(DocumentPath.from(ResourceIdParser.asString(path)), type).join());
- }
-
- private Boolean checkNode(ResourceId path, DataNode node) {
- //TODO single instance and multi instance need to be handled differently
- if ((node.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) ||
- (node.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE)) {
- return (addLeaf(path, (LeafNode) node));
- } else if ((node.type() == DataNode.Type.SINGLE_INSTANCE_NODE) ||
- (node.type() == DataNode.Type.MULTI_INSTANCE_NODE)) {
- addKey(path, node.type());
- return (traverseInner(path, (InnerNode) node));
- } else {
- throw new FailedException("Node type should either be LEAF or INNERNODE");
+ @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());
}
}
- private LeafNode readLeaf(ResourceId path) {
- return objectStore.get(ResourceIdParser.asString(path)).value();
+ @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());
+ }
}
- private Boolean traverseInner(ResourceId path, InnerNode node) {
- addKey(path, node.type());
- Map<NodeKey, DataNode> entries = node.childNodes();
- if (entries.size() == 0) {
- throw new FailedException("Inner node cannot have empty children map");
- }
- entries.forEach((k, v) -> {
- ResourceId tempPath;
- try {
- tempPath = path.copyBuilder()
- .addBranchPointSchema(k.schemaId().name(),
- k.schemaId().namespace())
- .build();
- } catch (CloneNotSupportedException e) {
- throw new FailedException("ResourceId could not be cloned@@@@");
- }
- //TODO single instance and multi instance need to be handled differently
- if ((v.type() == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) ||
- (v.type() == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE)) {
- addLeaf(tempPath, (LeafNode) v);
- } else if ((v.type() == DataNode.Type.SINGLE_INSTANCE_NODE) ||
- (v.type() == DataNode.Type.MULTI_INSTANCE_NODE)) {
- traverseInner(tempPath, (InnerNode) v);
+ @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 {
- throw new FailedException("Node type should either be LEAF or INNERNODE");
+ log.info("STORE: no Listeners!!");
+ return null;
}
- });
- return true;
- }
-
- private void readInner(DataNode.Builder superBldr, ResourceId path) {
- Map<String, Versioned<DataNode.Type>> entries = keystore.getChildren(
- DocumentPath.from(ResourceIdParser.asString(path))).join();
- if (entries.size() == 0) {
- throw new FailedException("Inner node cannot have empty children map");
+ } catch (ConsistentMapException e) {
+ //throw new FailedException(e.getCause().getMessage());
+ throw new FailedException("getConfigListener failed");
+ } catch (NullPointerException e) {
+ throw new FailedException(e.getCause().getMessage());
}
- entries.forEach((k, v) -> {
- ResourceId tempPath;
- String[] names = k.split("#");
- String name = names[0];
- String nmSpc = names[1];
- DataNode.Type type = v.value();
- try {
- tempPath = path.copyBuilder()
- .addBranchPointSchema(name, nmSpc)
- .build();
- } catch (CloneNotSupportedException e) {
- throw new FailedException("ResourceId could not be cloned@@@@");
- }
- //TODO single instance and multi instance need to be handled differently
- if ((type == DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE) ||
- (type == DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE)) {
- superBldr.createChildBuilder(name, nmSpc, readLeaf(tempPath))
- .type(type)
- .exitNode();
- } else if ((type == DataNode.Type.SINGLE_INSTANCE_NODE) ||
- (type == DataNode.Type.MULTI_INSTANCE_NODE)) {
- DataNode.Builder tempBldr = superBldr.createChildBuilder(name, nmSpc)
- .type(type);
- readInner(tempBldr, tempPath);
- } else {
- throw new FailedException("Node type should either be LEAF or INNERNODE");
- }
- });
- superBldr.exitNode();
}
public class InternalDocTreeListener implements DocumentTreeListener<DataNode.Type> {
@Override
public void event(DocumentTreeEvent<DataNode.Type> event) {
DynamicConfigEvent.Type type;
- DataNode node;
ResourceId path;
switch (event.type()) {
case CREATED:
log.info("NODE created in store");
+ type = NODE_ADDED;
break;
case UPDATED:
log.info("NODE updated in store");
+ type = NODE_UPDATED;
break;
case DELETED:
log.info("NODE deleted in store");
+ type = NODE_DELETED;
break;
-
default:
+ log.info("UNKNOWN operation in store");
+ type = UNKNOWN_OPRN;
}
- //notify
+ path = ResourceIdParser.getResId(event.path().pathElements());
+ notifyDelegate(new DynamicConfigEvent(type, path));
}
}
@@ -343,7 +438,6 @@
//log.info("NODE removed in store");
break;
}
- //notify
}
}
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 154d014..c79d42a 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
@@ -40,6 +40,8 @@
import org.onosproject.event.EventDeliveryService;
import org.slf4j.Logger;
+import java.util.Collection;
+
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -85,10 +87,6 @@
return store.readNode(path, filter).join();
}
- public Integer getNumberOfChildren(ResourceId path, Filter filter) {
- throw new FailedException("Not yet implemented");
- }
-
public void updateNode(ResourceId path, DataNode node) {
throw new FailedException("Not yet implemented");
}
@@ -108,13 +106,15 @@
public void replaceNode(ResourceId path, DataNode node) {
throw new FailedException("Not yet implemented");
}
-
- public void addConfigListener(ResourceId path, DynamicConfigListener listener) {
+ 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) {
- throw new FailedException("Not yet implemented");
+ store.removeConfigListener(path, listener);
}
public void registerHandler(RpcHandler handler, RpcCommand command) {
@@ -134,13 +134,19 @@
throw new FailedException("Not yet implemented");
}
/**
- * Auxiliary store delegate to receive notification about changes in
- * the prop configuration store state - by the store itself.
+ * Auxiliary store delegate to receive notification about changes in the store.
*/
private class InternalStoreDelegate implements DynamicConfigStoreDelegate {
public void notify(DynamicConfigEvent event) {
- // TODO
- // post(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");
+ }
}
}
}
\ No newline at end of file