From 052bd27d118a2addb3eae2253515890369a60182 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Mon, 2 Mar 2015 14:39:49 +0100 Subject: [PATCH] Bug 2766: Fixed parsing and serializing XPath Instance Identifiers 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 --- .../JSONStringInstanceIdentifierCodec.java | 8 + .../gson/NormalizedNodeToJsonStreamTest.java | 33 +- ...estingNormalizedNodeStructuresCreator.java | 17 +- .../resources/complexjson/complex-json.json | 2 +- .../keyed-list-node-in-container.json | 2 +- .../yang/data/impl/codec/SchemaTracker.java | 4 +- .../xml/ElementInstanceIdentifierParser.java | 10 +- .../xml/InstanceIdentifierForXmlCodec.java | 13 +- ...domPrefixInstanceIdentifierSerializer.java | 14 +- .../data/impl/codec/xml/XmlStreamUtils.java | 35 +- .../yang/data/impl/codec/xml/XmlUtils.java | 7 +- .../base/AugmentationSchemaProxy.java | 100 +----- .../base/parser/BaseDispatcherParser.java | 4 +- .../serializer/BaseDispatcherSerializer.java | 12 +- ...DataNodeContainerModificationStrategy.java | 17 +- .../impl/codec/xml/XmlDocumentUtilsTest.java | 4 +- yang/yang-data-util/pom.xml | 8 + .../util/AbstractInteriorContextNode.java | 25 ++ .../data/util/AbstractLeafNodeContext.java | 35 ++ .../data/util/AbstractMixinContextNode.java | 25 ++ ...AbstractStringInstanceIdentifierCodec.java | 123 ++----- .../yang/data/util/AnyXmlContextNode.java | 36 ++ .../data/util/AugmentationContextNode.java | 46 +++ .../yang/data/util/ChoiceNodeContextNode.java | 49 +++ .../yang/data/util/ContainerContextNode.java | 19 + .../data/util/DataContainerContextNode.java | 75 ++++ .../yang/data/util/DataSchemaContextNode.java | 207 +++++++++++ .../yang/data/util/DataSchemaContextTree.java | 55 +++ .../yang/data/util/LeafContextNode.java | 19 + .../data/util/LeafListEntryContextNode.java | 23 ++ .../yang/data/util/ListItemContextNode.java | 25 ++ .../util/OrderedLeafListMixinContextNode.java | 17 + .../data/util/OrderedMapMixinContextNode.java | 18 + .../data/util/UnkeyedListItemContextNode.java | 19 + .../util/UnkeyedListMixinContextNode.java | 40 +++ .../UnorderedLeafListMixinContextNode.java | 40 +++ .../util/UnorderedMapMixinContextNode.java | 43 +++ ...XpathStringParsingPathArgumentBuilder.java | 326 ++++++++++++++++++ .../util/EffectiveAugmentationSchema.java | 114 ++++++ 39 files changed, 1417 insertions(+), 252 deletions(-) create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractInteriorContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractLeafNodeContext.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AugmentationContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataContainerContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListItemContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedLeafListMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedMapMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListItemContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedLeafListMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedMapMixinContextNode.java create mode 100644 yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java create mode 100644 yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java diff --git a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java index 77fa797efa..528162a359 100644 --- a/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java +++ b/yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONStringInstanceIdentifierCodec.java @@ -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 { 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; diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java index 484aa70029..90fd51b803 100644 --- a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java +++ b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/NormalizedNodeToJsonStreamTest.java @@ -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()); } diff --git a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java index 71a2b99e7f..140c7ff008 100644 --- a/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java +++ b/yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/TestingNormalizedNodeStructuresCreator.java @@ -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 childLflst11() { @@ -270,7 +269,7 @@ public class TestingNormalizedNodeStructuresCreator { public static NormalizedNode leafNodeInContainer() { LeafNode 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); } diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json index fd4538833b..07490bdb63 100644 --- a/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json +++ b/yang/yang-data-codec-gson/src/test/resources/complexjson/complex-json.json @@ -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" } diff --git a/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-node-in-container.json b/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-node-in-container.json index 7cb51939ab..dbcc8a91e8 100644 --- a/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-node-in-container.json +++ b/yang/yang-data-codec-gson/src/test/resources/complexjson/keyed-list-node-in-container.json @@ -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" } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java index 79df0ea200..09aa9c8a2b 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java @@ -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; } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java index 11944faad8..150189ae11 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/ElementInstanceIdentifierParser.java @@ -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; + } + } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java index 563641fd68..ce304c82eb 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/InstanceIdentifierForXmlCodec.java @@ -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 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); diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java index a6fa1c0c51..9c2c613ebf 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/RandomPrefixInstanceIdentifierSerializer.java @@ -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> getPrefixes() { return prefixes.getPrefixes(); @@ -30,4 +37,9 @@ final class RandomPrefixInstanceIdentifierSerializer extends AbstractStringInsta throw new UnsupportedOperationException("Not implemented"); } + @Override + protected DataSchemaContextTree getDataContextTree() { + return schemaTree; + } + } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java index f9f6a70ac2..541253d09f 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlStreamUtils.java @@ -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 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> prefixes) throws XMLStreamException { + for (Entry 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); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java index e6cfd58e7d..cfb8fc0897 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlUtils.java @@ -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()) { diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/AugmentationSchemaProxy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/AugmentationSchemaProxy.java index 7fec679d1d..4a75a3faa3 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/AugmentationSchemaProxy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/AugmentationSchemaProxy.java @@ -7,108 +7,22 @@ */ 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 realChildSchemas; - private final Map mappedChildSchemas; - - public AugmentationSchemaProxy(final AugmentationSchema augmentSchema, final Set realChildSchemas) { - this.delegate = augmentSchema; - this.realChildSchemas = realChildSchemas; - - final Map 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 getUnknownSchemaNodes() { - return delegate.getUnknownSchemaNodes(); - } - - @Override - public Set> getTypeDefinitions() { - return delegate.getTypeDefinitions(); - } - - @Override - public Set getChildNodes() { - return realChildSchemas; - } - - @Override - public Set 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 getUses() { - return delegate.getUses(); + public AugmentationSchemaProxy(final AugmentationSchema augmentSchema, final Set realChildSchemas) { + super(augmentSchema,realChildSchemas); } - @Override - public Optional getOriginalDefinition() { - return delegate.getOriginalDefinition(); - } } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/BaseDispatcherParser.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/BaseDispatcherParser.java index ed458c6c65..833767bdc7 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/BaseDispatcherParser.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/parser/BaseDispatcherParser.java @@ -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, S> for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) { Set realChildSchemas = getRealSchemasForAugment(schema, augmentSchema); - AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas); + EffectiveAugmentationSchema augSchemaProxy = new EffectiveAugmentationSchema(augmentSchema, realChildSchemas); containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema))); } diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/serializer/BaseDispatcherSerializer.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/serializer/BaseDispatcherSerializer.java index d356508da4..a58ecc5a61 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/serializer/BaseDispatcherSerializer.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/transform/base/serializer/BaseDispatcherSerializer.java @@ -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 AugmentationSchema augSchema = getAugmentedCase(schema, (AugmentationNode) choiceChild); Set realChildSchemas = getRealSchemasForAugment(schema, augSchema); - childSchema = new AugmentationSchemaProxy(augSchema, realChildSchemas); + childSchema = new EffectiveAugmentationSchema(augSchema, realChildSchemas); } else { childSchema = getSchemaForChild(schema, choiceChild); diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/DataNodeContainerModificationStrategy.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/DataNodeContainerModificationStrategy.java index bfa3f28e6e..e239c38bf0 100644 --- a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/DataNodeContainerModificationStrategy.java +++ b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/DataNodeContainerModificationStrategy.java @@ -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 realChildSchemas = new HashSet<>(); for(DataSchemaNode augChild : schema.getChildNodes()) { realChildSchemas.add(resolved.getDataChildByName(augChild.getQName())); } - return new AugmentationSchemaProxy(schema, realChildSchemas); + return new EffectiveAugmentationSchema(schema, realChildSchemas); } } diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtilsTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtilsTest.java index e93a5704d5..308fac9601 100644 --- a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtilsTest.java +++ b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/codec/xml/XmlDocumentUtilsTest.java @@ -54,7 +54,9 @@ public class XmlDocumentUtilsTest { public static final String XML_CONTENT = "\n" + "value\n" + - "/ltha:cont/ltha:l[ltha:id='id']\n" + + ""+ + "/ltha:cont/ltha:l[ ltha:id='id/foo/bar' ]"+ + "\n" + ""; public static final String RPC_REPLY = "\n" + diff --git a/yang/yang-data-util/pom.xml b/yang/yang-data-util/pom.xml index b86f440019..85d904a269 100644 --- a/yang/yang-data-util/pom.xml +++ b/yang/yang-data-util/pom.xml @@ -26,5 +26,13 @@ ${project.groupId} yang-data-api + + ${project.groupId} + yang-model-api + + + ${project.groupId} + yang-model-util + 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 index 0000000000..0ec3baf3f5 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractInteriorContextNode.java @@ -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 extends + DataSchemaContextNode { + + 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 index 0000000000..84e8a9783b --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractLeafNodeContext.java @@ -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 extends DataSchemaContextNode { + + 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 index 0000000000..3806612fd9 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractMixinContextNode.java @@ -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 extends + AbstractInteriorContextNode { + + protected AbstractMixinContextNode(final T identifier, final DataSchemaNode schema) { + super(identifier, schema); + } + + @Override + public final boolean isMixin() { + return true; + } + +} \ No newline at end of file diff --git a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java index 3e47e966cf..ef6ac8eb31 100644 --- a/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java @@ -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 { - 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 xPathParts = SLASH_SPLITTER.split(data).iterator(); - - // must be at least "/pr:node" - if (!xPathParts.hasNext() || !xPathParts.next().isEmpty() || !xPathParts.hasNext()) { - return null; - } - - List 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 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 index 0000000000..fa6f64c506 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AnyXmlContextNode.java @@ -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 { + + 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 index 0000000000..a2393ca0e7 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AugmentationContextNode.java @@ -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 { + + 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 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 index 0000000000..216e3f5e61 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ChoiceNodeContextNode.java @@ -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 { + + private final ImmutableMap> byQName; + private final ImmutableMap> byArg; + + protected ChoiceNodeContextNode(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) { + super(new NodeIdentifier(schema.getQName()), schema); + ImmutableMap.Builder> byQNameBuilder = ImmutableMap.builder(); + ImmutableMap.Builder> 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 index 0000000000..10e49b6e32 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerContextNode.java @@ -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 { + + 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 index 0000000000..2cbbf1f253 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataContainerContextNode.java @@ -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 extends + AbstractInteriorContextNode { + + private final DataNodeContainer schema; + private final Map> byQName; + private final Map> 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 index 0000000000..050255e921 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextNode.java @@ -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 Path Argument type + * + */ +public abstract class DataSchemaContextNode implements Identifiable { + + 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 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 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 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 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 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 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 index 0000000000..27224b49a0 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/DataSchemaContextTree.java @@ -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 TREES = CacheBuilder.newBuilder() + .weakKeys() + .build(new CacheLoader() { + + @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 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 index 0000000000..378d23525b --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafContextNode.java @@ -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 { + + 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 index 0000000000..c8dd12ca05 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/LeafListEntryContextNode.java @@ -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 { + + 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 index 0000000000..3465f5638b --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ListItemContextNode.java @@ -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 { + + + 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 index 0000000000..31143ae303 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedLeafListMixinContextNode.java @@ -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 index 0000000000..81eeb90814 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/OrderedMapMixinContextNode.java @@ -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 index 0000000000..cbf773d626 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListItemContextNode.java @@ -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 { + + 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 index 0000000000..6a5a443b70 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnkeyedListMixinContextNode.java @@ -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 { + + 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 index 0000000000..13f77e7051 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedLeafListMixinContextNode.java @@ -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 { + + 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 index 0000000000..10a3d0ec2b --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/UnorderedMapMixinContextNode.java @@ -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 { + + private final ListItemContextNode innerNode; + + public UnorderedMapMixinContextNode(final ListSchemaNode list) { + super(new NodeIdentifier(list.getQName()), list); + this.innerNode = new ListItemContextNode(new NodeIdentifierWithPredicates(list.getQName(), + Collections. 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 index 0000000000..d25f0655c0 --- /dev/null +++ b/yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java @@ -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> { + + /** + * 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 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 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 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 index 0000000000..88d356ee97 --- /dev/null +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/EffectiveAugmentationSchema.java @@ -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 realChildSchemas; + private final Map mappedChildSchemas; + + public EffectiveAugmentationSchema(final AugmentationSchema augmentSchema, final Set realChildSchemas) { + this.delegate = augmentSchema; + this.realChildSchemas = realChildSchemas; + + final Map 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 getUnknownSchemaNodes() { + return delegate.getUnknownSchemaNodes(); + } + + @Override + public Set> getTypeDefinitions() { + return delegate.getTypeDefinitions(); + } + + @Override + public Set getChildNodes() { + return realChildSchemas; + } + + @Override + public Set 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 getUses() { + return delegate.getUses(); + } + + @Override + public Optional getOriginalDefinition() { + return delegate.getOriginalDefinition(); + } +} -- 2.36.6