Bug 2766: Fixed parsing and serializing XPath Instance Identifiers 00/15900/8
authorTony Tkacik <ttkacik@cisco.com>
Mon, 2 Mar 2015 13:39:49 +0000 (14:39 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Sun, 8 Mar 2015 12:19:40 +0000 (13:19 +0100)
Original implementation of Instance Identifier codec used
Splitters which did not have enough information to determine
that '/' is used in string literals.

Fortunatelly Instance Identifier is only very constrained
subset of XPath, so it was still possible to reimplement
correct token-based parser using Guava.

Other problem fixed with  parsing instance identifiers was
that YangInstanceIdentifier also contained components,
which are not present in XML / JSON serialization.

Change-Id: I4186f59f8e16c92eb2e0ca2bc0a6c12e7215a3be
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
39 files changed:
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java
yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json
yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-node-in-container.json
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/AugmentationSchemaProxy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/BaseDispatcherParser.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/serializer/BaseDispatcherSerializer.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/DataNodeContainerModificationStrategy.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtilsTest.java
yang/yang-data-util/pom.xml
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractInteriorContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractLeafNodeContext.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AugmentationContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataContainerContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListItemContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedLeafListMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedMapMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListItemContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedLeafListMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedMapMixinContextNode.java [new file with mode: 0644]
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java [new file with mode: 0644]

index 77fa797efa4f3036d89c93f3063c25433003865a..528162a359e2151e2b971ec573cbe85abb2f63b0 100644 (file)
@@ -13,14 +13,17 @@ import java.io.IOException;
 import java.net.URI;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.util.AbstractModuleStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 final class JSONStringInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec implements JSONCodec<YangInstanceIdentifier> {
     private final SchemaContext context;
+    private final DataSchemaContextTree dataContextTree;
 
     JSONStringInstanceIdentifierCodec(final SchemaContext context) {
         this.context = Preconditions.checkNotNull(context);
+        this.dataContextTree = DataSchemaContextTree.from(context);
     }
 
     @Override
@@ -34,6 +37,11 @@ final class JSONStringInstanceIdentifierCodec extends AbstractModuleStringInstan
         return module == null ? null : module.getName();
     }
 
+    @Override
+    protected DataSchemaContextTree getDataContextTree() {
+        return dataContextTree;
+    }
+
     @Override
     public boolean needQuotes() {
         return true;
index 484aa70029c1182660de8863616c12cbc205b295..90fd51b80302a420df40ef01a93ef81cec99a4f0 100644 (file)
@@ -7,11 +7,26 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.childArray;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.childPrimitive;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadModules;
+import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.resolveCont1;
+
 import com.google.common.collect.Sets;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonPrimitive;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Iterator;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -20,22 +35,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStre
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.net.URISyntaxException;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.childArray;
-import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.childPrimitive;
-import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.loadModules;
-import static org.opendaylight.yangtools.yang.data.codec.gson.TestUtils.resolveCont1;
-
 /**
  * Each test tests whether json output obtained after transformation contains is corect. The transformation takes
  * normalized node data structure and transform it to json output. To make it easier validate json output it is loaded
@@ -201,7 +200,7 @@ public class NormalizedNodeToJsonStreamTest {
                 assertNotNull(lf111);
 
                 assertEquals("key111 value", key111.getAsString());
-                assertEquals("/complexjson:cont1/complexjson:lflst11", lf112.getAsString());
+                assertEquals("/complexjson:cont1/complexjson:lflst11[.='foo']", lf112.getAsString());
                 assertEquals("lf113 value", lf113.getAsString());
                 assertEquals("lf111 value", lf111.getAsString());
             }
index 71a2b99e7f9f914cac06c50fcfdb8480d2981c8c..140c7ff008076384217f315a7956bfcc927f78e4 100644 (file)
@@ -9,12 +9,13 @@ package org.opendaylight.yangtools.yang.data.codec.gson;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import java.util.HashMap;
+import java.util.Map;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
@@ -38,9 +39,6 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContaine
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
 
-import java.util.HashMap;
-import java.util.Map;
-
 public class TestingNormalizedNodeStructuresCreator {
 
     static NormalizedNode<?, ?> cont1Node(
@@ -215,10 +213,11 @@ public class TestingNormalizedNodeStructuresCreator {
     }
 
     private static Object lf112Value() {
-        InstanceIdentifierBuilder builder = YangInstanceIdentifier.builder();
-        builder.node(QName.create("ns:complex:json", "2014-08-11", "cont1"));
-        builder.node(QName.create("ns:complex:json", "2014-08-11", "lflst11"));
-        return builder.build();
+        return YangInstanceIdentifier.create(
+                new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "cont1")),
+                new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lflst11")),
+                new NodeWithValue(QName.create("ns:complex:json", "2014-08-11", "lflst11"),"foo")
+        );
     }
 
     private static DataContainerChild<? extends PathArgument, ?> childLflst11() {
@@ -270,7 +269,7 @@ public class TestingNormalizedNodeStructuresCreator {
     public static NormalizedNode<?, ?> leafNodeInContainer() {
         LeafNode<Object> lf11 = Builders.leafBuilder()
                 .withNodeIdentifier(new NodeIdentifier(QName.create("ns:complex:json", "2014-08-11", "lf11")))
-                .withValue((int) 453).build();
+                .withValue(453).build();
         return cont1Node(lf11);
     }
 
index fd4538833bd40457a225437a51e3a0e3692bafa6..07490bdb633bd712fe96f3c4c039cdc30c98d069 100644 (file)
@@ -17,7 +17,7 @@
         "lst11":[
             {
                 "key111":"key111 value",
-                "lf112":"/complexjson:cont1/complexjson:lflst11",
+                "lf112":"/complexjson:cont1/complexjson:lflst11[.='foo']",
                 "lf113":"lf113 value",
                 "lf111":"lf111 value"
             }
index 7cb51939ab4e479896b9e1f5a995e84473e8943b..dbcc8a91e830e292df7c67d32adecb38b2f8ddd8 100644 (file)
@@ -3,7 +3,7 @@
         "lst11":[
             {
                 "key111":"key111 value",
-                "lf112":"/complexjson:cont1/complexjson:lflst11",
+                "lf112":"/complexjson:cont1/complexjson:lflst11[.='foo']",
                 "lf113":"lf113 value",
                 "lf111":"lf111 value"
             }
index 79df0ea2006e4528adc52403a66644748ecbaeb7..09aa9c8a2b9abec1a36bfb7059d44f07adc29787 100644 (file)
@@ -22,7 +22,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
@@ -40,6 +39,7 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -227,7 +227,7 @@ public final class SchemaTracker {
         for(final DataSchemaNode child : schema.getChildNodes()) {
             realChildSchemas.add(((DataNodeContainer) parent).getDataChildByName(child.getQName()));
         }
-        final AugmentationSchema resolvedSchema = new AugmentationSchemaProxy(schema, realChildSchemas);
+        final AugmentationSchema resolvedSchema = new EffectiveAugmentationSchema(schema, realChildSchemas);
         schemaStack.push(resolvedSchema);
         return resolvedSchema;
     }
index 11944faad8d136a4a2b0d2eed484abd9aa88195c..150189ae1183f7e9bae2ccbc391860c1808f784e 100644 (file)
@@ -8,11 +8,10 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import com.google.common.base.Preconditions;
-
 import java.net.URI;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.util.AbstractStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.w3c.dom.Element;
@@ -20,10 +19,12 @@ import org.w3c.dom.Element;
 final class ElementInstanceIdentifierParser extends AbstractStringInstanceIdentifierCodec {
     private final SchemaContext schema;
     private final Element element;
+    private final DataSchemaContextTree dataContextTree;
 
     ElementInstanceIdentifierParser(final SchemaContext schema, final Element element) {
         this.element = Preconditions.checkNotNull(element);
         this.schema = Preconditions.checkNotNull(schema);
+        this.dataContextTree = DataSchemaContextTree.from(schema);
     }
 
     @Override
@@ -42,4 +43,9 @@ final class ElementInstanceIdentifierParser extends AbstractStringInstanceIdenti
         return QName.create(module.getQNameModule(), localName);
     }
 
+    @Override
+    protected DataSchemaContextTree getDataContextTree() {
+        return dataContextTree;
+    }
+
 }
index 563641fd68161f87e7e2cdc401469880ee107100..ce304c82eb74dc878f50ecd45a200df25fd216d2 100644 (file)
@@ -24,8 +24,8 @@ public final class InstanceIdentifierForXmlCodec {
         return codec.deserialize(element.getTextContent().trim());
     }
 
-    public static Element serialize(final YangInstanceIdentifier id, final Element element) {
-        final RandomPrefixInstanceIdentifierSerializer codec = new RandomPrefixInstanceIdentifierSerializer();
+    public static Element serialize(final YangInstanceIdentifier id, final Element element, SchemaContext context) {
+        final RandomPrefixInstanceIdentifierSerializer codec = new RandomPrefixInstanceIdentifierSerializer(context);
         final String str = codec.serialize(id);
 
         for (Entry<URI, String> e : codec.getPrefixes()) {
@@ -35,6 +35,15 @@ public final class InstanceIdentifierForXmlCodec {
         return element;
     }
 
+    /**
+     *
+     * @deprecated USe {@link #serialize(YangInstanceIdentifier, Element, SchemaContext)} instead.
+     */
+    @Deprecated
+    public static Element serialize(final YangInstanceIdentifier id, final Element element) {
+        throw new UnsupportedOperationException("Not supported, due to buggy API contract.");
+    }
+
     private static String getIdAndPrefixAsStr(final String pathPart) {
         int predicateStartIndex = pathPart.indexOf('[');
         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
index a6fa1c0c5117604ea9ddf568d7879e48c0cd426c..9c2c613ebfb806a9915fec988c3ad17a8403acd3 100644 (file)
@@ -9,12 +9,19 @@ package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import java.net.URI;
 import java.util.Map;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.util.AbstractStringInstanceIdentifierCodec;
+import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 final class RandomPrefixInstanceIdentifierSerializer extends AbstractStringInstanceIdentifierCodec {
     private final RandomPrefix prefixes = new RandomPrefix();
+    private final DataSchemaContextTree schemaTree;
+
+
+    RandomPrefixInstanceIdentifierSerializer(SchemaContext ctx) {
+        schemaTree = DataSchemaContextTree.from(ctx);
+    }
 
     Iterable<Map.Entry<URI, String>> getPrefixes() {
         return prefixes.getPrefixes();
@@ -30,4 +37,9 @@ final class RandomPrefixInstanceIdentifierSerializer extends AbstractStringInsta
         throw new UnsupportedOperationException("Not implemented");
     }
 
+    @Override
+    protected DataSchemaContextTree getDataContextTree() {
+        return schemaTree;
+    }
+
 }
index f9f6a70ac2c7f88945d5aa63fbcd103b4a14b1eb..541253d09f0434de6cb77e2c799382640173ed56 100644 (file)
@@ -95,20 +95,17 @@ public class XmlStreamUtils {
      * @param writer XML Stream writer
      * @param id InstanceIdentifier
      * @throws XMLStreamException
+     *
+     * @deprecated Use {@link #writeInstanceIdentifier(XMLStreamWriter, YangInstanceIdentifier)} instead.
      */
+    @Deprecated
     public static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull YangInstanceIdentifier id) throws XMLStreamException {
         Preconditions.checkNotNull(writer, "Writer may not be null");
         Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
 
         final RandomPrefix prefixes = new RandomPrefix();
         final String str = XmlUtils.encodeIdentifier(prefixes, id);
-
-        for (Entry<URI, String> e: prefixes.getPrefixes()) {
-            final String ns = e.getKey().toString();
-            final String p = e.getValue();
-
-            writer.writeNamespace(p, ns);
-        }
+        writeNamespaceDeclarations(writer,prefixes.getPrefixes());
         writer.writeCharacters(str);
     }
 
@@ -351,15 +348,35 @@ public class XmlStreamUtils {
         }
     }
 
-    private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException {
+    private void write(final @Nonnull XMLStreamWriter writer, final @Nonnull InstanceIdentifierTypeDefinition type, final @Nonnull Object value) throws XMLStreamException {
         if (value instanceof YangInstanceIdentifier) {
-            write(writer, (YangInstanceIdentifier)value);
+            writeInstanceIdentifier(writer, (YangInstanceIdentifier)value);
         } else {
             LOG.warn("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass());
             writer.writeCharacters(String.valueOf(value));
         }
     }
 
+    public void writeInstanceIdentifier(XMLStreamWriter writer, YangInstanceIdentifier value) throws XMLStreamException {
+        if(schemaContext.isPresent()) {
+            RandomPrefixInstanceIdentifierSerializer iiCodec = new RandomPrefixInstanceIdentifierSerializer(schemaContext.get());
+            String serializedValue = iiCodec.serialize(value);
+            writeNamespaceDeclarations(writer,iiCodec.getPrefixes());
+            writer.writeCharacters(serializedValue);
+        } else {
+            LOG.warn("Schema context not present in {}, serializing {} without schema.",this,value);
+            write(writer,value);
+        }
+    }
+
+    private static void writeNamespaceDeclarations(XMLStreamWriter writer, Iterable<Entry<URI, String>> prefixes) throws XMLStreamException {
+        for (Entry<URI, String> e: prefixes) {
+            final String ns = e.getKey().toString();
+            final String p = e.getValue();
+            writer.writeNamespace(p, ns);
+        }
+    }
+
     public static XmlStreamUtils create(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) {
         return new XmlStreamUtils(codecProvider, schemaContext);
     }
index e6cfd58e7ddb7b4b43105190646fbcf62c2dd321..cfb8fc0897cd5b2f620f940bd8358b1ed94a2524 100644 (file)
@@ -8,9 +8,7 @@
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import java.util.Map;
-
 import javax.annotation.Nonnull;
-
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -42,6 +40,11 @@ public final class XmlUtils {
         return superType;
     }
 
+    /**
+     *
+     * @deprecated Use {@link RandomPrefixInstanceIdentifierSerializer} instead.
+     */
+    @Deprecated
     static String encodeIdentifier(final RandomPrefix prefixes, final YangInstanceIdentifier id) {
         StringBuilder textContent = new StringBuilder();
         for (PathArgument pathArgument : id.getPathArguments()) {
index 7fec679d1d7033fe63a6e7fc701b1f9a44b0e400..4a75a3faa3a2191e9bb9390e4e8f1ccbde9bb776 100644 (file)
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.transform.base;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableMap;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
-
-import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 
 /**
  * Proxy for AugmentationSchema. Child node schemas are replaced with actual schemas from parent.
+ *
+ * @deprecated Replaced with {@link EffectiveAugmentationSchema}.
  */
-public final class AugmentationSchemaProxy implements AugmentationSchema {
-    private final AugmentationSchema delegate;
-    private final Set<DataSchemaNode> realChildSchemas;
-    private final Map<QName, DataSchemaNode> mappedChildSchemas;
-
-    public AugmentationSchemaProxy(final AugmentationSchema augmentSchema, final Set<DataSchemaNode> realChildSchemas) {
-        this.delegate = augmentSchema;
-        this.realChildSchemas = realChildSchemas;
-
-        final Map<QName, DataSchemaNode> m = new HashMap<>(realChildSchemas.size());
-        for (DataSchemaNode realChildSchema : realChildSchemas) {
-            m.put(realChildSchema.getQName(), realChildSchema);
-        }
-
-        this.mappedChildSchemas = ImmutableMap.copyOf(m);
-    }
+@Deprecated
+public final class AugmentationSchemaProxy extends EffectiveAugmentationSchema {
 
-    @Override
-    public RevisionAwareXPath getWhenCondition() {
-        return delegate.getWhenCondition();
-    }
-
-    @Override
-    public String getDescription() {
-        return delegate.getDescription();
-    }
-
-    @Override
-    public String getReference() {
-        return delegate.getReference();
-    }
-
-    @Override
-    public Status getStatus() {
-        return delegate.getStatus();
-    }
 
-    @Override
-    public SchemaPath getTargetPath() {
-        return delegate.getTargetPath();
-    }
-
-    @Override
-    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
-        return delegate.getUnknownSchemaNodes();
-    }
-
-    @Override
-    public Set<TypeDefinition<?>> getTypeDefinitions() {
-        return delegate.getTypeDefinitions();
-    }
-
-    @Override
-    public Set<DataSchemaNode> getChildNodes() {
-        return realChildSchemas;
-    }
-
-    @Override
-    public Set<GroupingDefinition> getGroupings() {
-        return delegate.getGroupings();
-    }
-
-    @Override
-    public DataSchemaNode getDataChildByName(final QName name) {
-        return mappedChildSchemas.get(name);
-    }
-
-    @Override
-    public DataSchemaNode getDataChildByName(final String name) {
-        // Unused
-        throw new UnsupportedOperationException("Unable to retrieve child node by name");
-    }
-
-    @Override
-    public Set<UsesNode> getUses() {
-        return delegate.getUses();
+    public AugmentationSchemaProxy(final AugmentationSchema augmentSchema, final Set<DataSchemaNode> realChildSchemas) {
+       super(augmentSchema,realChildSchemas);
     }
 
-    @Override
-    public Optional<AugmentationSchema> getOriginalDefinition() {
-        return delegate.getOriginalDefinition();
-    }
 }
index ed458c6c65c07ab4281098b6ecbde32a50e01f9c..833767bdc75d9d4c8de396f9f9d7fec0784dcf22 100644 (file)
@@ -21,10 +21,10 @@ import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 
 /**
  * Abstract(base) Parser for DataContainerNodes e.g. ContainerNode, AugmentationNode.
@@ -135,7 +135,7 @@ public abstract class BaseDispatcherParser<E, N extends DataContainerNode<?>, S>
 
         for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
             Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
-            AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas);
+            EffectiveAugmentationSchema augSchemaProxy = new EffectiveAugmentationSchema(augmentSchema, realChildSchemas);
             containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
         }
 
index d356508da477a498f0753f11a11b560f0e4cd626..a58ecc5a616c369a8cfbf4271b4d128da8124a3a 100644 (file)
@@ -7,21 +7,19 @@
  */
 package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.serializer;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import java.util.List;
 import java.util.Set;
-
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.transform.FromNormalizedNodeSerializer;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 
 /**
  * Abstract(base) Serializer for DataContainerNodes e.g. ContainerNode, AugmentationNode.
@@ -78,7 +76,7 @@ public abstract class BaseDispatcherSerializer<E, N extends DataContainerNode<?>
 
                 AugmentationSchema augSchema = getAugmentedCase(schema, (AugmentationNode) choiceChild);
                 Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augSchema);
-                childSchema = new AugmentationSchemaProxy(augSchema, realChildSchemas);
+                childSchema = new EffectiveAugmentationSchema(augSchema, realChildSchemas);
 
             } else {
                 childSchema = getSchemaForChild(schema, choiceChild);
index bfa3f28e6e95ec7ff34184778d74924adf09110d..e239c38bf03d2d8de528779a8cf42577fdee3214 100644 (file)
@@ -9,10 +9,14 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
-
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
@@ -25,19 +29,13 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableAu
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableUnkeyedListEntryNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 
 /**
  * Base strategy for applying changes to a ContainerNode, irrespective of its
@@ -106,13 +104,12 @@ abstract class DataNodeContainerModificationStrategy<T extends DataNodeContainer
             return ImmutableAugmentationNodeBuilder.create((AugmentationNode) original);
         }
 
-
         private static AugmentationSchema createAugmentProxy(final AugmentationSchema schema, final DataNodeContainer resolved) {
             Set<DataSchemaNode> realChildSchemas = new HashSet<>();
             for(DataSchemaNode augChild : schema.getChildNodes()) {
                 realChildSchemas.add(resolved.getDataChildByName(augChild.getQName()));
             }
-            return new AugmentationSchemaProxy(schema, realChildSchemas);
+            return new EffectiveAugmentationSchema(schema, realChildSchemas);
         }
     }
 
index e93a5704d5d1914810a612d53505f044819af632..308fac960152d095ee06d08cd7294c90c185fd60 100644 (file)
@@ -54,7 +54,9 @@ public class XmlDocumentUtilsTest {
 
     public static final String XML_CONTENT = "<input xmlns=\"urn:opendaylight:controller:rpc:test\">\n" +
             "<a>value</a>\n" +
-            "<ref xmlns:ltha=\"urn:opendaylight:controller:rpc:test\">/ltha:cont/ltha:l[ltha:id='id']</ref>\n" +
+            "<ref xmlns:ltha=\"urn:opendaylight:controller:rpc:test\">"+
+            "/ltha:cont/ltha:l[  ltha:id='id/foo/bar'  ]"+
+            "</ref>\n" +
             "</input>";
 
     public static final String RPC_REPLY = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\"m-1\">\n" +
index b86f4400197981a3537efec94f8b1f8ed43f9ca6..85d904a2698534df081c0e47ec91e626edb5d78a 100644 (file)
             <groupId>${project.groupId}</groupId>
             <artifactId>yang-data-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-util</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractInteriorContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractInteriorContextNode.java
new file mode 100644 (file)
index 0000000..0ec3baf
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+abstract class AbstractInteriorContextNode<T extends PathArgument> extends
+        DataSchemaContextNode<T> {
+
+    protected AbstractInteriorContextNode(final T identifier, final DataSchemaNode schema) {
+        super(identifier, schema);
+    }
+
+    @Override
+    public boolean isLeaf() {
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractLeafNodeContext.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractLeafNodeContext.java
new file mode 100644 (file)
index 0000000..84e8a97
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+abstract class AbstractLeafNodeContext<T extends PathArgument> extends DataSchemaContextNode<T> {
+
+    protected AbstractLeafNodeContext(final T identifier, final DataSchemaNode potential) {
+        super(identifier, potential);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        return null;
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        return null;
+    }
+
+    @Override
+    public boolean isLeaf() {
+        return true;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractMixinContextNode.java
new file mode 100644 (file)
index 0000000..3806612
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+abstract class AbstractMixinContextNode<T extends PathArgument> extends
+        AbstractInteriorContextNode<T> {
+
+    protected AbstractMixinContextNode(final T identifier, final DataSchemaNode schema) {
+        super(identifier, schema);
+    }
+
+    @Override
+    public final boolean isMixin() {
+        return true;
+    }
+
+}
\ No newline at end of file
index 3e47e966cf94a1f1f6b0e6b485fb922678f02ce0..ef6ac8eb31860a72325d98d7436f82ba291f8e24 100644 (file)
@@ -9,17 +9,10 @@ package org.opendaylight.yangtools.yang.data.util;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
@@ -31,20 +24,21 @@ import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
  */
 @Beta
 public abstract class AbstractStringInstanceIdentifierCodec extends AbstractNamespaceCodec implements InstanceIdentifierCodec<String> {
-    private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
 
     @Override
     public final String serialize(final YangInstanceIdentifier data) {
         StringBuilder sb = new StringBuilder();
+        DataSchemaContextNode<?> current = getDataContextTree().getRoot();
         for (PathArgument arg : data.getPathArguments()) {
-            if(arg instanceof AugmentationIdentifier) {
+            current = current.getChild(arg);
+
+            if(current.isMixin()) {
                 /*
                  * XML/YANG instance identifier does not have concept
-                 * of augmentation identifier, which identifies
-                 * mixin (same as paretn element), so we can safely
-                 * ignore it if it is part of path (since child node)
-                 * is identified in same fashion.
+                 * of augmentation identifier, or list as whole which
+                 * identifies mixin (same as paretn element),
+                 * so we can safely ignore it if it is part of path
+                 * (since child node) is identified in same fashion.
                  *
                  */
                 continue;
@@ -67,90 +61,33 @@ public abstract class AbstractStringInstanceIdentifierCodec extends AbstractName
                 sb.append("']");
             }
         }
-
         return sb.toString();
     }
 
+    /**
+     *
+     * Returns DataSchemaContextTree associated with SchemaContext for which
+     * serialization / deserialization occurs.
+     *
+     * Implementations MUST provide non-null Data Tree context, in order
+     * for correct serialization / deserialization of PathArguments,
+     * since XML representation does not have Augmentation arguments
+     * and does not provide path arguments for cases.
+     *
+     * This effectively means same input XPath representation of Path Argument
+     * may result in different YangInstanceIdentifiers if models are different
+     * in uses of choices and cases.
+     *
+     * @return DataSchemaContextTree associated with SchemaContext for which
+     * serialization / deserialization occurs.
+     */
+    protected abstract @Nonnull DataSchemaContextTree getDataContextTree();
+
     @Override
     public final YangInstanceIdentifier deserialize(final String data) {
         Preconditions.checkNotNull(data, "Data may not be null");
-
-        final Iterator<String> xPathParts = SLASH_SPLITTER.split(data).iterator();
-
-        // must be at least "/pr:node"
-        if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) {
-            return null;
-        }
-
-        List<PathArgument> result = new ArrayList<>();
-        while (xPathParts.hasNext()) {
-            String xPathPartTrimmed = xPathParts.next().trim();
-
-            PathArgument pathArgument = toPathArgument(xPathPartTrimmed);
-            if (pathArgument != null) {
-                result.add(pathArgument);
-            }
-        }
-        return YangInstanceIdentifier.create(result);
+        XpathStringParsingPathArgumentBuilder builder = new XpathStringParsingPathArgumentBuilder(this, data);
+        return YangInstanceIdentifier.create(builder.build());
     }
 
-    private PathArgument toPathArgument(final String xPathArgument) {
-        final QName mainQName = parseQName(xPathArgument);
-
-        // predicates
-        final Matcher matcher = PREDICATE_PATTERN.matcher(xPathArgument);
-        final Map<QName, Object> predicates = new LinkedHashMap<>();
-        QName currentQName = mainQName;
-
-        while (matcher.find()) {
-            final String predicateStr = matcher.group(1).trim();
-            final int indexOfEqualityMark = predicateStr.indexOf('=');
-            if (indexOfEqualityMark != -1) {
-                final String predicateValue = toPredicateValue(predicateStr.substring(indexOfEqualityMark + 1));
-                if (predicateValue == null) {
-                    return null;
-                }
-
-                if (predicateStr.charAt(0) != '.') {
-                    // target is not a leaf-list
-                    currentQName = parseQName(predicateStr.substring(0, indexOfEqualityMark));
-                    if (currentQName == null) {
-                        return null;
-                    }
-                }
-                predicates.put(currentQName, predicateValue);
-            }
-        }
-
-        if (predicates.isEmpty()) {
-            return new YangInstanceIdentifier.NodeIdentifier(mainQName);
-        } else {
-            return new YangInstanceIdentifier.NodeIdentifierWithPredicates(mainQName, predicates);
-        }
-    }
-
-    private static String toPredicateValue(final String predicatedValue) {
-        final String predicatedValueTrimmed = predicatedValue.trim();
-        if (predicatedValue.isEmpty()) {
-            return null;
-        }
-
-        switch (predicatedValueTrimmed.charAt(0)) {
-        case '"':
-            return trimIfEndIs(predicatedValueTrimmed, '"');
-        case '\'':
-            return trimIfEndIs(predicatedValueTrimmed, '\'');
-        default:
-            return null;
-        }
-    }
-
-    private static String trimIfEndIs(final String str, final char end) {
-        final int l = str.length() - 1;
-        if (str.charAt(l) != end) {
-            return null;
-        }
-
-        return str.substring(1, l);
-    }
 }
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlContextNode.java
new file mode 100644 (file)
index 0000000..fa6f64c
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+
+class AnyXmlContextNode extends DataSchemaContextNode<NodeIdentifier> {
+
+    protected AnyXmlContextNode(final AnyXmlSchemaNode schema) {
+        super(new NodeIdentifier(schema.getQName()), schema);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        return null;
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        return null;
+    }
+
+    @Override
+    public boolean isLeaf() {
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AugmentationContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AugmentationContextNode.java
new file mode 100644 (file)
index 0000000..a2393ca
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+final class AugmentationContextNode extends
+        DataContainerContextNode<AugmentationIdentifier> {
+
+    public AugmentationContextNode(final AugmentationSchema augmentation, final DataNodeContainer schema) {
+        // super();
+        super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema), null);
+    }
+
+    @Override
+    public boolean isMixin() {
+        return true;
+    }
+
+    @Override
+    protected DataSchemaContextNode<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
+        DataSchemaNode result = findChildSchemaNode(schema, child);
+        // We try to look up if this node was added by augmentation
+        if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
+            return fromAugmentation(schema, (AugmentationTarget) schema, result);
+        }
+        return fromDataSchemaNode(result);
+    }
+
+    @Override
+    protected Set<QName> getQNameIdentifiers() {
+        return getIdentifier().getPossibleChildNames();
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeContextNode.java
new file mode 100644 (file)
index 0000000..216e3f5
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import com.google.common.collect.ImmutableMap;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class ChoiceNodeContextNode extends AbstractMixinContextNode<NodeIdentifier> {
+
+    private final ImmutableMap<QName, DataSchemaContextNode<?>> byQName;
+    private final ImmutableMap<PathArgument, DataSchemaContextNode<?>> byArg;
+
+    protected ChoiceNodeContextNode(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
+        super(new NodeIdentifier(schema.getQName()), schema);
+        ImmutableMap.Builder<QName, DataSchemaContextNode<?>> byQNameBuilder = ImmutableMap.builder();
+        ImmutableMap.Builder<PathArgument, DataSchemaContextNode<?>> byArgBuilder = ImmutableMap.builder();
+
+        for (ChoiceCaseNode caze : schema.getCases()) {
+            for (DataSchemaNode cazeChild : caze.getChildNodes()) {
+                DataSchemaContextNode<?> childOp = fromDataSchemaNode(cazeChild);
+                byArgBuilder.put(childOp.getIdentifier(), childOp);
+                for (QName qname : childOp.getQNameIdentifiers()) {
+                    byQNameBuilder.put(qname, childOp);
+                }
+            }
+        }
+        byQName = byQNameBuilder.build();
+        byArg = byArgBuilder.build();
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        return byArg.get(child);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        return byQName.get(child);
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerContextNode.java
new file mode 100644 (file)
index 0000000..10e49b6
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+
+final class ContainerContextNode extends DataContainerContextNode<NodeIdentifier> {
+
+    protected ContainerContextNode(final ContainerSchemaNode schema) {
+        super(new NodeIdentifier(schema.getQName()), schema, schema);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataContainerContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataContainerContextNode.java
new file mode 100644 (file)
index 0000000..2cbbf1f
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+class DataContainerContextNode<T extends PathArgument> extends
+        AbstractInteriorContextNode<T> {
+
+    private final DataNodeContainer schema;
+    private final Map<QName, DataSchemaContextNode<?>> byQName;
+    private final Map<PathArgument, DataSchemaContextNode<?>> byArg;
+
+    protected DataContainerContextNode(final T identifier, final DataNodeContainer schema,
+            final DataSchemaNode node) {
+        super(identifier, node);
+        this.schema = schema;
+        this.byArg = new ConcurrentHashMap<>();
+        this.byQName = new ConcurrentHashMap<>();
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        DataSchemaContextNode<?> potential = byArg.get(child);
+        if (potential != null) {
+            return potential;
+        }
+        potential = fromLocalSchema(child);
+        return register(potential);
+    }
+
+    private DataSchemaContextNode<?> fromLocalSchema(final PathArgument child) {
+        if (child instanceof AugmentationIdentifier) {
+            return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
+                    .iterator().next());
+        }
+        return fromSchemaAndQNameChecked(schema, child.getNodeType());
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        DataSchemaContextNode<?> potential = byQName.get(child);
+        if (potential != null) {
+            return potential;
+        }
+        potential = fromLocalSchemaAndQName(schema, child);
+        return register(potential);
+    }
+
+    protected DataSchemaContextNode<?> fromLocalSchemaAndQName(final DataNodeContainer schema2, final QName child) {
+        return fromSchemaAndQNameChecked(schema2, child);
+    }
+
+    private DataSchemaContextNode<?> register(final DataSchemaContextNode<?> potential) {
+        if (potential != null) {
+            byArg.put(potential.getIdentifier(), potential);
+            for (QName qName : potential.getQNameIdentifiers()) {
+                byQName.put(qName, potential);
+            }
+        }
+        return potential;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java
new file mode 100644 (file)
index 0000000..050255e
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
+
+/**
+ * Schema derived data providing necessary information for mapping
+ * between {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode}
+ * and serialization format defined in RFC6020, since the mapping
+ * is not one-to-one.
+ *
+ * @param <T> Path Argument type
+ *
+ */
+public abstract class DataSchemaContextNode<T extends PathArgument> implements Identifiable<T> {
+
+    private final T identifier;
+    private final DataSchemaNode dataSchemaNode;
+
+    @Override
+    public T getIdentifier() {
+        return identifier;
+    };
+
+    protected DataSchemaContextNode(final T identifier, final SchemaNode schema) {
+        super();
+        this.identifier = identifier;
+        if (schema instanceof DataSchemaNode) {
+            this.dataSchemaNode = (DataSchemaNode) schema;
+        } else {
+            this.dataSchemaNode = null;
+        }
+    }
+
+    public boolean isMixin() {
+        return false;
+    }
+
+    public boolean isKeyedEntry() {
+        return false;
+    }
+
+    protected Set<QName> getQNameIdentifiers() {
+        return Collections.singleton(identifier.getNodeType());
+    }
+
+    public abstract @Nullable DataSchemaContextNode<?> getChild(final PathArgument child);
+
+    public abstract @Nullable DataSchemaContextNode<?> getChild(QName child);
+
+    public abstract boolean isLeaf();
+
+
+    public @Nullable DataSchemaNode getDataSchemaNode() {
+        return dataSchemaNode;
+    }
+
+    static final DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
+        DataSchemaNode potential = parent.getDataChildByName(child);
+        if (potential == null) {
+            Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
+                    parent.getChildNodes()).filter(ChoiceNode.class);
+            potential = findChoice(choices, child);
+        }
+        return potential;
+    }
+
+    static DataSchemaContextNode<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
+        DataSchemaNode result = findChildSchemaNode(schema, child);
+        // We try to look up if this node was added by augmentation
+        if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
+            return fromAugmentation(schema, (AugmentationTarget) schema, result);
+        }
+        return fromDataSchemaNode(result);
+    }
+
+    private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
+            final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices, final QName child) {
+        org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
+        choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
+            for (ChoiceCaseNode caze : choice.getCases()) {
+                if (findChildSchemaNode(caze, child) != null) {
+                    foundChoice = choice;
+                    break choiceLoop;
+                }
+            }
+        }
+        return foundChoice;
+    }
+
+    public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
+        ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
+        for (DataSchemaNode child : augmentation.getChildNodes()) {
+            potentialChildren.add(child.getQName());
+        }
+        return new AugmentationIdentifier(potentialChildren.build());
+    }
+
+    static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation,
+            final DataNodeContainer schema) {
+        Set<DataSchemaNode> children = new HashSet<>();
+        for (DataSchemaNode augNode : augmentation.getChildNodes()) {
+            children.add(schema.getDataChildByName(augNode.getQName()));
+        }
+        return new EffectiveAugmentationSchema(augmentation, children);
+    }
+
+    /**
+     * Returns a DataContextNodeOperation for provided child node
+     *
+     * If supplied child is added by Augmentation this operation returns a
+     * DataContextNodeOperation for augmentation, otherwise returns a
+     * DataContextNodeOperation for child as call for
+     * {@link #fromDataSchemaNode(DataSchemaNode)}.
+     *
+     *
+     * @param parent
+     * @param parentAug
+     * @param child
+     * @return
+     */
+    static @Nullable DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent,
+            final AugmentationTarget parentAug, final DataSchemaNode child) {
+        AugmentationSchema augmentation = null;
+        for (AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
+            DataSchemaNode potential = aug.getDataChildByName(child.getQName());
+            if (potential != null) {
+                augmentation = aug;
+                break;
+            }
+        }
+        if (augmentation != null) {
+            return new AugmentationContextNode(augmentation, parent);
+        }
+        return fromDataSchemaNode(child);
+    }
+
+    public static @Nullable DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) {
+        if (potential instanceof ContainerSchemaNode) {
+            return new ContainerContextNode((ContainerSchemaNode) potential);
+        } else if (potential instanceof ListSchemaNode) {
+            return fromListSchemaNode((ListSchemaNode) potential);
+        } else if (potential instanceof LeafSchemaNode) {
+            return new LeafContextNode((LeafSchemaNode) potential);
+        } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
+            return new ChoiceNodeContextNode((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
+        } else if (potential instanceof LeafListSchemaNode) {
+            return fromLeafListSchemaNode((LeafListSchemaNode) potential);
+        } else if (potential instanceof AnyXmlSchemaNode) {
+            return new AnyXmlContextNode((AnyXmlSchemaNode) potential);
+        }
+        return null;
+    }
+
+    private static DataSchemaContextNode<?> fromListSchemaNode(final ListSchemaNode potential) {
+        List<QName> keyDefinition = potential.getKeyDefinition();
+        if (keyDefinition == null || keyDefinition.isEmpty()) {
+            return new UnkeyedListMixinContextNode(potential);
+        }
+        if (potential.isUserOrdered()) {
+            return new OrderedMapMixinContextNode(potential);
+        }
+        return new UnorderedMapMixinContextNode(potential);
+    }
+
+    private static DataSchemaContextNode<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
+        if (potential.isUserOrdered()) {
+            return new OrderedLeafListMixinContextNode(potential);
+        }
+        return new UnorderedLeafListMixinContextNode(potential);
+    }
+
+    public static DataSchemaContextNode<?> from(final SchemaContext ctx) {
+        return new ContainerContextNode(ctx);
+    }
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java
new file mode 100644 (file)
index 0000000..27224b4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import java.util.Iterator;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class DataSchemaContextTree {
+
+    private static final LoadingCache<SchemaContext, DataSchemaContextTree> TREES = CacheBuilder.newBuilder()
+            .weakKeys()
+            .build(new CacheLoader<SchemaContext, DataSchemaContextTree>() {
+
+                @Override
+                public DataSchemaContextTree load(SchemaContext key) throws Exception {
+                    return new DataSchemaContextTree(key);
+                }
+
+            });
+
+    private final DataSchemaContextNode<?> root;
+
+    private DataSchemaContextTree(final SchemaContext ctx) {
+        root = DataSchemaContextNode.from(ctx);
+    }
+
+
+    public static DataSchemaContextTree from(SchemaContext ctx) {
+        return TREES.getUnchecked(ctx);
+    }
+
+    public DataSchemaContextNode<?> getChild(final YangInstanceIdentifier path) {
+        DataSchemaContextNode<?> currentOp = root;
+        Iterator<PathArgument> arguments = path.getPathArguments().iterator();
+        while (arguments.hasNext()) {
+            currentOp = currentOp.getChild(arguments.next());
+        }
+        return currentOp;
+    }
+
+    public DataSchemaContextNode<?> getRoot() {
+        return root;
+    }
+
+}
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafContextNode.java
new file mode 100644 (file)
index 0000000..378d235
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+final class LeafContextNode extends AbstractLeafNodeContext<NodeIdentifier> {
+
+    protected LeafContextNode(final LeafSchemaNode potential) {
+        super(new NodeIdentifier(potential.getQName()), potential);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryContextNode.java
new file mode 100644 (file)
index 0000000..c8dd12c
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+final class LeafListEntryContextNode extends AbstractLeafNodeContext<NodeWithValue> {
+
+    public LeafListEntryContextNode(final LeafListSchemaNode potential) {
+        super(new NodeWithValue(potential.getQName(), null), potential);
+    }
+
+    @Override
+    public boolean isKeyedEntry() {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListItemContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListItemContextNode.java
new file mode 100644 (file)
index 0000000..3465f56
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+final class ListItemContextNode extends
+        DataContainerContextNode<NodeIdentifierWithPredicates> {
+
+
+    protected ListItemContextNode(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
+        super(identifier, schema, schema);
+    }
+
+    @Override
+    public boolean isKeyedEntry() {
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedLeafListMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedLeafListMixinContextNode.java
new file mode 100644 (file)
index 0000000..31143ae
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+final class OrderedLeafListMixinContextNode extends UnorderedLeafListMixinContextNode {
+
+    public OrderedLeafListMixinContextNode(final LeafListSchemaNode potential) {
+        super(potential);
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedMapMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedMapMixinContextNode.java
new file mode 100644 (file)
index 0000000..81eeb90
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+final class OrderedMapMixinContextNode extends UnorderedMapMixinContextNode {
+
+    public OrderedMapMixinContextNode(final ListSchemaNode list) {
+        super(list);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListItemContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListItemContextNode.java
new file mode 100644 (file)
index 0000000..cbf773d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+final class UnkeyedListItemContextNode extends DataContainerContextNode<NodeIdentifier> {
+
+    protected UnkeyedListItemContextNode(final ListSchemaNode schema) {
+        super(new NodeIdentifier(schema.getQName()), schema, schema);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListMixinContextNode.java
new file mode 100644 (file)
index 0000000..6a5a443
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class UnkeyedListMixinContextNode extends AbstractMixinContextNode<NodeIdentifier> {
+
+    private final UnkeyedListItemContextNode innerNode;
+
+    public UnkeyedListMixinContextNode(final ListSchemaNode list) {
+        super(new NodeIdentifier(list.getQName()), list);
+        this.innerNode = new UnkeyedListItemContextNode(list);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        if (child.getNodeType().equals(getIdentifier().getNodeType())) {
+            return innerNode;
+        }
+        return null;
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        if (getIdentifier().getNodeType().equals(child)) {
+            return innerNode;
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedLeafListMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedLeafListMixinContextNode.java
new file mode 100644 (file)
index 0000000..13f77e7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+
+class UnorderedLeafListMixinContextNode extends AbstractMixinContextNode<NodeIdentifier> {
+
+    private final DataSchemaContextNode<?> innerOp;
+
+    public UnorderedLeafListMixinContextNode(final LeafListSchemaNode potential) {
+        super(new NodeIdentifier(potential.getQName()), potential);
+        innerOp = new LeafListEntryContextNode(potential);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        if (child instanceof NodeWithValue) {
+            return innerOp;
+        }
+        return null;
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        if (getIdentifier().getNodeType().equals(child)) {
+            return innerOp;
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedMapMixinContextNode.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedMapMixinContextNode.java
new file mode 100644 (file)
index 0000000..10a3d0e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import java.util.Collections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+
+class UnorderedMapMixinContextNode extends AbstractMixinContextNode<NodeIdentifier> {
+
+    private final ListItemContextNode innerNode;
+
+    public UnorderedMapMixinContextNode(final ListSchemaNode list) {
+        super(new NodeIdentifier(list.getQName()), list);
+        this.innerNode = new ListItemContextNode(new NodeIdentifierWithPredicates(list.getQName(),
+                Collections.<QName, Object> emptyMap()), list);
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final PathArgument child) {
+        if (child.getNodeType().equals(getIdentifier().getNodeType())) {
+            return innerNode;
+        }
+        return null;
+    }
+
+    @Override
+    public DataSchemaContextNode<?> getChild(final QName child) {
+        if (getIdentifier().getNodeType().equals(child)) {
+            return innerNode;
+        }
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java
new file mode 100644 (file)
index 0000000..d25f065
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.util;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import java.util.LinkedList;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Builder;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+/**
+ *
+ * Iterator which lazily parses {@link PathArgument} from string representation.
+ *
+ * Note that invocation of {@link #hasNext()} or {@link #next()} may result in
+ * throwing of {@link IllegalArgumentException} if underlying string represenation
+ * is not correctly serialized or does not represent instance identifier valid
+ * for associated schema context.
+ *
+ * In order to obtain {@link Iterable} or {@link java.util.Collection} please use
+ * {@link com.google.common.collect.ImmutableList#copyOf(java.util.Iterator)}
+ * with this Iterator, which will trigger computation of all path arguments.
+ *
+ */
+class XpathStringParsingPathArgumentBuilder implements Builder<Iterable<PathArgument>> {
+
+    /**
+     * Matcher matching WSP YANG ABNF token
+     *
+     */
+    private static final CharMatcher WSP = CharMatcher.anyOf(" \t");
+
+    /**
+     * Matcher matching IDENTIFIER first char token.
+     *
+     */
+    private static final CharMatcher IDENTIFIER_FIRST_CHAR =
+            CharMatcher.inRange('a', 'z')
+            .or(CharMatcher.inRange('A', 'Z'))
+            .or(CharMatcher.is('_')).precomputed();
+    /**
+     *
+     * Matcher matching IDENTIFIER token
+     *
+     */
+    private static final CharMatcher IDENTIFIER =
+            IDENTIFIER_FIRST_CHAR
+            .or(CharMatcher.inRange('0', '9'))
+            .or(CharMatcher.anyOf(".-")).precomputed();
+
+    private static final CharMatcher SQUOTE = CharMatcher.is('\'');
+    private static final CharMatcher DQUOTE = CharMatcher.is('"');
+
+    private static final char SLASH = '/';
+    private static final char COLON = ':';
+    private static final char DOT = '.';
+    private static final char EQUALS = '=';
+    private static final char PRECONDITION_START = '[';
+    private static final char PRECONDITION_END = ']';
+
+    private final AbstractStringInstanceIdentifierCodec codec;
+    private final String data;
+
+    private final LinkedList<PathArgument> product = new LinkedList<>();
+
+    private DataSchemaContextNode<?> current;
+    private int offset;
+
+    XpathStringParsingPathArgumentBuilder(AbstractStringInstanceIdentifierCodec codec, String data) {
+        this.codec = Preconditions.checkNotNull(codec);
+        this.data = Preconditions.checkNotNull(data);
+        this.current = codec.getDataContextTree().getRoot();
+        this.offset = 0;
+    }
+
+
+    @Override
+    public Iterable<PathArgument> build() {
+        while (!allCharactersConsumed()) {
+            product.add(computeNextArgument());
+        }
+        return ImmutableList.copyOf(product);
+    }
+
+    private PathArgument computeNextArgument() {
+        checkValid(SLASH  == currentChar(),"Identifier must start with '/'.");
+        skipCurrentChar();
+
+        QName name = nextQName();
+        if(allCharactersConsumed() || SLASH == currentChar()) {
+            return computeIdentifier(name);
+        } else {
+            checkValid(PRECONDITION_START == currentChar(), "Last element must be identifier, predicate or '/'");
+            return computeIdentifierWithPredicate(name);
+        }
+    }
+
+
+    private DataSchemaContextNode<?> nextContextNode(QName name) {
+        current = current.getChild(name);
+        checkValid(current != null, "%s is not correct schema node identifier.",name);
+        while(current.isMixin()) {
+            product.add(current.getIdentifier());
+            current = current.getChild(name);
+        }
+        return current;
+    }
+
+
+    /**
+     *
+     * Creates path argument with predicates and sets offset
+     * to end of path argument.
+     *
+     * {@code
+     *     predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
+     *     predicate-expr = (node-identifier / ".") *WSP "=" *WSP
+     *          ((DQUOTE string DQUOTE) /
+     *           (SQUOTE string SQUOTE))
+     *     pos = non-negative-integer-value
+     * }
+     *
+     * @param name QName of node, for which predicates are computed.
+     * @return PathArgument representing node selection with predictes
+     */
+    private PathArgument computeIdentifierWithPredicate(QName name) {
+        DataSchemaContextNode<?> currentNode = nextContextNode(name);
+        checkValid(currentNode.isKeyedEntry(), "Entry %s does not allow specifying predicates.", name);
+
+        ImmutableMap.Builder<QName,Object> keyValues = ImmutableMap.builder();
+        while(!allCharactersConsumed() && PRECONDITION_START == currentChar()) {
+            skipCurrentChar();
+            skipWhitespaces();
+            final QName key;
+            if(DOT == currentChar()) {
+                key = null;
+                skipCurrentChar();
+            } else {
+                key = nextQName();
+            }
+            skipWhitespaces();
+            checkCurrentAndSkip(EQUALS, "Precondition must contain '='");
+            skipWhitespaces();
+            final Object value = deserializeValue(key,nextQuotedValue());
+            skipWhitespaces();
+            checkCurrentAndSkip(PRECONDITION_END, "Precondition must ends with ']'");
+
+            // Break-out from method for leaf-list case
+            if(key == null && currentNode.isLeaf()) {
+                checkValid(offset == data.length(), "Leaf argument must be last argument of instance identifier.");
+                return new YangInstanceIdentifier.NodeWithValue(name, value);
+            }
+            keyValues.put(key, value);
+        }
+        return new YangInstanceIdentifier.NodeIdentifierWithPredicates(name, keyValues.build());
+    }
+
+
+    private PathArgument computeIdentifier(QName name) {
+        DataSchemaContextNode<?> currentNode = nextContextNode(name);
+        checkValid(!currentNode.isKeyedEntry(), "Entry %s requires key or value predicate to be present", name);
+        return currentNode.getIdentifier();
+    }
+
+
+    /**
+     *
+     * Returns following QName and sets offset to end of QName.
+     *
+     * @return following QName.
+     */
+    private QName nextQName() {
+        // Consume prefix or identifie
+        final String maybePrefix = nextIdentifier();
+        final String prefix,localName;
+        if(COLON == currentChar()) {
+            // previous token is prefix;
+            prefix = maybePrefix;
+            skipCurrentChar();
+            localName = nextIdentifier();
+        } else {
+            prefix = "";
+            localName = maybePrefix;
+        }
+        return createQName(prefix, localName);
+    }
+
+    /**
+     * Returns true if all characters from input string
+     * were consumed.
+     *
+     * @return true if all characters from input string
+     * were consumed.
+     */
+    private boolean allCharactersConsumed() {
+        return offset == data.length();
+    }
+
+
+    private QName createQName(String prefix, String localName) {
+        return codec.createQName(prefix, localName);
+    }
+
+    /**
+     *
+     * Skips current char if it equals expected otherwise fails parsing.
+     *
+     * @param expected Expected character
+     * @param errorMsg Error message if {@link #currentChar()} does not match expected.
+     */
+    private void checkCurrentAndSkip(char expected, String errorMsg) {
+        checkValid(expected == currentChar(), errorMsg);
+        offset++;
+    }
+
+
+    /**
+     *
+     * Deserializes value for supplied key
+     *
+     * @param key Name of referenced key, If null, referenced leaf is previous encountered item.
+     * @param value Value to be checked and deserialized
+     * @return Object representing value in yang-data-api format.
+     */
+    private Object deserializeValue(@Nullable QName key, String value) {
+        // FIXME: Use codec to deserialize value to correct Java type
+        return value;
+    }
+
+    /**
+     *
+     * Fails parsing if condition is not met.
+     *
+     * In case of error provides pointer to failed instance identifier,
+     * offset on which failure occured with explanation.
+     *
+     * @param condition Fails parsing if {@code condition} is false
+     * @param errorMsg Error message which will be provided to user.
+     * @param attributes
+     */
+    private void checkValid(boolean condition, String errorMsg, Object... attributes) {
+        Preconditions.checkArgument(condition, "Could not parse Instance Identifier '%s'. Offset: %s : Reason: %s",
+                data,
+                offset,
+                String.format(errorMsg, attributes));
+    }
+
+    /**
+     *
+     * Returns following value of quoted literal (without qoutes)
+     * and sets offset after literal.
+     *
+     * @return String literal
+     */
+    private String nextQuotedValue() {
+        char quoteChar = currentChar();
+        checkValidQuotation(quoteChar);
+        skipCurrentChar();
+        int valueStart = offset;
+        int endQoute = data.indexOf(quoteChar, offset);
+        String value = data.substring(valueStart, endQoute);
+        offset = endQoute;
+        skipCurrentChar();
+        return value;
+    }
+
+    /**
+     * Returns character at current offset.
+     *
+     * @return character at current offset.
+     */
+    private char currentChar() {
+        return data.charAt(offset);
+    }
+
+    /**
+     * Increases processing offset by 1
+     */
+    private void skipCurrentChar() {
+        offset++;
+    }
+
+    /**
+     * Skip whitespace characters, sets offset to first following
+     * non-whitespace character.
+     */
+    private void skipWhitespaces() {
+        nextSequenceEnd(WSP);
+    }
+
+    /**
+     * Returns string which matches IDENTIFIER YANG ABNF token
+     * and sets processing offset after end of identifier.
+     *
+     * @return string which matches IDENTIFIER YANG ABNF token
+     */
+    private String nextIdentifier() {
+        int start = offset;
+        checkValid(IDENTIFIER_FIRST_CHAR.matches(currentChar()), "Identifier must start with character from set 'a-zA-Z_'");
+        nextSequenceEnd(IDENTIFIER);
+        return data.substring(start, offset);
+    }
+
+    private void nextSequenceEnd(CharMatcher matcher) {
+        while(!allCharactersConsumed() && matcher.matches(data.charAt(offset))) {
+            offset++;
+        }
+    }
+
+    private void checkValidQuotation(char quoteChar) {
+        checkValid(
+                SQUOTE.matches(quoteChar) || DQUOTE.matches(quoteChar),
+                "Value must be qoute escaped with ''' or '\"'.");
+
+    }
+
+}
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java
new file mode 100644 (file)
index 0000000..88d356e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+/**
+ * Proxy for AugmentationSchema. Child node schemas are replaced with actual schemas from parent.
+ *
+ * FIXME: Make this class final, once derived deprecated class is removed.
+ */
+public class EffectiveAugmentationSchema implements AugmentationSchema {
+    private final AugmentationSchema delegate;
+    private final Set<DataSchemaNode> realChildSchemas;
+    private final Map<QName, DataSchemaNode> mappedChildSchemas;
+
+    public EffectiveAugmentationSchema(final AugmentationSchema augmentSchema, final Set<DataSchemaNode> realChildSchemas) {
+        this.delegate = augmentSchema;
+        this.realChildSchemas = realChildSchemas;
+
+        final Map<QName, DataSchemaNode> m = new HashMap<>(realChildSchemas.size());
+        for (DataSchemaNode realChildSchema : realChildSchemas) {
+            m.put(realChildSchema.getQName(), realChildSchema);
+        }
+
+        this.mappedChildSchemas = ImmutableMap.copyOf(m);
+    }
+
+    @Override
+    public RevisionAwareXPath getWhenCondition() {
+        return delegate.getWhenCondition();
+    }
+
+    @Override
+    public String getDescription() {
+        return delegate.getDescription();
+    }
+
+    @Override
+    public String getReference() {
+        return delegate.getReference();
+    }
+
+    @Override
+    public Status getStatus() {
+        return delegate.getStatus();
+    }
+
+    @Override
+    public SchemaPath getTargetPath() {
+        return delegate.getTargetPath();
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return delegate.getUnknownSchemaNodes();
+    }
+
+    @Override
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        return delegate.getTypeDefinitions();
+    }
+
+    @Override
+    public Set<DataSchemaNode> getChildNodes() {
+        return realChildSchemas;
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return delegate.getGroupings();
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final QName name) {
+        return mappedChildSchemas.get(name);
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final String name) {
+        // Unused
+        throw new UnsupportedOperationException("Unable to retrieve child node by name");
+    }
+
+    @Override
+    public Set<UsesNode> getUses() {
+        return delegate.getUses();
+    }
+
+    @Override
+    public Optional<AugmentationSchema> getOriginalDefinition() {
+        return delegate.getOriginalDefinition();
+    }
+}