ONOS-5863, ONOS-5804 DynamicConfig store and service implementation(create and read supported)

Change-Id: I299a27afe46b87f98d4af79643732e2f1bdc2010
diff --git a/apps/config/pom.xml b/apps/config/pom.xml
index de5cdc7..4916c1d 100755
--- a/apps/config/pom.xml
+++ b/apps/config/pom.xml
@@ -52,6 +52,14 @@
             <groupId>org.apache.karaf.shell</groupId>
             <artifactId>org.apache.karaf.shell.console</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
     </dependencies>
 
 
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 bb29b9d..05ed0c4 100755
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigEvent.java
@@ -16,18 +16,18 @@
 package org.onosproject.config;
 
 
-import org.onosproject.config.model.ResourceIdentifier;
+import org.onosproject.config.model.ResourceId;
 import org.onosproject.event.AbstractEvent;
 
 /**
  * Describes a DynamicConfig change event.
  */
-public class DynamicConfigEvent extends AbstractEvent<DynamicConfigEvent.Type, ResourceIdentifier> {
+public class DynamicConfigEvent extends AbstractEvent<DynamicConfigEvent.Type, ResourceId> {
 
     /**
      * Type of configuration events.
      * A configuration instance could be a leaf node or a subtree,
-     * identified by the subject, ResourceIdentifier.
+     * identified by the subject, ResourceId.
      */
     public enum Type {
         /**
@@ -57,7 +57,7 @@
      * @param type  config node type
      * @param path  config node path
      */
-    public DynamicConfigEvent(Type type, ResourceIdentifier path) {
+    public DynamicConfigEvent(Type type, ResourceId path) {
         super(type, path);
     }
 }
\ No newline at end of file
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 991e806..2adf61b 100755
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigService.java
@@ -16,8 +16,8 @@
 
 package org.onosproject.config;
 
-import org.onosproject.config.model.ResourceIdentifier;
 import org.onosproject.config.model.DataNode;
+import org.onosproject.config.model.ResourceId;
 import org.onosproject.event.ListenerService;
 
 /**
@@ -36,7 +36,7 @@
      * @param node recursive data structure, holding a leaf node or a subtree
      * @throws FailedException if the new node could not be created
      */
-    void createNode(ResourceIdentifier path, DataNode node);
+    void createNode(ResourceId path, DataNode node);
 
     /**
      * Creates a new node in the dynamic config store.
@@ -50,7 +50,7 @@
      * @param node recursive data structure, holding a leaf node or a subtree
      * @throws FailedException if the new node could not be created
      */
-    void createNodeRecursive(ResourceIdentifier path, DataNode node);
+    void createNodeRecursive(ResourceId path, DataNode node);
 
     /**
      * Reads the requested node form the dynamic config store.
@@ -65,7 +65,7 @@
      * @return a recursive data structure, holding a leaf node or a subtree
      * @throws FailedException if the requested node could not be read
      */
-    DataNode readNode(ResourceIdentifier path, Filter filter);
+    DataNode readNode(ResourceId path, Filter filter);
 
     /**
      * Returns the number of children under the node at the given path.
@@ -78,7 +78,7 @@
      * @return the number of children after applying the filtering conditions if any
      * @throws FailedException if the request failed
      */
-    Integer getNumberOfChildren(ResourceIdentifier path, Filter filter);
+    Integer getNumberOfChildren(ResourceId path, Filter filter);
 
     /**
      * Updates an existing node in the dynamic config store.
@@ -90,7 +90,7 @@
      * @param node recursive data structure, holding a leaf node or a subtree
      * @throws FailedException if the update request failed
      */
-    void updateNode(ResourceIdentifier path, DataNode node);
+    void updateNode(ResourceId path, DataNode node);
 
     /**
      * Updates an existing node in the dynamic config store.
@@ -104,7 +104,7 @@
      * @throws FailedException if the update request failed for any reason
      *
      */
-    void updateNodeRecursive(ResourceIdentifier path, DataNode node);
+    void updateNodeRecursive(ResourceId path, DataNode node);
 
     /**
      * Replaces nodes in the dynamic config store.
@@ -117,7 +117,7 @@
      * @param node recursive data structure, holding a leaf node or a subtree
      * @throws FailedException if the replace request failed
      */
-    void replaceNode(ResourceIdentifier path, DataNode node);
+    void replaceNode(ResourceId path, DataNode node);
 
     /**
      * Removes a leaf node from the dynamic config store.
@@ -129,7 +129,7 @@
      * @param path data structure with absolute path to the intended node
      * @throws FailedException if the delete request failed
      */
-    void deleteNode(ResourceIdentifier path);
+    void deleteNode(ResourceId path);
 
     /**
      * Removes a subtree from the dynamic config store.
@@ -141,7 +141,7 @@
      * @param path data structure with absolute path to the intended node
      * @throws FailedException if the delete request failed
      */
-    void deleteNodeRecursive(ResourceIdentifier path);
+    void deleteNodeRecursive(ResourceId path);
 
     /**
      * Adds a listener to be notified when a leaf or subtree rooted at the
@@ -151,7 +151,7 @@
      * @param listener listener to be notified
      * @throws FailedException if the listener could not be added
      */
-    void addConfigListener(ResourceIdentifier path, DynamicConfigListener listener);
+    void addConfigListener(ResourceId path, DynamicConfigListener listener);
 
     /**
      * Removes a previously added listener.
@@ -160,7 +160,7 @@
      * @param listener listener to unregister
      * @throws FailedException if the listener could not be removed
      */
-    void removeConfigListener(ResourceIdentifier path, DynamicConfigListener listener);
+    void removeConfigListener(ResourceId path, DynamicConfigListener listener);
 
     /**
      * Registers an 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 c95efba..2a857e4 100644
--- a/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
+++ b/apps/config/src/main/java/org/onosproject/config/DynamicConfigStore.java
@@ -16,7 +16,7 @@
 package org.onosproject.config;
 
 import org.onosproject.config.model.DataNode;
-import org.onosproject.config.model.ResourceIdentifier;
+import org.onosproject.config.model.ResourceId;
 import org.onosproject.store.Store;
 
 import java.util.concurrent.CompletableFuture;
@@ -38,7 +38,7 @@
      * successfully added or completed exceptionally with
      * {@code FailedException} if node addition failed
      */
-    CompletableFuture<Boolean> addNode(ResourceIdentifier path, DataNode node);
+    CompletableFuture<Boolean> addNode(ResourceId path, DataNode node);
 
     /**
      * Adds a new node in the dynamic config store.
@@ -52,7 +52,7 @@
      * successfully added or completed exceptionally with
      * {@code FailedException} if the node addition failed
      */
-    CompletableFuture<Boolean> addRecursive(ResourceIdentifier path, DataNode node);
+    CompletableFuture<Boolean> addRecursive(ResourceId path, DataNode node);
 
     /**
      * Reads the requested node from the dynamic config store.
@@ -66,7 +66,7 @@
      * DataNode if after applying the filter, the result is an empty list of nodes)
      * or completed with {@code FailedException} if the node could not be read
      */
-    CompletableFuture<DataNode> readNode(ResourceIdentifier path, Filter filter);
+    CompletableFuture<DataNode> readNode(ResourceId path, Filter filter);
 
     /**
      * Updates an existing node in the dynamic config store.
@@ -79,7 +79,7 @@
      * successfully updated or completed exceptionally with
      * {@code FailedException} if the update request failed
      */
-    CompletableFuture<Boolean> updateNode(ResourceIdentifier path, DataNode node);
+    CompletableFuture<Boolean> updateNode(ResourceId path, DataNode node);
 
     /**
      * Updates an existing node in the dynamic config store.
@@ -93,7 +93,7 @@
      * successfully updated or completed exceptionally with
      * {@code FailedException} if the update request failed
      */
-    CompletableFuture<Boolean> updateNodeRecursive(ResourceIdentifier path, DataNode node);
+    CompletableFuture<Boolean> updateNodeRecursive(ResourceId path, DataNode node);
 
     /**
      * Replaces nodes in the dynamic config store.
@@ -107,7 +107,7 @@
      * successfully replaced or completed exceptionally with
      * {@code FailedException} if the replace request failed
      */
-    CompletableFuture<Boolean> replaceNode(ResourceIdentifier path, DataNode node);
+    CompletableFuture<Boolean> replaceNode(ResourceId path, DataNode node);
 
     /**
      * Removes  a node from the dynamic config store.
@@ -120,7 +120,7 @@
      * successfully deleted or completed exceptionally with
      * {@code FailedException} if the delete request failed
      */
-    CompletableFuture<Boolean> deleteNode(ResourceIdentifier path);
+    CompletableFuture<Boolean> deleteNode(ResourceId path);
 
     /**
      * Removes a subtree from the dynamic config store.
@@ -133,5 +133,5 @@
      * successful or completed exceptionally with
      * {@code FailedException} if the delete request failed
      */
-    CompletableFuture<Boolean> deleteNodeRecursive(ResourceIdentifier path);
+    CompletableFuture<Boolean> deleteNodeRecursive(ResourceId path);
 }
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/Filter.java b/apps/config/src/main/java/org/onosproject/config/Filter.java
index 377a148..e826bfa 100755
--- a/apps/config/src/main/java/org/onosproject/config/Filter.java
+++ b/apps/config/src/main/java/org/onosproject/config/Filter.java
@@ -16,102 +16,189 @@
 package org.onosproject.config;
 
 
-import org.onosproject.config.model.ResourceIdentifier;
+import org.onosproject.config.model.ResourceId;
 
+import java.util.LinkedHashSet;
 import java.util.Set;
 
 /**
  * Abstraction for Filters that can be used while traversing the dynamic config store.
  * This abstraction allows to select entries of interest based on various criteria
  * defined by this interface.
- * NOTE: Only criteria based on {@code ResourceIdentifier} are supported currently.
- * This is a placeholder for a filter; Set of ResourceIdentifier becomes inefficient when
+ * NOTE: Only criteria based on {@code ResourceId} are supported currently.
+ * This is a placeholder for a filter; Set of ResourceId becomes inefficient when
  * using a large number of filtering criteria;
  */
-public interface Filter {
-    enum TraversalMode {
-        /**
-         * Traversal types.
-         */
+public class Filter {
+    /**
+     * Traversal modes.
+     */
+    public enum TraversalMode {
         SUB_TREE(-1),
         NODE_ONLY(0),
         GIVEN_DEPTH;
-
         /**
-         * variable indicating the depth of traversal.
-         * depth = -1 => if the node is pointing to a subtree, the entire subtree will be traversed;
-         * if the node points to a leaf, just the leaf will be retrieved.
-         * depth = 0 => tree will not be traversed; will retrieve just the specific node,
-         * irrespective of it being a subtree root or a leaf node
-         * depth = any other integer => that many levels of the subtree will be traversed;
-         * if depth > the number of levels of children, the entire subtree will
-         * be traversed and end the traversal, without throwing any errors.
+         * SUB_TREE => if the node points to a subtree, the entire subtree will
+         * be traversed; if pointing to a leaf, just the leaf will be retrieved.
+         * NODE_ONLY => tree will not be traversed; will retrieve just the
+         * specific node, irrespective of it being a subtree root or a leaf node
+         * GIVEN_DEPTH => as many levels of the subtree as indicated by depth
+         * field of filter that  will be traversed; if depth > the number of
+         * levels of children, the entire subtree will be traversed and end
+         * the traversal, without throwing any errors.
          */
-        int depth;
-
+        int val;
         TraversalMode() {
 
         }
-
-        TraversalMode(int depth) {
-            this.depth = depth;
+        TraversalMode(int val) {
+            this.val = val;
         }
-
-        int depth() {
-            return depth;
+        int val() {
+            return val;
         }
     }
 
-    /**
-     * Adds the traversal depth to the Filter object.
-     * Various interpretations of depth are as mentioned.
-     * Default traversal mode is to read just the given node(NODE_ONLY).
-     *
-     * @param depth new criteria
+    /** Filtering criteria.
      */
-    void addDepth(TraversalMode depth);
+    Set<ResourceId> criteria = new LinkedHashSet<ResourceId>();
+    /** Traversal mode; default is to read just the given node(NODE_ONLY).
+     */
+    TraversalMode mode = TraversalMode.NODE_ONLY;
+    /** depth of traversal; default value is 0.
+     */
+    int depth = TraversalMode.NODE_ONLY.val();
 
     /**
-     * Adds new ResourceIdentifier filtering criteria to a Filter object.
-     * If the same ResourceIdentifier is already part of the criteria
+     * Creates a new Filter object.
+     */
+    public Filter() {
+
+    }
+    /**
+     * Creates a new Filter object.
+     *
+     * @param criteria  set of filtering criteria
+     * @param mode traversal mode
+     * @param depth depth of traversal
+     */
+    public Filter(Set<ResourceId> criteria, TraversalMode mode, int depth) {
+        this.criteria = criteria;
+        this.mode = mode;
+        this.depth = depth;
+
+    }
+
+    /**
+     * Returns the traversal mode.
+     *
+     *@return traversal mode
+     */
+    TraversalMode mode() {
+        return mode;
+    }
+
+    /**
+     * Sets the traversal mode.
+     *
+     * @param mode traversal mode
+     */
+    void mode(TraversalMode mode) {
+        this.mode = mode;
+    }
+
+    /**
+     * Returns the depth.
+     *
+     *@return depth
+     */
+    int depth() {
+        return depth;
+    }
+
+    /**
+     * Sets the depth.
+     *
+     * @param depth of traversal
+     */
+    void mode(int depth) {
+        this.depth = depth;
+    }
+    /**
+     * Adds a new ResourceId filtering criterion to a Filter object.
+     * If the same ResourceId is already part of the criteria
      * for the object, it will not be added again, but will not throw any exceptions.
-     * This will not check for the validity of the ResourceIdentifier.
+     * This will not check for the validity of the ResourceId.
      *
-     * @param add new criteria
+     * @param add new criterion
      */
-    void addCriteria(Set<ResourceIdentifier> add);
+    void addCriteria(ResourceId add) {
+        criteria.add(add);
+    }
 
     /**
-     * Removes the given ResourceIdentifier filtering criteria from a Filter object.
-     * If the ResourceIdentifier was NOT already part of the criteria for
+     * Adds new ResourceId filtering criteria to a Filter object.
+     * If the same ResourceId is already part of the criteria
+     * for the object, it will not be added again, but will not throw any exceptions.
+     * This will not check for the validity of the ResourceId.
+     *
+     * @param addAll new criteria
+     */
+    void addCriteria(Set<ResourceId> addAll) {
+        criteria.addAll(addAll);
+    }
+
+    /**
+     * Removes the given ResourceId filtering criterion from a Filter object.
+     * If the ResourceId was NOT already part of the criteria for
      * the object, it will not be removed, but will not throw any exceptions.
-     * This will not check for the validity of the ResourceIdentifier.
+     * This will not check for the validity of the ResourceId.
      *
-     * @param remove criteria to be removed
+     * @param remove criterion to be removed
      */
-    void removeCriteria(Set<ResourceIdentifier> remove);
+    void removeCriteria(ResourceId remove) {
+        criteria.remove(remove);
+    }
 
     /**
-     * Method to list all the ResourceIdentifier criteria that are in place for a Filter.
+     * Removes the given ResourceId filtering criteria from a Filter object.
+     * If the ResourceId was NOT already part of the criteria for
+     * the object, it will not be removed, but will not throw any exceptions.
+     * This will not check for the validity of the ResourceId.
      *
-     * @return Set of ResourceIdentifier criteria for this entity
+     * @param removeAll criteria to be removed
      */
-    Set<ResourceIdentifier> getCriteria();
+    void removeCriteria(Set<ResourceId> removeAll) {
+        criteria.removeAll(removeAll);
+    }
+
+    /**
+     * Returns the criteria that are in place for a Filter.
+     *
+     * @return Set of ResourceId criteria
+     */
+    Set<ResourceId> criteria() {
+        return this.criteria;
+    }
 
     /**
      * Method to create a filter that include all entries rejected by the criteria.
      *
-     * @param original filter object with a criteria set
+     * @param original Filter object with a criteria set
      * @return Filter object with negated criteria set
      * @throws InvalidFilterException if the received Filter object
      * was null or if it had an empty criteria set
      */
-    Filter negateFilter(Filter original);
+    Filter negateFilter(Filter original) {
+        throw new FailedException("Not yet implemented");
+    }
 
     /**
-     * Method to check if the Filter has an empty criteria set.
+     * Returns if the Filter has an empty criteria set.
      *
-     * @return {@code true} if criteria set is empty, {@code true} otherwise.
+     * @return {@code true} if criteria set is empty, {@code false} otherwise.
      */
-    boolean isEmptyFilter();
+    boolean isEmptyFilter() {
+        return criteria.isEmpty();
+    }
 }
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/RpcCommand.java b/apps/config/src/main/java/org/onosproject/config/RpcCommand.java
index ada6b96..9274a3d 100644
--- a/apps/config/src/main/java/org/onosproject/config/RpcCommand.java
+++ b/apps/config/src/main/java/org/onosproject/config/RpcCommand.java
@@ -15,7 +15,7 @@
  */
 package org.onosproject.config;
 
-import org.onosproject.config.model.ResourceIdentifier;
+import org.onosproject.config.model.ResourceId;
 /**
  * Abstract implementation of an RPC command.
  */
@@ -23,14 +23,14 @@
     /**
      * Identifier of an RPC command.
      */
-    ResourceIdentifier cmdId;
+    ResourceId cmdId;
 
     /**
      * Creates an instance of RpcCommand.
      *
      * @param cmdId of RPC command
      */
-    public RpcCommand(ResourceIdentifier cmdId) {
+    public RpcCommand(ResourceId cmdId) {
         this.cmdId = cmdId;
     }
 
@@ -39,7 +39,7 @@
      *
      * @return cmdId
      */
-    public ResourceIdentifier cmdId() {
+    public ResourceId cmdId() {
         return this.cmdId;
     }
     /**
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
new file mode 100644
index 0000000..c7d570d
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DistributedDynamicConfigStore.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2016-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.config.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigStore;
+import org.onosproject.config.DynamicConfigStoreDelegate;
+import org.onosproject.config.FailedException;
+import org.onosproject.config.Filter;
+import org.onosproject.config.model.DataNode;
+import org.onosproject.config.model.InnerNode;
+import org.onosproject.config.model.LeafNode;
+import org.onosproject.config.model.NodeKey;
+import org.onosproject.config.model.ResourceId;
+import org.onosproject.config.model.SchemaId;
+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.DocumentPath;
+import org.onosproject.store.service.DocumentTreeEvent;
+import org.onosproject.store.service.DocumentTreeListener;
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.MapEventListener;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.Versioned;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Implementation of the dynamic config store.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedDynamicConfigStore
+        extends AbstractStore<DynamicConfigEvent, DynamicConfigStoreDelegate>
+        implements DynamicConfigStore {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+    private AsyncDocumentTree<DataNode.Type> keystore;
+    private ConsistentMap<ResourceId, LeafNode> objectStore;
+    private final DocumentTreeListener<DataNode.Type> klistener = new InternalDocTreeListener();
+    private final MapEventListener<ResourceId, LeafNode> olistener = new InternalMapListener();
+
+    @Activate
+    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)
+                .register(InnerNode.class)
+                .register(ResourceId.class)
+                .register(NodeKey.class)
+                .register(SchemaId.class)
+                .register(java.util.LinkedHashMap.class);
+        keystore = storageService.<DataNode.Type>documentTreeBuilder()
+                .withSerializer(Serializer.using(kryoBuilder.build()))
+                .withName("config-key-store")
+                .withRelaxedReadConsistency()
+                .buildDocumentTree();
+        objectStore = storageService.<ResourceId, LeafNode>consistentMapBuilder()
+                .withSerializer(Serializer.using(kryoBuilder.build()))
+                .withName("config-object-store")
+                .withRelaxedReadConsistency()
+                .build();
+        keystore.addListener(klistener);
+        objectStore.addListener(olistener);
+        log.info("DyanmicConfig Store Active");
+    }
+
+    @Deactivate
+    public void deactivateStore() {
+        keystore.removeListener(klistener);
+        objectStore.removeListener(olistener);
+        log.info("DyanmicConfig Store Stopped");
+    }
+
+    @Override
+    public CompletableFuture<Boolean>
+    addNode(ResourceId path, DataNode node) {
+        CompletableFuture<Boolean> eventFuture = CompletableFuture.completedFuture(false);
+        Boolean stat = false;
+        DocumentPath dpath  = DocumentPath.from(path.asString());
+        log.info("STORE: dpath to parent {}", dpath);
+        if (keystore.get(dpath).join() == null) {
+            throw new FailedException("Some of the parents are not present in " +
+                    "the requested path, please use a recursive create");
+        }
+        ResourceId cpath = path.builder()
+                .addBranchPointSchema(node.key().schemaId().name(),
+                                      node.key().schemaId().namespace()).build();
+        dpath  = DocumentPath.from(cpath.asString());
+        if (keystore.get(dpath).join() != null) {
+            throw new FailedException("Requested node already present in the" +
+                                              " store, please use an update method");
+        }
+        stat = checkNode(cpath, node);
+        if (stat) {
+            eventFuture = CompletableFuture.completedFuture(true);
+        } else {
+            log.info("STORE: FAILED to create node @ {}", path);
+        }
+        return eventFuture;
+    }
+
+    @Override
+    public CompletableFuture<DataNode> readNode(ResourceId path, Filter filter) {
+        CompletableFuture<DataNode> eventFuture = CompletableFuture.completedFuture(null);
+        DocumentPath dpath = DocumentPath.from(path.asString());
+        DataNode.Type type;
+        type = keystore.get(dpath).join().value();
+        if (type == null) {
+            throw new FailedException("Requested node or some of the parents" +
+                                              "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 = new InnerNode.Builder(key.schemaId().name(),
+                                          key.schemaId().namespace()).type(type);
+            readInner(superBldr, path);
+            retVal = superBldr.build();
+        }
+        if (retVal != null) {
+            eventFuture = CompletableFuture.completedFuture(retVal);
+        } else {
+            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(path.asString());
+      //TODO need to check for each parent in the path and recursively create all missing
+      /*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;
+  }
+    @Override
+    public CompletableFuture<Boolean> updateNode(ResourceId path, DataNode node) {
+        throw new FailedException("Not yet implemented");
+    }
+    @Override
+    public CompletableFuture<Boolean>
+    updateNodeRecursive(ResourceId path, DataNode node) {
+        throw new FailedException("Not yet implemented");
+    }
+    @Override
+    public CompletableFuture<Boolean>
+    replaceNode(ResourceId path, DataNode node) {
+        throw new FailedException("Not yet implemented");
+    }
+    @Override
+    public CompletableFuture<Boolean>
+    deleteNode(ResourceId path) {
+        throw new FailedException("Not yet implemented");
+    }
+    @Override
+    public CompletableFuture<Boolean>
+    deleteNodeRecursive(ResourceId path) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    private Boolean addLeaf(ResourceId path, LeafNode node) {
+        objectStore.put(path, node);
+        return (keystore.create(DocumentPath.from(path.asString()), node.type()).join());
+    }
+
+    private Boolean addKey(ResourceId path, DataNode.Type type) {
+        return (keystore.create(DocumentPath.from(path.asString()), 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");
+        }
+    }
+
+    private LeafNode readLeaf(ResourceId path) {
+        return objectStore.get(path).value();
+    }
+
+    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);
+            } else {
+                throw new FailedException("Node type should either be LEAF or INNERNODE");
+            }
+        });
+        return true;
+    }
+
+    private void readInner(DataNode.Builder superBldr, ResourceId path) {
+        Map<String, Versioned<DataNode.Type>> entries = keystore.getChildren(
+                DocumentPath.from(path.asString())).join();
+        if (entries.size() == 0) {
+            throw new FailedException("Inner node cannot have empty children map");
+        }
+        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("key created in store");
+                    break;
+                case UPDATED:
+                    log.info("key updated in store");
+                    break;
+                case DELETED:
+                    log.info("key deleted in store");
+                    break;
+
+                default:
+            }
+            //notify
+        }
+    }
+
+    public class InternalMapListener implements MapEventListener<ResourceId, LeafNode> {
+        @Override
+        public void event(MapEvent<ResourceId, LeafNode> event) {
+            switch (event.type()) {
+                case INSERT:
+                    log.info("OBJECT created in store");
+                    break;
+                case UPDATE:
+                    log.info("OBJECT updated in store");
+                    break;
+                case REMOVE:
+                default:
+                    log.info("OBJECT removed in store");
+                    break;
+            }
+            //notify
+        }
+    }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..a4ea428
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/impl/DynamicConfigManager.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016-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.config.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onosproject.config.DynamicConfigEvent;
+import org.onosproject.config.DynamicConfigListener;
+import org.onosproject.config.DynamicConfigService;
+import org.onosproject.config.DynamicConfigStore;
+import org.onosproject.config.DynamicConfigStoreDelegate;
+import org.onosproject.config.FailedException;
+import org.onosproject.config.Filter;
+import org.onosproject.config.RpcCaller;
+import org.onosproject.config.RpcCommand;
+import org.onosproject.config.RpcHandler;
+import org.onosproject.config.RpcInput;
+import org.onosproject.config.RpcOutput;
+import org.onosproject.config.model.DataNode;
+import org.onosproject.config.model.ResourceId;
+import org.onosproject.event.AbstractListenerManager;
+import org.onosproject.event.EventDeliveryService;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Demo application to use the DynamicConfig Service and DynamicConfigStore.
+ *
+ */
+@Component(immediate = true)
+@Service
+public class DynamicConfigManager
+        extends AbstractListenerManager<DynamicConfigEvent, DynamicConfigListener>
+        implements DynamicConfigService {
+    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);
+        log.info("DynamicConfigService Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        store.unsetDelegate(storeDelegate);
+        log.info("DynamicConfigService Stopped");
+    }
+
+    @Override
+    public void createNode(ResourceId path, DataNode node) {
+        Boolean stat = false;
+        stat = this.store.addNode(path, node).join();
+    }
+
+    public void createNodeRecursive(ResourceId path, DataNode node) {
+        Boolean stat = false;
+        stat = this.store.addRecursive(path, node).join();
+    }
+
+    public DataNode readNode(ResourceId path, Filter filter) {
+        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");
+    }
+
+    public void deleteNode(ResourceId path) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void deleteNodeRecursive(ResourceId path) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void updateNodeRecursive(ResourceId path, DataNode node) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void replaceNode(ResourceId path, DataNode node) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void addConfigListener(ResourceId path, DynamicConfigListener listener) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void removeConfigListener(ResourceId path, DynamicConfigListener listener) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void registerHandler(RpcHandler handler, RpcCommand command) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void unRegisterHandler(RpcHandler handler, RpcCommand command) {
+        //check obj1.getClass().equals(obj2.getClass())
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void invokeRpc(RpcCaller caller, Integer msgId, RpcCommand command, RpcInput input) {
+        throw new FailedException("Not yet implemented");
+    }
+
+    public void rpcResponse(Integer msgId, RpcOutput output) {
+        throw new FailedException("Not yet implemented");
+    }
+    /**
+     * Auxiliary store delegate to receive notification about changes in
+     * the prop configuration store state - by the store itself.
+     */
+    private class InternalStoreDelegate implements DynamicConfigStoreDelegate {
+        public void notify(DynamicConfigEvent event) {
+            // TODO
+            // post(event);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/impl/package-info.java b/apps/config/src/main/java/org/onosproject/config/impl/package-info.java
index 63a91d1..563c244 100755
--- a/apps/config/src/main/java/org/onosproject/config/impl/package-info.java
+++ b/apps/config/src/main/java/org/onosproject/config/impl/package-info.java
@@ -16,8 +16,5 @@
 
 /**
  * Dynamic config service App and Store implementation.
- * Work in progress; would change considerably based on
- * the DataNode and ResourceId implementations.
- * These are to be looked upon as placeholders
  */
 package org.onosproject.config.impl;
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/DataNode.java b/apps/config/src/main/java/org/onosproject/config/model/DataNode.java
index 5c43304..f0a94f0 100755
--- a/apps/config/src/main/java/org/onosproject/config/model/DataNode.java
+++ b/apps/config/src/main/java/org/onosproject/config/model/DataNode.java
@@ -15,102 +15,17 @@
  */
 package org.onosproject.config.model;
 
-import java.util.LinkedHashMap;
-
 /**
- * Hollow definition of DataNode for ConfigService APIs.
+ * Abstraction of an entity which represents data tree node. Information
+ * exchange between YANG runtime, protocol and store will be based on this
+ * node, agnostic of schema.
  */
-public interface DataNode {
-    //will remove this when the corresponding changes in onos-yang-tools become available
+public abstract class DataNode {
 
-    /**
-     * Builder for DataNode.
-     */
-    interface Builder<V> {
-        /**
-         * clones a base Data node obj to a new one.
-         *
-         * @param base base DataNode obj to be cloned
-         * @return a DataNode builder
-         */
-        Builder addBaseObj(DataNode base);
-        /**
-         * Adds the value of the instance node.
-         *
-         * @param key of the node
-         * @return a DataNode builder
-         */
-        Builder addKey(NodeKey key);
-        /**
-         * Adds the value of the instance node.
-         *
-         * @param type of the node
-         * @return a DataNode builder
-         */
-        Builder addType(DataNode.Type type);
-        /**
-         * Adds the value of the leaf node.
-         *
-         * @param value at the node
-         * @return a DataNode builder
-         */
-        Builder addValue(String value);
-
-        /**
-         * Adds children to the children field.
-         *
-         * @param children to be added
-         * @return a DataNode builder
-         */
-        //Builder addChildren(LinkedHashMap<NodeKey, DataNode> children);
-
-        /**
-         * Builds an immutable DataNode entity.
-         *
-         * @return DataNode
-         */
-        DataNode build();
-    }
-
-    /**
-     * Returns the children if DataNode contains an inner node.
-     *
-     * @return LinkedHashMap of children for an inner node, null for a leaf node
-     */
-    LinkedHashMap<NodeKey, DataNode> children();
-
-    /**
-     * Returns the value at the leaf node as a string.
-     *
-     * @return value at the leaf node as a string, null if it is an innernode
-     */
-    String value();
-
-    /**
-     * Returns the node schema identifier.
-     *
-     * @return node schema identifier
-     */
-    SchemaIdentifier identifier();
-
-    /**
-     * Returns the type of node.
-     *
-     * @return node type
-     */
-    Type type();
-
-    /**
-     * Returns the key to identify a branching node.
-     *
-     * @return key to identify a branching node
-     */
-    NodeKey key();
-
-    /**
+    /*
      * Represents type of node in data store.
      */
-    enum Type {
+    public enum Type {
 
         /**
          * Single instance node.
@@ -132,4 +47,237 @@
          */
         MULTI_INSTANCE_LEAF_VALUE_NODE
     }
+
+    /**
+     * Type of node in data store.
+     */
+    protected Type type;
+
+    /**
+     * Identifies a node uniquely among its siblings.
+     */
+    protected NodeKey key;
+
+    /**
+     * Returns the type of node.
+     *
+     * @return node type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the key to identify a branching node.
+     *
+     * @return key to identify a branching node
+     */
+    public NodeKey key() {
+        return key;
+    }
+
+    /**
+     * Creates an instance of data node.
+     *
+     * @param builder data node builder
+     */
+    protected DataNode(Builder builder) {
+        type = builder.type;
+        key = builder.key;
+    }
+
+    /**
+     * Returns data node builder for a given data node.
+     * It contains all the attributes from the data node. It is to provide
+     * mutability of data node using builder pattern.
+     *
+     * @return data node builder
+     */
+    public abstract Builder copyBuilder();
+
+    /**
+     * Represents the implementation of data node builder class.
+     *
+     * @param <B> type of data node builder
+     */
+    public abstract static  class Builder<B extends Builder<B>> {
+
+        /**
+         * Type of node in data store.
+         */
+        protected Type type;
+
+        /**
+         * Identifies a node uniquely among its siblings.
+         */
+        protected NodeKey key;
+
+        /**
+         * Node key builder.
+         */
+        protected NodeKey.NodeKeyBuilder keyBuilder;
+
+        /**
+         * Parent data node.
+         */
+        protected InnerNode.Builder parent;
+
+        /**
+         * Creates an instance of data node builder.
+         */
+        protected Builder() {
+        }
+
+        /**
+         * Creates an instance of data node builder using old data node.
+         *
+         * @param node data node which
+         */
+        protected Builder(DataNode node) {
+            type = node.type;
+            key = node.key;
+        }
+
+        /**
+         * Sets node key in builder object.
+         * when serializers have an instance of key present with them they can
+         * directly set the key value using this method.
+         *
+         * @param key node key identifier
+         * @return data node builder object
+         */
+        public B key(NodeKey key) {
+            this.key = key;
+            return (B) this;
+        }
+
+        /**
+         * Sets parent node's builder.
+         *
+         * @param node parent node builder
+         * @return builder object
+         */
+        protected B parent(InnerNode.Builder node) {
+            parent = node;
+            return (B) this;
+        }
+
+        /**
+         * Sets node type in builder object.
+         *
+         * @param type node type
+         * @return data node builder
+         */
+        public B type(Type type) {
+            this.type = type;
+            return (B) this;
+        }
+
+        /**
+         * Creates a child builder of type inner node and set a back reference
+         * of parent node. it is used while creating a data tree.
+         *
+         * @param name      name of inner node
+         * @param nameSpace namespace of inner node
+         * @return child node builder
+         */
+        public abstract InnerNode.Builder createChildBuilder(
+                String name, String nameSpace);
+
+        /**
+         * Creates a child build of type leaf node and set a back reference
+         * of parent node. it is used while creating a data tree. the value
+         * of leaf is set while creation.
+         *
+         * @param name      name of leaf node
+         * @param nameSpace namespace of leaf node
+         * @param value     value for leaf node
+         * @return child node builder
+         */
+        public abstract LeafNode.Builder createChildBuilder(
+                String name, String nameSpace, Object value);
+
+        /**
+         * Deletes child node for a given node key from parent node.
+         * <p>
+         * for deleting a node from data tree , caller should parse resource
+         * identifier to reach to the child node. while parsing the resource
+         * identifier caller need to create a new data node using copy
+         * builder. this copy builder can be used further to create child
+         * nodes copy builders.
+         *
+         * @param key node key for child node
+         * @return data node builder
+         */
+        public abstract InnerNode.Builder deleteChild(NodeKey key);
+
+        /**
+         * Returns a child node builder for a given node key. it contains all
+         * the attribute of child node. it is used to modify the data tree
+         * while delete or update operations.
+         * <p>
+         * this method provides copy builder of child node when a
+         * update/delete request comes. it sets a back reference of parent
+         * node as well in child node's copy builder.
+         *
+         * @param key data node key
+         * @return child node
+         */
+        public abstract InnerNode.Builder getChildBuilder(NodeKey key);
+
+
+        /**
+         * Add key leaf for list node key. It can be used while handling a
+         * list node when in your yang file you have multiple key leaves.
+         * <p>
+         * this method is used for adding multiple key leaves in you list
+         * node. these keys will be added to key builder which is built while
+         * while node building. To use this method caller should know about
+         * schema of list and key leaves.
+         *
+         * @param name      name of leaf node
+         * @param nameSpace namespace of leaf node
+         * @param val       value of leaf
+         * @return data node builder
+         */
+        public abstract InnerNode.Builder addKeyLeaf(String name, String nameSpace,
+                                                     Object val);
+
+        /**
+         * Add key value to leaf list key. this can be used while handling a
+         * leaf list where you need to add multiple values.
+         *
+         * @param val value
+         * @return data node builder
+         */
+        public abstract LeafNode.Builder addLeafListValue(Object val);
+
+        /**
+         * Builds data node.
+         *
+         * @return data node
+         */
+        public abstract DataNode build();
+
+        /**
+         * Returns parent node builder after building and adding the child
+         * node to parent's child node map.
+         * <p>
+         * This method is used when caller has reached to the depth of the
+         * subtree and then he wants to go back to its parent node so he
+         * should build the node and then it should add it to parent node's
+         * map. this method provides both the functionalities of build and
+         * add to parent . Also it returns back the parent pointer so caller
+         * can do further operations on data tree.
+         *
+         * @return parent's builder object
+         */
+        public InnerNode.Builder exitNode() {
+            if (parent != null) {
+                parent.addNode(build());
+            }
+            return parent;
+        }
+    }
 }
+
diff --git a/apps/config/src/main/java/org/onosproject/config/model/DefaultDataNode.java b/apps/config/src/main/java/org/onosproject/config/model/DefaultDataNode.java
deleted file mode 100755
index 44b8c1e..0000000
--- a/apps/config/src/main/java/org/onosproject/config/model/DefaultDataNode.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2016-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.config.model;
-
-import java.util.LinkedHashMap;
-
-/**
- * Representation of an instance node in the Dynamic config store.
- */
-public final class DefaultDataNode implements DataNode {
-    DataNode.Type type;
-    NodeKey key;
-    //Object value;
-    String value;
-    LinkedHashMap<NodeKey, DataNode> children;
-
-    /**
-     * Creates a new DefaultDataNode.
-     *
-     * @param key node key
-     * @param type of the node
-     * @param value of leaf node
-     * @param children of the inner node
-     */
-    private DefaultDataNode(NodeKey key, DataNode.Type type,
-                            String value, LinkedHashMap<NodeKey, DataNode> children) {
-        this.type = type;
-        this.key = key;
-        this.value = value;
-        this.children = children;
-    }
-    /**
-     *
-     */
-    /**
-     * Creates a new DefaultDataNode.
-     *
-     * @param node to be cloned
-     * @param value of leaf node
-     */
-    private DefaultDataNode(DataNode node, String value) {
-        this.type = node.type();
-        this.key = node.key();
-        this.value = value;
-        this.children = null;
-    }
-    /**
-     * Creates a new DefaultDataNode.
-     *
-     * @param node to be cloned
-     * @param children to be added
-     */
-    private DefaultDataNode(DataNode node, LinkedHashMap<NodeKey, DataNode> children) {
-        this.type = node.type();
-        this.key = node.key();
-        this.value = null;
-        this.children = children;
-    }
-
-    @Override
-    public LinkedHashMap<NodeKey, DataNode> children() {
-        return this.children;
-    }
-
-    @Override
-    public  String value() {
-        return value;
-        //return value.toString();
-    }
-
-
-    /**
-     * Creates and returns a new builder instance.
-     *
-     * @return new builder
-     */
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static final class Builder<V> implements DataNode.Builder {
-
-        private DataNode.Type type;
-        private NodeKey key;
-        //Object value;
-        private String value;
-        private LinkedHashMap<NodeKey, DataNode> children;
-
-        private Builder() {
-            this.type = null;
-            this.key = null;
-            this.value = null;
-            this.children = null;
-        }
-
-        @Override
-        public Builder addBaseObj(DataNode base) {
-            this.key = base.key();
-            this.type = base.type();
-            this.value = base.value();
-            this.children = base.children();
-            return this;
-        }
-
-        @Override
-        public Builder addKey(NodeKey key) {
-            this.key = key;
-            return this;
-        }
-
-        @Override
-        public Builder addType(DataNode.Type type) {
-            this.type = type;
-            return this;
-        }
-
-        @Override
-        public Builder addValue(String value) {
-            this.value = value;
-            return this;
-        }
-
-        //@Override
-        public Builder addChildren(LinkedHashMap<NodeKey, DataNode> children) {
-            this.children = children;
-            return this;
-        }
-
-        @Override
-        public DataNode build() {
-            return new DefaultDataNode(this.key, this.type, this.value, this.children);
-        }
-    }
-
-
-    @Override
-    public SchemaIdentifier identifier() {
-        return this.key.schemaId;
-    }
-
-    @Override
-    public Type type() {
-        return this.type;
-    }
-
-    @Override
-    public NodeKey key() {
-        return this.key;
-    }
-}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/DefaultResourceIdentifier.java b/apps/config/src/main/java/org/onosproject/config/model/DefaultResourceIdentifier.java
deleted file mode 100755
index 63aba40..0000000
--- a/apps/config/src/main/java/org/onosproject/config/model/DefaultResourceIdentifier.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016-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.config.model;
-
-/**
- * Created by sdn on 12/15/16.
- */
-public class DefaultResourceIdentifier<V> implements ResourceIdentifier     {
-    NodeKey key;
-    ResourceIdentifier next;
-
-    public DefaultResourceIdentifier(String nm, String nmspc) {
-        this.key = new NodeKey(nm, nmspc);
-        this.next = null;
-    }
-
-    public DefaultResourceIdentifier(ResourceIdentifier parent, NodeKey ckey) {
-        this.key = parent.nodeKey();
-        //new NodeKey(parent.nodeKey().schemaId.name, parent.nodeKey().schemaId.nameSpace);
-        this.next = new DefaultResourceIdentifier(ckey);
-    }
-
-    public DefaultResourceIdentifier(ResourceIdentifier parent, ResourceIdentifier child) {
-        this.key = parent.nodeKey();
-        this.next = child;
-    }
-
-    public DefaultResourceIdentifier(NodeKey nkey) {
-        this.key = nkey;
-        this.next = null;
-    }
-
-    /*public void setChild(NodeKey ckey) {
-        this.next = new DefaultResourceIdentifier(ckey);
-    }*/
-
-    @Override
-    public NodeKey nodeKey() {
-        return this.key;
-    }
-
-    @Override
-    public ResourceIdentifier descendentIdentifier() {
-        return this.next;
-    }
-
-    @Override
-    public String getBase() {
-        return this.key.schemaId.name.concat("#").concat(this.key.schemaId.nameSpace);
-    }
-
-    @Override
-    public String asString() {
-        String base = getBase();
-        ResourceIdentifier desc = next;
-        while (desc != null) {
-            base.concat(".").concat(desc.getBase());
-            desc = desc.descendentIdentifier();
-        }
-        return base;
-    }
-}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/InnerNode.java b/apps/config/src/main/java/org/onosproject/config/model/InnerNode.java
new file mode 100644
index 0000000..2a0dfee
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/InnerNode.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2016-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.config.model;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.onosproject.config.model.ModelConstants.LEAF_IS_TERMINAL;
+
+/**
+ * Abstraction of an entity which represents an inner node in data store.
+ */
+public final class InnerNode extends DataNode {
+
+    /**
+     * Map containing info of all child data nodes with respect to their node
+     * keys.
+     */
+    private Map<NodeKey, DataNode> childNodes = new LinkedHashMap<>();
+
+    /**
+     * Returns the children nodes to the current node.
+     * Children nodes are identified based on the node key.
+     *
+     * @return read only linked map of children nodes
+     */
+    public Map<NodeKey, DataNode> childNodes() {
+        return childNodes;
+    }
+
+    /**
+     * Creates an instance of inner node.
+     *
+     * @param builder inner node builder
+     */
+    public InnerNode(Builder builder) {
+        super(builder);
+        childNodes = builder.childNodes;
+    }
+
+    /**
+     * Returns inner node builder instance.
+     *
+     * @param name      name of node
+     * @param nameSpace namespace of node
+     * @return inner node builder instance
+     */
+    public static Builder builder(String name, String nameSpace) {
+        return new Builder(name, nameSpace);
+    }
+
+    /**
+     * Returns inner node copy builder.
+     *
+     * @return inner node copy builder
+     */
+    @Override
+    public Builder copyBuilder() {
+        return new Builder(this);
+    }
+
+    /**
+     * Builder with get and set functions to build inner node,
+     * builder will be used both to create inner node from scratch or from a
+     * given inner node.
+     */
+    public static class Builder extends DataNode.Builder<Builder> {
+
+        /**
+         * Map containing info of all child data nodes with respect to their
+         * node keys.
+         */
+        private Map<NodeKey, DataNode> childNodes = new LinkedHashMap<>();
+
+        public Builder() {
+        }
+        /**
+         * Creates an instance of data node builder.
+         *
+         * @param name      name of node
+         * @param namespace namespace of node
+         */
+        public Builder(String name, String namespace) {
+            keyBuilder = NodeKey.builder().schemaId(name, namespace);
+        }
+
+        /**
+         * Creates an instance of inner node builder.
+         *
+         * @param node old inner node
+         */
+        public Builder(InnerNode node) {
+            super(node);
+            childNodes = node.childNodes;
+        }
+
+        /**
+         * Adds node to the builder.
+         *
+         * @param node node to be added
+         * @return inner node builder
+         */
+        public Builder addNode(DataNode node) {
+            childNodes.put(node.key(), node);
+            return this;
+        }
+
+        /**
+         * Builds a inner node object.
+         *
+         * @return inner node
+         */
+        @Override
+        public InnerNode build() {
+            if (type == null) {
+                throw new IllegalStateException("node should have a type.");
+            }
+            if (key == null) {
+                key = keyBuilder.build();
+            }
+            return new InnerNode(this);
+        }
+
+        @Override
+        public InnerNode.Builder createChildBuilder(String name, String nameSpace) {
+            return InnerNode.builder(name, nameSpace)
+                    .parent(this);
+        }
+
+        @Override
+        public LeafNode.Builder createChildBuilder(String name, String nameSpace,
+                                                   Object value) {
+            return LeafNode.builder(name, nameSpace)
+                    .parent(this)
+                    .value(value);
+        }
+
+        @Override
+        public InnerNode.Builder deleteChild(NodeKey key) {
+            childNodes.remove(key);
+            return this;
+        }
+
+        @Override
+        public Builder getChildBuilder(NodeKey nodeKey) {
+            DataNode node = childNodes.get(nodeKey);
+            if (node == null) {
+                throw new IllegalArgumentException(
+                        "Invalid key: no child nodes found for given key: " +
+                                nodeKey);
+            }
+            return (Builder) node.copyBuilder().parent(this);
+        }
+
+        @Override
+        public Builder addKeyLeaf(String name, String nameSpace, Object val) {
+            ListKey.ListKeyBuilder listKeyBuilder;
+            if (!(keyBuilder instanceof ListKey.ListKeyBuilder)) {
+                if (keyBuilder instanceof LeafListKey.LeafListKeyBuilder) {
+                    throw new ModelException(LEAF_IS_TERMINAL);
+                }
+
+                listKeyBuilder = new ListKey.ListKeyBuilder(keyBuilder);
+            } else {
+                listKeyBuilder = (ListKey.ListKeyBuilder) keyBuilder;
+            }
+
+            listKeyBuilder.addKeyLeaf(name, nameSpace, val);
+            keyBuilder = listKeyBuilder;
+            return this;
+        }
+
+        @Override
+        public LeafNode.Builder addLeafListValue(Object val) {
+            throw new IllegalStateException("node is not of leaf list type.");
+        }
+    }
+}
diff --git a/apps/config/src/main/java/org/onosproject/config/model/KeyLeaf.java b/apps/config/src/main/java/org/onosproject/config/model/KeyLeaf.java
new file mode 100644
index 0000000..1f21687
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/KeyLeaf.java
@@ -0,0 +1,109 @@
+/*
+ * 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.config.model;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.hash;
+
+/**
+ * Represents the List's key leaf value.
+ */
+public class KeyLeaf implements Cloneable {
+
+    private SchemaId leafSchema;
+    private Object leafVal;
+
+    private KeyLeaf() {
+    }
+
+    /**
+     * Constructs a key leaf with all the identifier and value initialized.
+     *
+     * @param name      name of the leaf
+     * @param nameSpace namespace of leaf
+     * @param leafVal   value of leaf
+     */
+    public KeyLeaf(String name, String nameSpace, Object leafVal) {
+        leafSchema = new SchemaId(name, nameSpace);
+        this.leafVal = leafVal;
+    }
+
+    /**
+     * Creates and returns a deep copy of this object.
+     *
+     * @return cloned copy
+     * @throws CloneNotSupportedException if the object's class does not
+     *                                    support the {@code Cloneable} interface
+     */
+    public KeyLeaf clone() throws CloneNotSupportedException {
+        KeyLeaf clonedLeaf = (KeyLeaf) super.clone();
+        clonedLeaf.leafSchema = leafSchema.clone();
+        return clonedLeaf;
+    }
+
+    /**
+     * Returns the node schema schemaId.
+     *
+     * @return node schema schemaId
+     */
+    public SchemaId leafSchema() {
+        return leafSchema;
+    }
+
+    /**
+     * Returns value contained in leaf node.
+     *
+     * @return value contained in leaf node
+     */
+    public Object leafValue() {
+        return leafVal;
+    }
+
+    /**
+     * Returns value as string, for usage in serializers.
+     *
+     * @return string representation of value
+     */
+    public String leafValAsString() {
+        return leafVal.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return hash(leafSchema, leafVal);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        KeyLeaf that = (KeyLeaf) obj;
+        return Objects.equals(leafSchema, that.leafSchema) &&
+                Objects.equals(leafVal, that.leafVal);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("schemaId", leafSchema)
+                .add("leafValue", leafVal)
+                .toString();
+    }
+}
diff --git a/apps/config/src/main/java/org/onosproject/config/model/LeafListKey.java b/apps/config/src/main/java/org/onosproject/config/model/LeafListKey.java
new file mode 100644
index 0000000..c532ae2
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/LeafListKey.java
@@ -0,0 +1,132 @@
+/*
+ * 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.config.model;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Representation of an entity which identifies a uniquely branching
+ * leaf-list entry corresponding to a multi instance leaf schema.
+ */
+public final class LeafListKey extends NodeKey<LeafListKey>
+        implements Comparable<LeafListKey> {
+    private Object val;
+
+    /**
+     * Create object from builder.
+     *
+     * @param builder initialized builder
+     */
+    private LeafListKey(LeafListKeyBuilder builder) {
+        super(builder);
+        val = builder.val;
+    }
+
+    /**
+     * Returns value of node, this is only valid for multi-instance leaf, node.
+     *
+     * @return value maintained in the node
+     */
+    Object value() {
+        return val;
+    }
+
+    /**
+     * Returns value as string, for usage in serializers.
+     *
+     * @return string representation of value
+     */
+    String asString() {
+        return val.toString();
+    }
+
+    /**
+     * Creates and returns a deep copy of this object.
+     *
+     * @return cloned copy
+     * @throws CloneNotSupportedException if the object's class does not
+     *                                    support the {@code Cloneable} interface
+     */
+    public LeafListKey clone() throws CloneNotSupportedException {
+        return (LeafListKey) super.clone();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(schemaId, val);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (!getClass().equals(obj.getClass())) {
+            return false;
+        }
+
+        LeafListKey that = (LeafListKey) obj;
+        return Objects.equals(val, that.val) &&
+                Objects.equals(schemaId, that.schemaId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("value", val)
+                .toString();
+    }
+
+    /**
+     * Represents Leaf list key builder.
+     */
+    public static class LeafListKeyBuilder
+            extends NodeKeyBuilder<LeafListKeyBuilder> {
+
+        private Object val;
+
+        /**
+         * constructor used while constructing the key from scratch.
+         */
+        public LeafListKeyBuilder() {
+
+        }
+
+        /**
+         * Adds the value for for the leaf list node identifier.
+         *
+         * @param val leaf list value
+         * @return LeafListKeyBuilder
+         */
+        LeafListKeyBuilder value(Object val) {
+            this.val = val;
+            return this;
+        }
+
+        /**
+         * Creates a leaf list entry identifier.
+         *
+         * @return leaf list entry identifier
+         */
+        public LeafListKey build() {
+            return new LeafListKey(this);
+        }
+    }
+}
diff --git a/apps/config/src/main/java/org/onosproject/config/model/LeafNode.java b/apps/config/src/main/java/org/onosproject/config/model/LeafNode.java
new file mode 100644
index 0000000..44319c8
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/LeafNode.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2016-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.config.model;
+
+import static org.onosproject.config.model.ModelConstants.NON_KEY_LEAF;
+
+/**
+ * Abstraction of an entity which represents leaf data tree node.
+ */
+public final class LeafNode extends DataNode {
+
+    /**
+     * Leaf node value.
+     */
+    private Object value;
+
+    /**
+     * Returns value contained in leaf node.
+     *
+     * @return value contained in leaf node
+     */
+    public Object value() {
+        return value;
+    }
+
+    /**
+     * Returns value as string, for usage in serializers.
+     *
+     * @return string representation of value
+     */
+    public String asString() {
+        return String.valueOf(value);
+    }
+
+    /**
+     * Creates an instance of leaf node.
+     *
+     * @param builder leaf node builder
+     */
+    public LeafNode(Builder builder) {
+        super(builder);
+        value = builder.value;
+    }
+
+    /**
+     * Returns data node builder instance.
+     *
+     * @param name      name of node
+     * @param nameSpace namespace of node
+     * @return data node builder instance
+     */
+    public static Builder builder(String name, String nameSpace) {
+        return new Builder(name, nameSpace);
+    }
+
+    /**
+     * Returns data node copy builder.
+     *
+     * @return data node copy builder
+     */
+    @Override
+    public Builder copyBuilder() {
+        return new Builder(this);
+    }
+
+    /**
+     * Builder with get and set functions to build leaf node,
+     * builder will be used both to create leaf node from scratch or from a
+     * given leaf node.
+     */
+    public static final  class Builder extends DataNode.Builder<Builder> {
+
+        /**
+         * Leaf node value.
+         */
+        private Object value;
+
+        public Builder() {
+        }
+
+        /**
+         * Creates an instance of data node builder.
+         *
+         * @param name      name of node
+         * @param namespace namespace of node
+         */
+        public Builder(String name, String namespace) {
+            keyBuilder = NodeKey.builder().schemaId(name, namespace);
+        }
+
+        /**
+         * Creates an instance of leaf node copy builder.
+         *
+         * @param node old leaf node
+         */
+        public Builder(LeafNode node) {
+            super(node);
+            value = node.value;
+        }
+
+        /**
+         * Sets value of leaf node builder.
+         *
+         * @param value value
+         * @return leaf node builder
+         */
+        public Builder value(Object value) {
+            this.value = value;
+            return this;
+        }
+
+        @Override
+        public InnerNode.Builder createChildBuilder(String name, String nameSpace) {
+            throw new IllegalStateException("leaf node can't have a child " +
+                                                    "node");
+        }
+
+        @Override
+        public LeafNode.Builder createChildBuilder(String name, String nameSpace,
+                                                   Object value) {
+            throw new IllegalStateException("leaf node can't have a child " +
+                                                    "node");
+        }
+
+        @Override
+        public InnerNode.Builder deleteChild(NodeKey key) {
+            throw new IllegalStateException("leaf node can't have a child " +
+                                                    "node");
+        }
+
+        @Override
+        public InnerNode.Builder getChildBuilder(NodeKey key) {
+            throw new IllegalStateException("leaf node can't have a child " +
+                                                    "node");
+        }
+
+
+        @Override
+        public InnerNode.Builder addKeyLeaf(String name, String nameSpace, Object val) {
+            throw new IllegalStateException("leaf node can't have a key " +
+                                                    "leaves node");
+        }
+
+        @Override
+        public Builder addLeafListValue(Object val) {
+            LeafListKey.LeafListKeyBuilder leafListKeyBuilder;
+            if (!(keyBuilder instanceof LeafListKey.LeafListKeyBuilder)) {
+                if (keyBuilder instanceof ListKey.ListKeyBuilder) {
+                    throw new ModelException(NON_KEY_LEAF);
+                }
+
+                leafListKeyBuilder = new LeafListKey.LeafListKeyBuilder();
+                NodeKey key = keyBuilder.build();
+                leafListKeyBuilder.schemaId(key.schemaId());
+            } else {
+                leafListKeyBuilder = (LeafListKey.LeafListKeyBuilder) keyBuilder;
+            }
+
+            leafListKeyBuilder.value(val);
+            keyBuilder = leafListKeyBuilder;
+            return this;
+        }
+
+        /**
+         * Builds a leaf node object.
+         *
+         * @return leaf node
+         */
+        @Override
+        public LeafNode build() {
+            if (type == null) {
+                throw new IllegalStateException("node should have a type.");
+            }
+            if (key == null) {
+                key = keyBuilder.build();
+            }
+            return new LeafNode(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/ListKey.java b/apps/config/src/main/java/org/onosproject/config/model/ListKey.java
new file mode 100644
index 0000000..617efaf
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/ListKey.java
@@ -0,0 +1,147 @@
+/*
+ * 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.config.model;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents an entity which identifies a unique branching node
+ * corresponding to a multi instance schema definition.
+ */
+public final class ListKey extends NodeKey<ListKey> implements Comparable<ListKey> {
+
+    private List<KeyLeaf> keyLeafs;
+
+    /**
+     * Create object from builder.
+     *
+     * @param builder initialized builder
+     */
+    private ListKey(ListKeyBuilder builder) {
+        super(builder);
+        keyLeafs = builder.keyLeafs;
+    }
+
+    /**
+     * Returns the list of key leaf nodes of a multi instance node, which
+     * uniquely identifies the branching node entry corresponding to a multi
+     * instance schema definition.
+     *
+     * @return List of key leaf nodes
+     */
+    List<KeyLeaf> keyLeafs() {
+        return keyLeafs;
+    }
+
+    /**
+     * Creates and returns a deep copy of this object.
+     *
+     * @return cloned copy
+     * @throws CloneNotSupportedException if the object's class does not
+     *                                    support the {@code Cloneable} interface
+     */
+    public ListKey clone() throws CloneNotSupportedException {
+        ListKey clonedListKey = (ListKey) super.clone();
+        List<KeyLeaf> clonedKeyLeafs = new LinkedList<>();
+        for (KeyLeaf leaf : keyLeafs) {
+            clonedKeyLeafs.add(leaf.clone());
+        }
+        clonedListKey.keyLeafs = clonedKeyLeafs;
+        return clonedListKey;
+    }
+
+    public int compareTo(ListKey o) {
+        //TODO: implement me
+        return 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(schemaId, keyLeafs);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (!getClass().equals(obj.getClass())) {
+            return false;
+        }
+
+        ListKey that = (ListKey) obj;
+        List<KeyLeaf> thatList = that.keyLeafs;
+        return keyLeafs.size() == thatList.size() &&
+                keyLeafs.containsAll(thatList) &&
+                Objects.equals(schemaId, that.schemaId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("value", keyLeafs)
+                .toString();
+    }
+
+    /**
+     * Represents list key builder.
+     */
+    public static class ListKeyBuilder extends NodeKeyBuilder<ListKeyBuilder> {
+        private List<KeyLeaf> keyLeafs = new LinkedList<>();
+
+        /**
+         * used to construct the key from scratch.
+         */
+        public ListKeyBuilder() {
+        }
+
+        /**
+         * used to construct a key from an existing node key.
+         *
+         * @param base existing node key
+         */
+        public ListKeyBuilder(NodeKeyBuilder base) {
+            super(base);
+        }
+
+        /**
+         * Adds the key leaf for the list resource.
+         *
+         * @param name      key leaf name
+         * @param nameSpace key laef namespace
+         * @param val       value of key
+         */
+        void addKeyLeaf(String name, String nameSpace, Object val) {
+            KeyLeaf keyLeaf = new KeyLeaf(name, nameSpace, val);
+            keyLeafs.add(keyLeaf);
+        }
+
+        /**
+         * Creates the list key object.
+         *
+         * @return list key
+         */
+        public ListKey build() {
+            return new ListKey(this);
+        }
+    }
+}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/SchemaIdentifier.java b/apps/config/src/main/java/org/onosproject/config/model/ModelConstants.java
old mode 100755
new mode 100644
similarity index 62%
rename from apps/config/src/main/java/org/onosproject/config/model/SchemaIdentifier.java
rename to apps/config/src/main/java/org/onosproject/config/model/ModelConstants.java
index 20ce4cb..532de78
--- a/apps/config/src/main/java/org/onosproject/config/model/SchemaIdentifier.java
+++ b/apps/config/src/main/java/org/onosproject/config/model/ModelConstants.java
@@ -16,13 +16,14 @@
 package org.onosproject.config.model;
 
 /**
- * Created by sdn on 12/15/16.
+ * Constants used in model package.
  */
-public class SchemaIdentifier {
-    String name;
-    String nameSpace;
-    SchemaIdentifier(String nm, String nmspc) {
-        this.name = nm;
-        this.nameSpace = nmspc;
+final class ModelConstants {
+    private ModelConstants() {
+
     }
+    static final String INCOMPLETE_SCHEMA_INFO = "Schema info is not complete";
+    static final String LEAF_IS_TERMINAL = "Leaf must be the terminal node";
+    static final String NON_KEY_LEAF = "Leaf list is not a key of list";
+    static final String NO_KEY_SET = "Resource Identifier is empty";
 }
diff --git a/apps/config/src/main/java/org/onosproject/config/model/ModelException.java b/apps/config/src/main/java/org/onosproject/config/model/ModelException.java
new file mode 100755
index 0000000..f2f6459
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/ModelException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016-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.config.model;
+
+/**
+ * Exceptions for use by the {@code DynamicConfigService}.
+ */
+public class ModelException extends RuntimeException {
+
+    /**
+     * Constructs a new runtime exception with no error message.
+     */
+    public ModelException() {
+        super();
+    }
+
+    /**
+     * Constructs a new runtime exception with the given error message.
+     *
+     * @param message error message
+     */
+    public ModelException(String message) {
+        super(message);
+    }
+}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/NodeKey.java b/apps/config/src/main/java/org/onosproject/config/model/NodeKey.java
index 9b462a0..18919e3 100755
--- a/apps/config/src/main/java/org/onosproject/config/model/NodeKey.java
+++ b/apps/config/src/main/java/org/onosproject/config/model/NodeKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Laboratory
+ * 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.
@@ -13,15 +13,154 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.onosproject.config.model;
 
-/**
- * Created by sdn on 12/15/16.
- */
-public class NodeKey {
-    SchemaIdentifier schemaId;
+import java.util.Objects;
 
-    public NodeKey(String nm, String nmspc) {
-        this.schemaId = new SchemaIdentifier(nm, nmspc);
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.hash;
+import static org.onosproject.config.model.ModelConstants.INCOMPLETE_SCHEMA_INFO;
+
+/**
+ * Abstraction of an entity which identifies a node uniquely among its
+ * siblings.
+ */
+public class NodeKey<E extends NodeKey> implements Comparable<E>, Cloneable {
+
+    protected SchemaId schemaId;
+
+    /**
+     * Create object from builder.
+     *
+     * @param builder initialized builder
+     */
+    protected NodeKey(NodeKeyBuilder builder) {
+        schemaId = builder.schemaId;
+    }
+
+    /**
+     * Returns node key builder.
+     *
+     * @return node key builder
+     */
+    public static NodeKeyBuilder builder() {
+        return new NodeKeyBuilder();
+    }
+
+    /**
+     * Returns the schema identifier as minimal key required to identify a
+     * branching node.
+     *
+     * @return schema identifier of a key
+     */
+    public SchemaId schemaId() {
+        return schemaId;
+    }
+
+    @Override
+    public int compareTo(NodeKey o) {
+        checkNotNull(o);
+        return schemaId.compareTo(o.schemaId());
+    }
+
+    @Override
+    public int hashCode() {
+        return hash(schemaId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (!getClass().equals(obj.getClass())) {
+            return false;
+        }
+
+        NodeKey that = (NodeKey) obj;
+        return Objects.equals(schemaId, that.schemaId);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("schemaId", schemaId)
+                .toString();
+    }
+
+    /**
+     * Creates and returns a deep copy of this object.
+     *
+     * @return cloned copy
+     * @throws CloneNotSupportedException if the object's class does not
+     *                                    support the {@code Cloneable} interface
+     */
+    public NodeKey clone() throws CloneNotSupportedException {
+        NodeKey clonedKey = (NodeKey) super.clone();
+        clonedKey.schemaId = schemaId.clone();
+        return clonedKey;
+    }
+
+    /**
+     * Builder for node key.
+     *
+     * @param <B> node key type
+     */
+    public static class NodeKeyBuilder<B extends NodeKeyBuilder<B>> {
+        private SchemaId schemaId;
+
+        /**
+         * Create the node key from scratch.
+         */
+        public NodeKeyBuilder() {
+        }
+
+        /**
+         * Support the derived object to inherit from existing node key builder.
+         *
+         * @param base existing node key builder
+         */
+        protected NodeKeyBuilder(NodeKeyBuilder base) {
+            checkNotNull(base.schemaId, INCOMPLETE_SCHEMA_INFO);
+            schemaId = base.schemaId;
+        }
+
+        /**
+         * set the schema identifier.
+         *
+         * @param schema schema identifier
+         * @return current builder
+         */
+        public B schemaId(SchemaId schema) {
+            schemaId = schema;
+            return (B) this;
+        }
+
+        /**
+         * set the schema identifier.
+         *
+         * @param name      name of the node
+         * @param nameSpace name space of the node
+         * @return current builder
+         */
+        public B schemaId(String name, String nameSpace) {
+            schemaId = new SchemaId(name, nameSpace);
+            return (B) this;
+        }
+
+        /**
+         * construct the node key.
+         *
+         * @return node key
+         */
+        public NodeKey build() {
+            checkNotNull(schemaId.name(), INCOMPLETE_SCHEMA_INFO);
+            checkNotNull(schemaId.namespace(), INCOMPLETE_SCHEMA_INFO);
+            return new NodeKey(this);
+        }
     }
 }
+
diff --git a/apps/config/src/main/java/org/onosproject/config/model/ResourceId.java b/apps/config/src/main/java/org/onosproject/config/model/ResourceId.java
new file mode 100755
index 0000000..a279d40
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/ResourceId.java
@@ -0,0 +1,289 @@
+/*
+ * 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.config.model;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.hash;
+import static org.onosproject.config.model.ModelConstants.*;
+
+/**
+ * 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.
+ */
+
+public final class ResourceId {
+
+    //private final Logger log = LoggerFactory.getLogger(getClass());
+    /**
+     * List of node keys.
+     */
+    private List<NodeKey> nodeKeyList;
+
+    /**
+     * Create object from builder.
+     *
+     * @param builder initialized builder
+     */
+    private ResourceId(Builder builder) {
+        nodeKeyList = builder.nodeKeyList;
+    }
+
+    /**
+     * Retrieves a new resource builder.
+     *
+     * @return resource builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Returns the list of node key used to uniquely identify the branch in the
+     * logical tree starting from root.
+     *
+     * @return node key uniquely identifying the branch
+     */
+    public List<NodeKey> nodeKeys() {
+        return nodeKeyList;
+    }
+
+    /**
+     * Returns resource identifier builder for a given resource identifier.
+     * It contains all the attributes from the resource identifier. It is to
+     * provide mutability of resource identifier using builder pattern.
+     *
+     * @return data node builder
+     * @throws CloneNotSupportedException if clone fails
+     */
+    public Builder copyBuilder() throws CloneNotSupportedException {
+        return new Builder(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return hash(nodeKeyList);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        ResourceId that = (ResourceId) obj;
+        List<NodeKey> thatList = that.nodeKeyList;
+        return nodeKeyList.size() == thatList.size() &&
+                nodeKeyList.containsAll(thatList);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("nodeKeyList", nodeKeyList)
+                .toString();
+    }
+
+    /**
+     * Builder to construct resource identifier.
+     */
+    public static class Builder {
+
+        /**
+         * Application related information, this enables application to use
+         * this builder as there work bench.
+         */
+        protected Object appInfo;
+
+        private List<NodeKey> nodeKeyList;
+        private NodeKey.NodeKeyBuilder curKeyBuilder = null;
+
+        /**
+         * Creates an instance of resource identifier builder.
+         */
+        public Builder() {
+            nodeKeyList = new LinkedList<>();
+        }
+
+        /**
+         * Creates an instance of resource identifier builder. This is used
+         * in scenario when builder is required from a given resource
+         * identifier.
+         *
+         * @param id old resource identifier
+         * @throws CloneNotSupportedException if clone fails
+         */
+        public Builder(ResourceId id) throws CloneNotSupportedException {
+            nodeKeyList = new LinkedList<>();
+            for (NodeKey key : id.nodeKeyList) {
+                nodeKeyList.add(key.clone());
+            }
+        }
+
+        /**
+         * Appends a given resource id to current builder.
+         *
+         * @param id resource identifier to be appended
+         * @return builder
+         * @throws CloneNotSupportedException if clone fails
+         */
+        public Builder append(ResourceId id) throws CloneNotSupportedException {
+            processCurKey();
+            curKeyBuilder = null;
+            Builder ob = id.copyBuilder();
+            nodeKeyList.addAll(ob.nodeKeyList);
+            return this;
+        }
+
+        /**
+         * Validates, build and add current key.
+         */
+        private void processCurKey() {
+            if (curKeyBuilder != null) {
+                if (curKeyBuilder instanceof LeafListKey.LeafListKeyBuilder) {
+                    throw new ModelException(LEAF_IS_TERMINAL);
+                }
+                nodeKeyList.add(curKeyBuilder.build());
+            }
+        }
+
+        /**
+         * Adds the descendent node's schema identity.
+         *
+         * @param name      name of descendent node
+         * @param nameSpace name space pf descendent node
+         * @return updated builder pointing to the specified schema location
+         */
+        public Builder addBranchPointSchema(String name, String nameSpace) {
+            processCurKey();
+            curKeyBuilder = new NodeKey.NodeKeyBuilder();
+            curKeyBuilder.schemaId(name, nameSpace);
+            return this;
+        }
+
+        /**
+         * Adds a multi instance attribute's node identity.
+         *
+         * @param name      name of the leaf list
+         * @param nameSpace name space of leaf list
+         * @param val       value of attribute to identify the instance
+         * @return updated builder pointing to the specific attribute
+         * value instance
+         */
+        public Builder addLeafListBranchPoint(String name, String nameSpace,
+                                              Object val) {
+            LeafListKey.LeafListKeyBuilder leafListKeyBuilder;
+            if (curKeyBuilder instanceof LeafListKey.LeafListKeyBuilder) {
+                throw new ModelException(NON_KEY_LEAF);
+            }
+            leafListKeyBuilder = new LeafListKey.LeafListKeyBuilder()
+                    .schemaId(name, nameSpace).value(val);
+
+            curKeyBuilder = leafListKeyBuilder;
+            return this;
+        }
+
+        /**
+         * Adds a multi instance nodes key attribute value to identify
+         * the branch point of instance tree.
+         *
+         * @param name      name of the key attribute
+         * @param nameSpace name space of key attribute
+         * @param val       value of the key leaf, to match in the list entry
+         * @return updated builder with list branching information
+         */
+        public Builder addKeyLeaf(String name, String nameSpace, Object val) {
+            ListKey.ListKeyBuilder listKeyBuilder;
+            if (!(curKeyBuilder instanceof ListKey.ListKeyBuilder)) {
+                if (curKeyBuilder instanceof LeafListKey.LeafListKeyBuilder) {
+                    throw new ModelException(LEAF_IS_TERMINAL);
+                }
+
+                listKeyBuilder = new ListKey.ListKeyBuilder(curKeyBuilder);
+            } else {
+                listKeyBuilder = (ListKey.ListKeyBuilder) curKeyBuilder;
+            }
+
+            listKeyBuilder.addKeyLeaf(name, nameSpace, val);
+            curKeyBuilder = listKeyBuilder;
+            return this;
+        }
+
+        /**
+         * Builds a resource identifier to based on set path information of
+         * the resource.
+         *
+         * @return built resource identifier
+         */
+        public ResourceId build() {
+            checkNotNull(curKeyBuilder, NO_KEY_SET);
+            nodeKeyList.add(curKeyBuilder.build());
+            return new ResourceId(this);
+        }
+
+        /**
+         * Returns application information. This enables application to use
+         * this builder as there work bench.
+         *
+         * @return application information
+         */
+        public Object appInfo() {
+            return appInfo;
+        }
+
+        /**
+         * Sets application information. This enables application to use
+         * this builder as there work bench.
+         *
+         * @param appInfo application related information
+         */
+        public void appInfo(Object appInfo) {
+            appInfo = appInfo;
+        }
+    }
+
+    public String asString() {
+        StringBuilder bldr = new StringBuilder();
+        bldr.append("root.");
+        Iterator<NodeKey> iter = nodeKeyList.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(".");
+            }
+        }
+        return bldr.toString();
+    }
+
+    public String lastNm() {
+        int sz = nodeKeyList.size();
+        return nodeKeyList.get(sz - 1).schemaId().name();
+    }
+
+    public String lastNmspc() {
+        int sz = nodeKeyList.size();
+        return nodeKeyList.get(sz - 1).schemaId().namespace();
+    }
+}
\ No newline at end of file
diff --git a/apps/config/src/main/java/org/onosproject/config/model/ResourceIdentifier.java b/apps/config/src/main/java/org/onosproject/config/model/ResourceIdentifier.java
deleted file mode 100755
index 4862fb2..0000000
--- a/apps/config/src/main/java/org/onosproject/config/model/ResourceIdentifier.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016-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.config.model;
-
-/**
- * Hollow definition of ResourceIdentifier for ConfigService APIs.
- */
-public interface ResourceIdentifier {
-    //will remove this when the corresponding changes in onos-yang-tools become available
-
-    /**
-     * Returns the node key used to uniquely identify the branch in the
-     * logical tree.
-     *
-     * @return node key uniquely identifying the branch
-     */
-    NodeKey nodeKey();
-
-    /**
-     * Returns the descendent resource identifier.
-     *
-     * @return descendent resource identifier
-     */
-    ResourceIdentifier descendentIdentifier();
-
-    String getBase();
-    String asString();
-    //DefaultResourceIdentifier asResId(NodeKey nkey);
-}
diff --git a/apps/config/src/main/java/org/onosproject/config/model/SchemaId.java b/apps/config/src/main/java/org/onosproject/config/model/SchemaId.java
new file mode 100755
index 0000000..c7ea7ef
--- /dev/null
+++ b/apps/config/src/main/java/org/onosproject/config/model/SchemaId.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016-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.config.model;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onosproject.config.model.ModelConstants.INCOMPLETE_SCHEMA_INFO;
+
+/**
+ * Representation of an entity which identifies a schema node in the schema /
+ * data tree.
+ */
+public class SchemaId implements Comparable<SchemaId>, Cloneable {
+
+    private String name;
+    private String nameSpace;
+
+    private SchemaId() {
+    }
+
+    public SchemaId(String name, String nameSpace) {
+        checkNotNull(name, INCOMPLETE_SCHEMA_INFO);
+        checkNotNull(nameSpace, INCOMPLETE_SCHEMA_INFO);
+        this.name = name;
+        this.nameSpace = nameSpace;
+    }
+
+    /**
+     * Returns node schema name. This is mandatory to identify node according
+     * to schema.
+     *
+     * @return node name
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns node's namespace. This is mandatory serializers must translate
+     * any implicit namespace to explicit namespace.
+     *
+     * @return node's namespace
+     */
+    public String namespace() {
+        return nameSpace;
+    }
+
+    /**
+     * Creates and returns a deep copy of this object.
+     *
+     * @return cloned copy
+     * @throws CloneNotSupportedException if the object's class does not
+     *                                    support the {@code Cloneable} interface
+     */
+    public SchemaId clone() throws CloneNotSupportedException {
+        return (SchemaId) super.clone();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, nameSpace);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        SchemaId that = (SchemaId) obj;
+        return Objects.equals(name, that.name) &&
+                Objects.equals(nameSpace, that.nameSpace);
+    }
+
+    @Override
+    public int compareTo(SchemaId o) {
+        checkNotNull(o);
+        if (name.equals(o.name)) {
+            if (nameSpace.equals(o.nameSpace)) {
+                return 0;
+            }
+        }
+        return -1;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(getClass())
+                .add("name", name)
+                .add("nameSpace", nameSpace)
+                .toString();
+    }
+}
\ No newline at end of file