Reimplement SchemaContextUtil.getBaseTypeForLeafRef() 99/94599/22
authormiroslav.kovac <miroslav.kovac@pantheon.tech>
Tue, 5 Jan 2021 14:00:46 +0000 (15:00 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 16 Feb 2021 08:40:25 +0000 (09:40 +0100)
This is the primary entry point to resolution of TypeDefinitions
and generally inferring along the data tree. We already have
required utilities in SchemaInferenceStack.

Introduce SchemaInferenceStack.resolvePathExpression(), which
serves the serves the same purpose, but results in a stack
manipulation.

This completely removes the need to perform any string-based
operations, or dedicated SchemaNode lookups or anything of that
kind -- removing a lot of legacy crud.

JIRA: YANGTOOLS-1127
JIRA: YANGTOOLS-1229
Change-Id: I64e4f4ef2062ab2a0d143a520a53e8972cf54b26
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
38 files changed:
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactory.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONCodecFactorySupplier.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONInstanceIdentifierCodec.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.java
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonParserStream.java
yang/yang-data-codec-gson/src/test/java/org/opendaylight/yangtools/yang/data/codec/gson/JsonStreamToNormalizedNodeTest.java
yang/yang-data-codec-gson/src/test/resources/bug-4969/yang/bar.yang
yang/yang-data-codec-gson/src/test/resources/leafref/yang/augment-leafref-module.yang
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamNormalizedNodeStreamWriter.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemaAwareXMLStreamWriterUtils.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/SchemalessXMLStreamWriterUtils.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XMLStreamWriterUtils.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlCodecFactory.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlParserStream.java
yang/yang-data-codec-xml/src/main/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStringInstanceIdentifierCodec.java
yang/yang-data-codec-xml/src/test/java/org/opendaylight/yangtools/yang/data/codec/xml/XmlStreamUtilsTest.java
yang/yang-data-util/src/main/java/module-info.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/AbstractStringInstanceIdentifierCodec.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/ContainerSchemaNodes.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/NormalizedNodeStreamWriterStack.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/XpathStringParsingPathArgumentBuilder.java
yang/yang-data-util/src/main/java/org/opendaylight/yangtools/yang/data/util/codec/AbstractCodecFactory.java
yang/yang-model-util/pom.xml
yang/yang-model-util/src/main/java/module-info.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/LeafrefResolver.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java [deleted file]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaInferenceStack.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Bug4969Test.java [deleted file]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/LeafrefStaticAnalysisTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtilIntegrationTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtilTest.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1050Test.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1060Test.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT1100Test.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/YT588Test.java
yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug5335Test.java
yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/RpcStmtTest.java

index e3fee0126edc4f5a7349af475b8509a141173c93..aaa67301959ca07ec457108de875cd5a8f889889 100644 (file)
@@ -7,8 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.gson;
 
-import static com.google.common.base.Verify.verifyNotNull;
-
 import com.google.common.annotations.Beta;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
@@ -24,7 +22,6 @@ import org.opendaylight.yangtools.yang.data.util.codec.AbstractCodecFactory;
 import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.LazyCodecCache;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
@@ -44,7 +41,6 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 /**
  * Factory for creating JSON equivalents of codecs. Each instance of this object is bound to
@@ -167,10 +163,4 @@ public abstract class JSONCodecFactory extends AbstractCodecFactory<JSONCodec<?>
     abstract JSONCodec<?> wrapDecimalCodec(DecimalStringCodec decimalCodec);
 
     abstract JSONCodec<?> wrapIntegerCodec(AbstractIntegerStringCodec<?, ?> integerCodec);
-
-    final JSONCodec<?> codecFor(final TypedDataSchemaNode currentNode) {
-        return codecFor(currentNode, type -> verifyNotNull(
-            SchemaContextUtil.getBaseTypeForLeafRef(type, getEffectiveModelContext(), currentNode),
-            "Unable to find base type for leafref node %s type %s.", currentNode, type));
-    }
 }
index c42e4d510266c648d8a88bc550d4aa1b38521945..2c3dacd2fe2a2255479b12e4ea3523506a7590f0 100644 (file)
@@ -15,18 +15,22 @@ import com.google.common.base.Stopwatch;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import java.util.Map;
 import java.util.Optional;
 import java.util.function.BiFunction;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.util.codec.CodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.LazyCodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.NoopCodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.PrecomputedCodecCache;
 import org.opendaylight.yangtools.yang.data.util.codec.SharedCodecCache;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,7 +75,13 @@ public enum JSONCodecFactorySupplier {
             final Stopwatch sw = Stopwatch.createStarted();
             final LazyCodecCache<JSONCodec<?>> lazyCache = new LazyCodecCache<>();
             final JSONCodecFactory lazy = factorySupplier.apply(key, lazyCache);
-            final int visitedLeaves = requestCodecsForChildren(lazy, key);
+            final SchemaInferenceStack stack = SchemaInferenceStack.of(key);
+
+            int visitedLeaves = 0;
+            for (ModuleEffectiveStatement module : key.getModuleStatements().values()) {
+                visitedLeaves += codecsForChildren(lazy, stack, module);
+                stack.clear();
+            }
             sw.stop();
 
             final PrecomputedCodecCache<JSONCodec<?>> cache = lazyCache.toPrecomputed();
@@ -80,14 +90,19 @@ public enum JSONCodecFactorySupplier {
             return factorySupplier.apply(key, cache);
         }
 
-        private static int requestCodecsForChildren(final JSONCodecFactory lazy, final DataNodeContainer parent) {
+        private static int codecsForChildren(final JSONCodecFactory lazy, final SchemaInferenceStack stack,
+                final DataTreeAwareEffectiveStatement<?, ?> parent) {
             int ret = 0;
-            for (DataSchemaNode child : parent.getChildNodes()) {
-                if (child instanceof TypedDataSchemaNode) {
-                    lazy.codecFor((TypedDataSchemaNode) child);
+            final Map<QName, DataTreeEffectiveStatement<?>> dataTree =
+                parent.getAll(DataTreeAwareEffectiveStatement.Namespace.class);
+            for (DataTreeEffectiveStatement<?> child : dataTree.values()) {
+                if (child instanceof DataTreeAwareEffectiveStatement) {
+                    stack.enterDataTree(child.argument());
+                    ret += codecsForChildren(lazy, stack, (DataTreeAwareEffectiveStatement<?, ?>) child);
+                    stack.exit();
+                } else if (child instanceof TypedDataSchemaNode) {
+                    lazy.codecFor((TypedDataSchemaNode) child, stack);
                     ++ret;
-                } else if (child instanceof DataNodeContainer) {
-                    ret += requestCodecsForChildren(lazy, (DataNodeContainer) child);
                 }
             }
 
index 3daa0554019e3b84bd0d793202a8d403d1d3b8c3..cf7388f7e4cd66c26265a69796e1d52026c0a694 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 
 abstract class JSONInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
         implements JSONCodec<YangInstanceIdentifier> {
@@ -52,10 +53,11 @@ abstract class JSONInstanceIdentifierCodec extends AbstractModuleStringInstanceI
     }
 
     @Override
-    protected final Object deserializeKeyValue(final DataSchemaNode schemaNode, final String value) {
+    protected final Object deserializeKeyValue(final DataSchemaNode schemaNode, final LeafrefResolver resolver,
+            final String value) {
         requireNonNull(schemaNode, "schemaNode cannot be null");
         checkArgument(schemaNode instanceof LeafSchemaNode, "schemaNode must be of type LeafSchemaNode");
-        final JSONCodec<?> objectJSONCodec = codecFactory.codecFor((LeafSchemaNode) schemaNode);
+        final JSONCodec<?> objectJSONCodec = codecFactory.codecFor((LeafSchemaNode) schemaNode, resolver);
         return objectJSONCodec.parseValue(null, value);
     }
 
index 67e4c1f1b045225fe549b127a5b30f83a710aff1..a62b8029f5e7fef20cb8ea31411f625f0a5627f7 100644 (file)
@@ -406,7 +406,7 @@ public abstract class JSONNormalizedNodeStreamWriter implements NormalizedNodeSt
     public void scalarValue(final Object value) throws IOException {
         final Object current = tracker.getParent();
         if (current instanceof TypedDataSchemaNode) {
-            writeValue(value, codecs.codecFor((TypedDataSchemaNode) current));
+            writeValue(value, codecs.codecFor((TypedDataSchemaNode) current, tracker));
         } else if (current instanceof AnydataSchemaNode) {
             writeAnydataValue(value);
         } else {
index a1d2e49bb7469b92f953a08105441b847662e0b4..e6f8dfdc4354a07576a4ee8fbb8bcecdd6e9753a 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Set;
 import javax.xml.transform.dom.DOMSource;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.util.AbstractNodeDataWithSchema;
@@ -48,10 +49,12 @@ import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -72,15 +75,30 @@ public final class JsonParserStream implements Closeable, Flushable {
     private final JSONCodecFactory codecs;
     private final DataSchemaNode parentNode;
 
+    private final SchemaInferenceStack stack;
+
     // TODO: consider class specialization to remove this field
     private final boolean lenient;
 
     private JsonParserStream(final NormalizedNodeStreamWriter writer, final JSONCodecFactory codecs,
-            final DataSchemaNode parentNode, final boolean lenient) {
+            final SchemaInferenceStack stack, final boolean lenient) {
         this.writer = requireNonNull(writer);
         this.codecs = requireNonNull(codecs);
-        this.parentNode = parentNode;
+        this.stack = requireNonNull(stack);
         this.lenient = lenient;
+
+        if (!stack.isEmpty()) {
+            final EffectiveStatement<?, ?> parent = stack.currentStatement();
+            if (parent instanceof DataSchemaNode) {
+                parentNode =  (DataSchemaNode) parent;
+            } else if (parent instanceof OperationDefinition) {
+                parentNode =  OperationAsContainer.of((OperationDefinition) parent);
+            } else {
+                throw new IllegalArgumentException("Illegal parent node " + parent);
+            }
+        } else {
+            parentNode = stack.getEffectiveModelContext();
+        }
     }
 
     /**
@@ -95,7 +113,8 @@ public final class JsonParserStream implements Closeable, Flushable {
      */
     public static @NonNull JsonParserStream create(final @NonNull NormalizedNodeStreamWriter writer,
             final @NonNull JSONCodecFactory codecFactory) {
-        return new JsonParserStream(writer, codecFactory, codecFactory.getEffectiveModelContext(), false);
+        return new JsonParserStream(writer, codecFactory,
+            SchemaInferenceStack.of(codecFactory.getEffectiveModelContext()), false);
     }
 
     /**
@@ -109,8 +128,8 @@ public final class JsonParserStream implements Closeable, Flushable {
      * @throws NullPointerException if any of the arguments are null
      */
     public static @NonNull JsonParserStream create(final @NonNull NormalizedNodeStreamWriter writer,
-            final @NonNull JSONCodecFactory codecFactory, final @NonNull SchemaNode parentNode) {
-        return new JsonParserStream(writer, codecFactory, validateParent(parentNode), false);
+            final @NonNull JSONCodecFactory codecFactory, final @NonNull EffectiveStatementInference parentNode) {
+        return new JsonParserStream(writer, codecFactory, SchemaInferenceStack.ofInference(parentNode), false);
     }
 
     /**
@@ -131,7 +150,8 @@ public final class JsonParserStream implements Closeable, Flushable {
      */
     public static @NonNull JsonParserStream createLenient(final @NonNull NormalizedNodeStreamWriter writer,
             final @NonNull JSONCodecFactory codecFactory) {
-        return new JsonParserStream(writer, codecFactory, codecFactory.getEffectiveModelContext(), true);
+        return new JsonParserStream(writer, codecFactory,
+            SchemaInferenceStack.of(codecFactory.getEffectiveModelContext()), true);
     }
 
     /**
@@ -151,8 +171,8 @@ public final class JsonParserStream implements Closeable, Flushable {
      * @throws NullPointerException if any of the arguments are null
      */
     public static @NonNull JsonParserStream createLenient(final @NonNull NormalizedNodeStreamWriter writer,
-            final @NonNull JSONCodecFactory codecFactory, final @NonNull SchemaNode parentNode) {
-        return new JsonParserStream(writer, codecFactory, validateParent(parentNode), true);
+            final @NonNull JSONCodecFactory codecFactory, final @NonNull EffectiveStatementInference parentNode) {
+        return new JsonParserStream(writer, codecFactory, SchemaInferenceStack.ofInference(parentNode), true);
     }
 
     public JsonParserStream parse(final JsonReader reader) {
@@ -302,13 +322,15 @@ public final class JsonParserStream implements Closeable, Flushable {
                         "Schema for node with name %s and namespace %s does not exist at %s",
                         localName, getCurrentNamespace(), parentSchema);
 
-
+                    final QName qname = childDataSchemaNodes.peekLast().getQName();
                     final AbstractNodeDataWithSchema<?> newChild = ((CompositeNodeDataWithSchema<?>) parent)
                             .addChild(childDataSchemaNodes, ChildReusePolicy.NOOP);
                     if (newChild instanceof AnyXmlNodeDataWithSchema) {
                         readAnyXmlValue(in, (AnyXmlNodeDataWithSchema) newChild, jsonElementName);
                     } else {
+                        stack.enterDataTree(qname);
                         read(in, newChild);
+                        stack.exit();
                     }
                     removeNamespace();
                 }
@@ -343,7 +365,7 @@ public final class JsonParserStream implements Closeable, Flushable {
 
     private Object translateValueByType(final String value, final DataSchemaNode node) {
         checkArgument(node instanceof TypedDataSchemaNode);
-        return codecs.codecFor((TypedDataSchemaNode) node).parseValue(null, value);
+        return codecs.codecFor((TypedDataSchemaNode) node, stack).parseValue(null, value);
     }
 
     private void removeNamespace() {
@@ -424,16 +446,6 @@ public final class JsonParserStream implements Closeable, Flushable {
         return namespaces.peek();
     }
 
-    private static DataSchemaNode validateParent(final SchemaNode parent) {
-        if (parent instanceof DataSchemaNode) {
-            return (DataSchemaNode) parent;
-        } else if (parent instanceof OperationDefinition) {
-            return OperationAsContainer.of((OperationDefinition) parent);
-        } else {
-            throw new IllegalArgumentException("Illegal parent node " + requireNonNull(parent));
-        }
-    }
-
     @Override
     public void flush() throws IOException {
         writer.flush();
index 6146779275771840c4f800c4a192554b883d4948..773d159710a29cbe5c63b314305e3d882cd843c3 100644 (file)
@@ -31,7 +31,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
 
 /**
  * Each test tests whether json input is correctly transformed to normalized node structure.
@@ -190,8 +190,8 @@ public class JsonStreamToNormalizedNodeTest extends AbstractComplexJsonTest {
 
         final NormalizedNodeResult result = new NormalizedNodeResult();
         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
-        final SchemaNode parentNode = schemaContext.findDataChildByName(CONT_1).get();
-        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, lhotkaCodecFactory, parentNode);
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, lhotkaCodecFactory,
+            Inference.ofDataTreePath(schemaContext, CONT_1));
         jsonParser.parse(new JsonReader(new StringReader(inputJson)));
         final NormalizedNode transformedInput = result.getResult();
         assertNotNull(transformedInput);
@@ -203,8 +203,8 @@ public class JsonStreamToNormalizedNodeTest extends AbstractComplexJsonTest {
 
         final NormalizedNodeResult result = new NormalizedNodeResult();
         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
-        final SchemaNode parentNode = schemaContext.findDataChildByName(CONT_1).get();
-        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, lhotkaCodecFactory, parentNode);
+        final JsonParserStream jsonParser = JsonParserStream.create(streamWriter, lhotkaCodecFactory,
+            Inference.ofDataTreePath(schemaContext, CONT_1));
         jsonParser.parse(new JsonReader(new StringReader(inputJson)));
         final NormalizedNode transformedInput = result.getResult();
         assertNotNull(transformedInput);
@@ -216,9 +216,8 @@ public class JsonStreamToNormalizedNodeTest extends AbstractComplexJsonTest {
 
         final NormalizedNodeResult result = new NormalizedNodeResult();
         final NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
-        final SchemaNode parentNode = schemaContext.findDataChildByName(CONT_1).get();
 
-        final QName augmentChoice1QName = QName.create(parentNode.getQName(), "augment-choice1");
+        final QName augmentChoice1QName = QName.create(CONT_1, "augment-choice1");
         final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
         final QName containerQName = QName.create(augmentChoice1QName, "case11-choice-case-container");
         final QName leafQName = QName.create(augmentChoice1QName, "case11-choice-case-leaf");
@@ -230,7 +229,7 @@ public class JsonStreamToNormalizedNodeTest extends AbstractComplexJsonTest {
         final NodeIdentifier containerId = new NodeIdentifier(containerQName);
 
         final NormalizedNode cont1Normalized =
-                containerBuilder().withNodeIdentifier(new NodeIdentifier(parentNode.getQName()))
+                containerBuilder().withNodeIdentifier(new NodeIdentifier(CONT_1))
                         .withChild(augmentationBuilder().withNodeIdentifier(aug1Id)
                                 .withChild(choiceBuilder().withNodeIdentifier(augmentChoice1Id)
                                         .withChild(augmentationBuilder().withNodeIdentifier(aug2Id)
index b594d3d0a0afcc3b448f3ad82229cbea1b043cff..f90488f9dcae22201d7ac2ca6d30464593925e38 100644 (file)
@@ -20,19 +20,19 @@ module bar {
 
     typedef ref1-2 {
         type leafref {
-            path "/root/l1";
+            path "/bar:root/bar:l1";
         }
     }
 
     typedef ref2-2 {
         type leafref {
-            path "/root/l2";
+            path "/bar:root/bar:l2";
         }
     }
 
     typedef ref3-2 {
         type leafref {
-            path "/root/l3";
+            path "/bar:root/bar:l3";
         }
     }
 
index b8b57506ba9912311e05696a2f4bd4349bd7c5b5..7e9dcc2636732d1b9c1aa4656d2a7787813f396b 100644 (file)
@@ -7,7 +7,7 @@ module augment-leafref-module {
 
     typedef leafreftype {
         type leafref {
-            path "/cont/lf3";
+            path "/auglfrfmo:cont/auglfrfmo:lf3";
         }
     }
 
index 54be0c26226856214a65f09a396760299e56e7f8..f859479751f1a58a3681e4d58ff27cf94ab22006 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Optional;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
@@ -33,7 +34,9 @@ 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.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
 final class SchemaAwareXMLStreamNormalizedNodeStreamWriter
         extends XMLStreamNormalizedNodeStreamWriter<TypedDataSchemaNode> implements EffectiveModelContextProvider {
@@ -50,7 +53,7 @@ final class SchemaAwareXMLStreamNormalizedNodeStreamWriter
     @Override
     String encodeValue(final ValueWriter xmlWriter, final Object value, final TypedDataSchemaNode schemaNode)
             throws XMLStreamException {
-        return streamUtils.encodeValue(xmlWriter, schemaNode, schemaNode.getType(), value,
+        return streamUtils.encodeValue(xmlWriter, resolveType(schemaNode.getType()), value,
             schemaNode.getQName().getModule());
     }
 
@@ -60,8 +63,8 @@ final class SchemaAwareXMLStreamNormalizedNodeStreamWriter
         final Optional<AnnotationSchemaNode> optAnnotation =
             AnnotationSchemaNode.find(streamUtils.getEffectiveModelContext(), qname);
         if (optAnnotation.isPresent()) {
-            final AnnotationSchemaNode schema = optAnnotation.get();
-            return streamUtils.encodeValue(xmlWriter, schema, schema.getType(), value, qname.getModule());
+            return streamUtils.encodeValue(xmlWriter, resolveType(optAnnotation.get().getType()), value,
+                qname.getModule());
         }
 
         checkArgument(!qname.getRevision().isPresent(), "Failed to find bound annotation %s", qname);
@@ -171,4 +174,15 @@ final class SchemaAwareXMLStreamNormalizedNodeStreamWriter
     void startAnydata(final NodeIdentifier name) {
         tracker.startAnydataNode(name);
     }
+
+    private @NonNull TypeDefinition<?> resolveType(final @NonNull TypeDefinition<?> type) throws XMLStreamException {
+        if (type instanceof LeafrefTypeDefinition) {
+            try {
+                return tracker.resolveLeafref((LeafrefTypeDefinition) type);
+            } catch (IllegalArgumentException e) {
+                throw new XMLStreamException("Cannot resolved type " + type, e);
+            }
+        }
+        return type;
+    }
 }
index 32ad7d523337c07ef0935075d7696a8bd10130a1..d619ae6d62fbc60bcc359950e572d5b8a9511db4 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
-import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import java.util.Map.Entry;
@@ -17,10 +16,6 @@ import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 final class SchemaAwareXMLStreamWriterUtils extends XMLStreamWriterUtils implements EffectiveModelContextProvider {
     private final @NonNull EffectiveModelContext schemaContext;
@@ -29,12 +24,6 @@ final class SchemaAwareXMLStreamWriterUtils extends XMLStreamWriterUtils impleme
         this.schemaContext = requireNonNull(schemaContext);
     }
 
-    @Override
-    TypeDefinition<?> getBaseTypeForLeafRef(final SchemaNode schemaNode, final LeafrefTypeDefinition type) {
-        final TypeDefinition<?> ret = SchemaContextUtil.getBaseTypeForLeafRef(type, schemaContext, schemaNode);
-        return verifyNotNull(ret, "Unable to find base type for leafref node '%s'.", schemaNode);
-    }
-
     @Override
     String encodeInstanceIdentifier(final ValueWriter writer, final YangInstanceIdentifier value)
             throws XMLStreamException {
index 75633278121b06768de88c19194ee849b09166d0..2825d4bd7b38c4bed4b50ddbe2a37ec89315b8e2 100644 (file)
@@ -8,9 +8,6 @@
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 
 final class SchemalessXMLStreamWriterUtils extends XMLStreamWriterUtils {
     static final SchemalessXMLStreamWriterUtils INSTANCE = new SchemalessXMLStreamWriterUtils();
@@ -19,11 +16,6 @@ final class SchemalessXMLStreamWriterUtils extends XMLStreamWriterUtils {
         // Hidden on purpose
     }
 
-    @Override
-    TypeDefinition<?> getBaseTypeForLeafRef(final SchemaNode schemaNode, final LeafrefTypeDefinition type) {
-        return type;
-    }
-
     @Override
     String encodeInstanceIdentifier(final ValueWriter writer, final YangInstanceIdentifier value) {
         throw new UnsupportedOperationException("Schema context not present in " + this + ", cannot serialize "
index 9ac5106b520e602c31fbee0b3df0185160e8510e..d50bbe7b88d9316740ef150fdb2663359b0efe0a 100644 (file)
@@ -16,11 +16,9 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,26 +34,6 @@ abstract class XMLStreamWriterUtils {
      */
     private static final Set<QName> IDENTITYREF_WARNED = ConcurrentHashMap.newKeySet();
 
-    /**
-     * Encode a value into a String in the context of a XML stream writer. This method assumes the start and end of
-     * element is emitted by the caller.
-     *
-     * @param writer XML Stream writer
-     * @param schemaNode Schema node that describes the value
-     * @param type Schema type definition
-     * @param value data value
-     * @param parent module QName owning the leaf definition
-     * @return String characters to be written
-     * @throws XMLStreamException if an encoding problem occurs
-     */
-    String encodeValue(final @NonNull ValueWriter writer,final @NonNull SchemaNode schemaNode,
-            final TypeDefinition<?> type, final @NonNull Object value, final QNameModule parent)
-                    throws XMLStreamException {
-        return type instanceof LeafrefTypeDefinition
-                ? encodeValue(writer, getBaseTypeForLeafRef(schemaNode, (LeafrefTypeDefinition) type), value, parent)
-                        : encodeValue(writer, type, value, parent);
-    }
-
     /**
      * Write a value into a XML stream writer. This method assumes the start and end of element is
      * emitted by the caller.
@@ -67,7 +45,7 @@ abstract class XMLStreamWriterUtils {
      * @return String characters to be written
      * @throws XMLStreamException if an encoding problem occurs
      */
-    private String encodeValue(final @NonNull ValueWriter writer, final @NonNull TypeDefinition<?> type,
+    String encodeValue(final @NonNull ValueWriter writer, final @NonNull TypeDefinition<?> type,
             final @NonNull Object value, final QNameModule parent) throws XMLStreamException {
         if (type instanceof IdentityrefTypeDefinition) {
             return encode(writer, (IdentityrefTypeDefinition) type, value, parent);
@@ -161,9 +139,6 @@ abstract class XMLStreamWriterUtils {
         return value.toString();
     }
 
-    abstract @NonNull TypeDefinition<?> getBaseTypeForLeafRef(SchemaNode schemaNode,
-            @NonNull LeafrefTypeDefinition type);
-
     abstract String encodeInstanceIdentifier(@NonNull ValueWriter writer, YangInstanceIdentifier value)
             throws XMLStreamException;
 }
index 18a2d4c4da3303e92168ccf175196c25c37bdc70..c63009f8f9f78e5097e6c3e100e5f258ac4df0be 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
-import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
@@ -26,8 +25,6 @@ import org.opendaylight.yangtools.yang.data.impl.codec.StringStringCodec;
 import org.opendaylight.yangtools.yang.data.util.codec.AbstractCodecFactory;
 import org.opendaylight.yangtools.yang.data.util.codec.SharedCodecCache;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeAware;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
@@ -47,7 +44,6 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 
 /**
  * A thread-safe factory for instantiating {@link XmlCodec}s.
@@ -179,10 +175,4 @@ public final class XmlCodecFactory extends AbstractCodecFactory<XmlCodec<?>> {
     protected XmlCodec<?> unknownCodec(final UnknownTypeDefinition type) {
         return NullXmlCodec.INSTANCE;
     }
-
-    <T extends SchemaNode & TypeAware> XmlCodec<?> codecFor(final T currentNode) {
-        return codecFor(currentNode, type -> verifyNotNull(
-            SchemaContextUtil.getBaseTypeForLeafRef(type, getEffectiveModelContext(), currentNode),
-            "Unable to find base type for leafref node %s type %s.", currentNode, type));
-    }
 }
index 5b3198834547f4c6db0460f4fd2ea052b79d113d..397dc44323dbd48376f2b8902550da617b9226ff 100644 (file)
@@ -362,7 +362,8 @@ public final class XmlParserStream implements Closeable, Flushable {
                     codecs.getEffectiveModelContext(), qname);
                 if (optAnnotation.isPresent()) {
                     final AnnotationSchemaNode schema = optAnnotation.get();
-                    final Object value = codecs.codecFor(schema).parseValue(in.getNamespaceContext(), attrValue);
+                    final Object value = codecs.codecFor(schema, stack)
+                        .parseValue(in.getNamespaceContext(), attrValue);
                     attributes.put(schema.getQName(), value);
                     continue;
                 }
@@ -670,7 +671,7 @@ public final class XmlParserStream implements Closeable, Flushable {
 
         checkArgument(node instanceof TypedDataSchemaNode);
         checkArgument(value instanceof String);
-        return codecs.codecFor((TypedDataSchemaNode) node).parseValue(namespaceCtx, (String) value);
+        return codecs.codecFor((TypedDataSchemaNode) node, stack).parseValue(namespaceCtx, (String) value);
     }
 
     private static AbstractNodeDataWithSchema<?> newEntryNode(final AbstractNodeDataWithSchema<?> parent) {
index 47bd2ba769923804cc413301693cb1be974a9840..4f74ecb4f02fb0d245255e2aa97fc4ab577baa28 100644 (file)
@@ -25,6 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 
 final class XmlStringInstanceIdentifierCodec extends AbstractModuleStringInstanceIdentifierCodec
         implements XmlCodec<YangInstanceIdentifier> {
@@ -60,10 +61,11 @@ final class XmlStringInstanceIdentifierCodec extends AbstractModuleStringInstanc
     }
 
     @Override
-    protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final String value) {
+    protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final LeafrefResolver resolver,
+            final String value) {
         requireNonNull(schemaNode, "schemaNode cannot be null");
         checkArgument(schemaNode instanceof LeafSchemaNode, "schemaNode must be of type LeafSchemaNode");
-        final XmlCodec<?> objectXmlCodec = codecFactory.codecFor((LeafSchemaNode) schemaNode);
+        final XmlCodec<?> objectXmlCodec = codecFactory.codecFor((LeafSchemaNode) schemaNode, resolver);
         return objectXmlCodec.parseValue(getNamespaceContext(), value);
     }
 
index 4536f99ca8465cc84bc0fb0270868b21aeb96975..b0fd191b3ad7d783eeb8c61718fbf9b3a0d496a8 100644 (file)
@@ -8,17 +8,15 @@
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
 import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.net.URI;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import javax.xml.stream.XMLStreamException;
@@ -31,16 +29,16 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.Revision;
 import org.opendaylight.yangtools.yang.common.XMLNamespace;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
 public class XmlStreamUtilsTest {
@@ -49,7 +47,7 @@ public class XmlStreamUtilsTest {
         void accept(XMLStreamWriter writer) throws XMLStreamException;
     }
 
-    private static SchemaContext schemaContext;
+    private static EffectiveModelContext schemaContext;
     private static Module leafRefModule;
 
     @BeforeClass
@@ -112,17 +110,17 @@ public class XmlStreamUtilsTest {
      */
     @Test
     public void testLeafRefRelativeChaining() {
-        getTargetNodeForLeafRef("leafname3", StringTypeDefinition.class);
+        getTargetNodeForLeafRef(StringTypeDefinition.class, "cont3", "leafname3");
     }
 
     @Test
     public void testLeafRefRelative() {
-        getTargetNodeForLeafRef("pointToStringLeaf", StringTypeDefinition.class);
+        getTargetNodeForLeafRef(StringTypeDefinition.class, "pointToStringLeaf");
     }
 
     @Test
     public void testLeafRefAbsoluteWithSameTarget() {
-        getTargetNodeForLeafRef("absname", InstanceIdentifierTypeDefinition.class);
+        getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "absname");
     }
 
     /**
@@ -132,70 +130,29 @@ public class XmlStreamUtilsTest {
     @Ignore
     @Test
     public void testLeafRefWithDoublePointInPath() {
-        getTargetNodeForLeafRef("lf-with-double-point-inside", StringTypeDefinition.class);
+        getTargetNodeForLeafRef(StringTypeDefinition.class, "lf-with-double-point-inside");
     }
 
     @Test
     public void testLeafRefRelativeAndAbsoluteWithSameTarget() {
-        final TypeDefinition<?> targetNodeForAbsname = getTargetNodeForLeafRef("absname",
-            InstanceIdentifierTypeDefinition.class);
-        final TypeDefinition<?> targetNodeForRelname = getTargetNodeForLeafRef("relname",
-            InstanceIdentifierTypeDefinition.class);
-        assertEquals(targetNodeForAbsname, targetNodeForRelname);
+        assertSame(getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "absname"),
+            getTargetNodeForLeafRef(InstanceIdentifierTypeDefinition.class, "relname"));
     }
 
-    private TypeDefinition<?> getTargetNodeForLeafRef(final String nodeName, final Class<?> clas) {
-        final LeafSchemaNode schemaNode = findSchemaNodeWithLeafrefType(leafRefModule, nodeName);
-        assertNotNull(schemaNode);
-        final LeafrefTypeDefinition leafrefTypedef = findLeafrefType(schemaNode);
-        assertNotNull(leafrefTypedef);
-        final TypeDefinition<?> targetBaseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypedef, schemaContext,
-                schemaNode);
-        assertTrue("Wrong class found.", clas.isInstance(targetBaseType));
-        return targetBaseType;
-    }
-
-    private static Map<String, String> mapPrefixed(final Iterable<Map.Entry<URI, String>> prefixes) {
-        final Map<String, String> mappedPrefixes = new HashMap<>();
-        for (final Map.Entry<URI, String> prefix : prefixes) {
-            mappedPrefixes.put(prefix.getKey().toString(), prefix.getValue());
+    private static TypeDefinition<?> getTargetNodeForLeafRef(final Class<?> clas, final String... names) {
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(schemaContext);
+        stack.enterDataTree(QName.create(leafRefModule.getQNameModule(), "cont2"));
+        for (String name : names) {
+            stack.enterDataTree(QName.create(leafRefModule.getQNameModule(), name));
         }
-        return mappedPrefixes;
-    }
 
-    private static QName getAttrQName(final String namespace, final String revision, final String localName,
-            final Optional<String> prefix) {
-        if (prefix.isPresent()) {
-            final QName moduleQName = QName.create(namespace, revision, "module");
-            final QNameModule module = QNameModule.create(moduleQName.getNamespace(), moduleQName.getRevision());
-            return QName.create(module, localName);
-        }
-        return QName.create(namespace, revision, localName);
-    }
+        final EffectiveStatement<?, ?> leaf = stack.currentStatement();
+        assertThat(leaf, instanceOf(LeafSchemaNode.class));
+        final TypeDefinition<? extends TypeDefinition<?>> type = ((TypedDataSchemaNode) leaf).getType();
+        assertThat(type, instanceOf(LeafrefTypeDefinition.class));
 
-    private LeafSchemaNode findSchemaNodeWithLeafrefType(final DataNodeContainer module, final String nodeName) {
-        for (final DataSchemaNode childNode : module.getChildNodes()) {
-            if (childNode instanceof DataNodeContainer) {
-                LeafSchemaNode leafrefFromRecursion = findSchemaNodeWithLeafrefType((DataNodeContainer) childNode,
-                        nodeName);
-                if (leafrefFromRecursion != null) {
-                    return leafrefFromRecursion;
-                }
-            } else if (childNode.getQName().getLocalName().equals(nodeName) && childNode instanceof LeafSchemaNode) {
-                final TypeDefinition<?> leafSchemaNodeType = ((LeafSchemaNode) childNode).getType();
-                if (leafSchemaNodeType instanceof LeafrefTypeDefinition) {
-                    return (LeafSchemaNode) childNode;
-                }
-            }
-        }
-        return null;
-    }
-
-    private static LeafrefTypeDefinition findLeafrefType(final LeafSchemaNode schemaNode) {
-        final TypeDefinition<?> type = schemaNode.getType();
-        if (type instanceof LeafrefTypeDefinition) {
-            return (LeafrefTypeDefinition) type;
-        }
-        return null;
+        final TypeDefinition<?> resolved = stack.resolveLeafref((LeafrefTypeDefinition) type);
+        assertThat(resolved, instanceOf(clas));
+        return resolved;
     }
 }
index df98a7065a57be292c993acb478dd559b7019881..77667498f2bd6e77fae5065794f7aeb5299b4f9e 100644 (file)
@@ -15,11 +15,12 @@ module org.opendaylight.yangtools.yang.data.util {
     requires transitive org.opendaylight.yangtools.yang.model.util;
 
     requires com.google.common;
+    requires org.opendaylight.yangtools.concepts;
+    requires org.opendaylight.yangtools.yang.model.api;
     requires org.opendaylight.yangtools.yang.model.spi;
     requires org.opendaylight.yangtools.util;
     requires org.slf4j;
 
     // Annotations
     requires static org.eclipse.jdt.annotation;
-    requires org.opendaylight.yangtools.concepts;
 }
index 02a245523f1968e841abb40c219bc20312b6c8fe..f59236ba90c4f70c396c6b1f343850f3e7d48255 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithV
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.codec.InstanceIdentifierCodec;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 
 /**
  * Abstract utility class for representations which encode {@link YangInstanceIdentifier} as a
@@ -89,7 +90,8 @@ public abstract class AbstractStringInstanceIdentifierCodec extends AbstractName
      */
     protected abstract @NonNull DataSchemaContextTree getDataContextTree();
 
-    protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final String value) {
+    protected Object deserializeKeyValue(final DataSchemaNode schemaNode, final LeafrefResolver resolver,
+            final String value) {
         return value;
     }
 
index 914333a1fb3259034f18d2cc715c8b602444602e..dcc87fbcbb6ea858c27e612c857a8817647fbe83 100644 (file)
@@ -69,6 +69,7 @@ public final class ContainerSchemaNodes {
         }
 
         @Override
+        @Deprecated
         public boolean isAugmenting() {
             return false;
         }
index 3b35e13c60437487aee35fd602651d4991dedae1..19b4a5564b25c6600abfc490a779b8d7ccca813b 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -20,7 +21,6 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Mutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
@@ -46,13 +46,16 @@ import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ActionEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
+import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
 import org.slf4j.Logger;
@@ -62,7 +65,7 @@ import org.slf4j.LoggerFactory;
  * Utility class for tracking schema state underlying a {@link NormalizedNode} structure.
  */
 @Beta
-public final class NormalizedNodeStreamWriterStack implements Mutable {
+public final class NormalizedNodeStreamWriterStack implements LeafrefResolver {
     private static final Logger LOG = LoggerFactory.getLogger(NormalizedNodeStreamWriterStack.class);
 
     private final Deque<WithStatus> schemaStack = new ArrayDeque<>();
@@ -70,8 +73,8 @@ public final class NormalizedNodeStreamWriterStack implements Mutable {
     private final DataNodeContainer root;
 
     private NormalizedNodeStreamWriterStack(final EffectiveModelContext context) {
-        root = requireNonNull(context);
         dataTree = SchemaInferenceStack.of(context);
+        root = requireNonNull(context);
     }
 
     private NormalizedNodeStreamWriterStack(final SchemaInferenceStack dataTree) {
@@ -169,13 +172,9 @@ public final class NormalizedNodeStreamWriterStack implements Mutable {
         return new NormalizedNodeStreamWriterStack(stack);
     }
 
-    /**
-     * Return a copy of this tracker's state as an {@link SchemaInferenceStack}.
-     *
-     * @return A SchemaInferenceStack
-     */
-    public @NonNull SchemaInferenceStack toSchemaInferenceStack() {
-        return dataTree.copy();
+    @Override
+    public TypeDefinition<?> resolveLeafref(final LeafrefTypeDefinition type) {
+        return dataTree.resolveLeafref(type);
     }
 
     public Object getParent() {
index c1ee5c252a3b66677c85d445bf39d67a82546cb4..d9f2f516b045cdc147ce9f1cfbba8be826348506 100644 (file)
@@ -14,12 +14,16 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 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;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 /**
  * Iterator which lazily parses {@link PathArgument} from string representation.
@@ -60,6 +64,7 @@ final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathAr
 
     private final List<PathArgument> product = new ArrayList<>();
     private final AbstractStringInstanceIdentifierCodec codec;
+    private final SchemaInferenceStack stack;
     private final String data;
 
     private DataSchemaContextNode<?> current;
@@ -69,8 +74,11 @@ final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathAr
     XpathStringParsingPathArgumentBuilder(final AbstractStringInstanceIdentifierCodec codec, final String data) {
         this.codec = requireNonNull(codec);
         this.data = requireNonNull(data);
-        this.current = codec.getDataContextTree().getRoot();
         this.offset = 0;
+
+        final DataSchemaContextTree tree = codec.getDataContextTree();
+        this.stack = SchemaInferenceStack.of(tree.getEffectiveModelContext());
+        this.current = tree.getRoot();
     }
 
     @Override
@@ -98,11 +106,12 @@ final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathAr
 
     private DataSchemaContextNode<?> nextContextNode(final QName name) {
         current = current.getChild(name);
-        checkValid(current != null, "%s is not correct schema node identifier.",name);
+        checkValid(current != null, "%s is not correct schema node identifier.", name);
         while (current.isMixin()) {
             product.add(current.getIdentifier());
             current = current.getChild(name);
         }
+        stack.enterDataTree(name);
         return current;
     }
 
@@ -122,10 +131,10 @@ final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathAr
      * @return PathArgument representing node selection with predictes
      */
     private PathArgument computeIdentifierWithPredicate(final QName name) {
-        DataSchemaContextNode<?> currentNode = nextContextNode(name);
+        final DataSchemaContextNode<?> currentNode = nextContextNode(name);
         checkValid(currentNode.isKeyedEntry(), "Entry %s does not allow specifying predicates.", name);
 
-        ImmutableMap.Builder<QName,Object> keyValues = ImmutableMap.builder();
+        ImmutableMap.Builder<QName, Object> keyValues = ImmutableMap.builder();
         while (!allCharactersConsumed() && PRECONDITION_START == currentChar()) {
             skipCurrentChar();
             skipWhitespaces();
@@ -150,12 +159,18 @@ final class XpathStringParsingPathArgumentBuilder implements Builder<List<PathAr
             }
             final DataSchemaContextNode<?> keyNode = currentNode.getChild(key);
             checkValid(keyNode != null, "%s is not correct schema node identifier.", key);
-            final Object value = codec.deserializeKeyValue(keyNode.getDataSchemaNode(), keyValue);
+            final Object value = codec.deserializeKeyValue(keyNode.getDataSchemaNode(),
+                type -> resolveLeafref(key, type), keyValue);
             keyValues.put(key, value);
         }
         return NodeIdentifierWithPredicates.of(name, keyValues.build());
     }
 
+    private @NonNull TypeDefinition<?> resolveLeafref(final QName qname, final LeafrefTypeDefinition type) {
+        final SchemaInferenceStack tmp = stack.copy();
+        tmp.enterDataTree(qname);
+        return tmp.resolveLeafref(type);
+    }
 
     private PathArgument computeIdentifier(final QName name) {
         DataSchemaContextNode<?> currentNode = nextContextNode(name);
index d5103ae6a3e83d86d771eec95b39b5a7c2c8f752..64e3bdc365c27205de4a9bf564b1465db2a7429f 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.yangtools.yang.data.util.codec;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.annotations.Beta;
 import java.util.ArrayList;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
@@ -40,6 +39,7 @@ import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnknownTypeDefinition;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveModelContextProvider;
+import org.opendaylight.yangtools.yang.model.util.LeafrefResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,21 +53,6 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class AbstractCodecFactory<T extends TypeAwareCodec<?, ?, ?>>
         extends AbstractEffectiveModelContextProvider {
-    /**
-     * Helper interface aiding resolution of leafref chains.
-     */
-    @Beta
-    @FunctionalInterface
-    public interface LeafrefResolver {
-        /**
-         * Resolve specified {@link LeafrefTypeDefinition}.
-         *
-         * @param type leafref definition
-         * @return Resolved type
-         */
-        @NonNull TypeDefinition<?> resolveLeafref(@NonNull LeafrefTypeDefinition type);
-    }
-
     private static final Logger LOG = LoggerFactory.getLogger(AbstractCodecFactory.class);
 
     private final @NonNull CodecCache<T> cache;
index bbedc0eeaf837a3db2cd1bbaca371726c5196199..a1a2ec0112ac22ecdb9a9e5d3efbb194f99b19d8 100644 (file)
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-model-spi</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-xpath-api</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>logback-classic</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-xpath-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
index 1767dcc1f0114b9985c148e056b58d702a0d5006..aebab935823c52c817c736e2825c2aefd927adee 100644 (file)
@@ -10,6 +10,7 @@ module org.opendaylight.yangtools.yang.model.util {
 
     requires transitive org.opendaylight.yangtools.yang.model.api;
     requires transitive org.opendaylight.yangtools.yang.repo.api;
+    requires transitive org.opendaylight.yangtools.yang.xpath.api;
     requires com.google.common;
     requires org.opendaylight.yangtools.yang.common;
     requires org.opendaylight.yangtools.yang.model.spi;
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/LeafrefResolver.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/LeafrefResolver.java
new file mode 100644 (file)
index 0000000..8fc4be9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.annotations.Beta;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+
+/**
+ * Helper interface aiding resolution of leafref chains.
+ */
+@Beta
+@FunctionalInterface
+public interface LeafrefResolver {
+    /**
+     * Resolve specified {@link LeafrefTypeDefinition} until a non-{@code leafref} type is found.
+     *
+     * @param type leafref definition
+     * @return Resolved type
+     * @throws NullPointerException if {@code type} is null
+     * @throws IllegalArgumentException if the type definition cannot be resolved
+     */
+    @NonNull TypeDefinition<?> resolveLeafref(@NonNull LeafrefTypeDefinition type);
+}
\ No newline at end of file
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PathExpressionImpl.java
deleted file mode 100644 (file)
index 5fe8519..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o.  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 static java.util.Objects.requireNonNull;
-
-import com.google.common.base.MoreObjects.ToStringHelper;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.model.spi.AbstractPathExpression;
-
-/**
- * A simple XPathExpression implementation.
- *
- * @deprecated Users are advised to supply their own implementation of PathExpression.
- */
-@Deprecated(forRemoval = true)
-@NonNullByDefault
-public final class PathExpressionImpl extends AbstractPathExpression {
-    private final @Nullable Steps steps;
-    private final boolean absolute;
-
-    @SuppressFBWarnings(value = "NP_STORE_INTO_NONNULL_FIELD", justification = "Non-grok on SpotBugs part")
-    public PathExpressionImpl(final String xpath, final boolean absolute) {
-        super(xpath);
-        this.absolute = absolute;
-        this.steps = null;
-    }
-
-    public PathExpressionImpl(final String xpath, final Steps steps) {
-        super(xpath);
-        this.steps = requireNonNull(steps);
-        this.absolute = steps instanceof LocationPathSteps
-                && ((LocationPathSteps) steps).getLocationPath().isAbsolute();
-    }
-
-    @Override
-    public boolean isAbsolute() {
-        return absolute;
-    }
-
-    @Override
-    public Steps getSteps() {
-        final Steps loc = steps;
-        if (loc == null) {
-            throw new UnsupportedOperationException("Steps have not been provided");
-        }
-        return loc;
-    }
-
-    @Override
-    protected ToStringHelper addToStringAttributes(final ToStringHelper helper) {
-        return super.addToStringAttributes(helper.add("absolute", absolute).add("steps", steps));
-    }
-}
index 742dab9e2fa753023ce767ecfcc62587328add95..5f5bb05dd3551223dae6ca6695577aff99a767cb 100644 (file)
@@ -8,66 +8,36 @@
 package org.opendaylight.yangtools.yang.model.util;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.AbstractQName;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.api.ModuleLike;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
-import org.opendaylight.yangtools.yang.model.api.PathExpression;
-import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
-import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
-import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
 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.api.Submodule;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
-import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep;
-import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
-import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
-import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -78,9 +48,7 @@ import org.slf4j.LoggerFactory;
  */
 public final class SchemaContextUtil {
     private static final Logger LOG = LoggerFactory.getLogger(SchemaContextUtil.class);
-    private static final Splitter COLON_SPLITTER = Splitter.on(':');
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
-    private static final Pattern GROUPS_PATTERN = Pattern.compile("\\[(.*?)\\]");
+
 
     private SchemaContextUtil() {
         // Hidden on purpose
@@ -111,171 +79,6 @@ public final class SchemaContextUtil {
         return findNodeInSchemaContext(context, prefixedPath);
     }
 
-    /**
-     * Attempt to find a DataSchemaNode based on its path from root, similar to
-     * {@link #findDataSchemaNode(SchemaContext, Module, PathExpression)} without requiring an expression.
-     *
-     * @param context Schema Context
-     * @param path Path to search for
-     * @return SchemaNode from the end of the Schema Path or {@code null} if the Node is not present.
-     * @throws NullPointerException if a any argument is null or if the path contains a null element
-     */
-    @Beta
-    public static SchemaNode findDataSchemaNode(final SchemaContext context, final List<QName> path) {
-        return findTargetNode(context, null, YangLocationPath.absolute(
-            path.stream().map(YangXPathAxis.CHILD::asStep).collect(Collectors.toList())));
-    }
-
-    /**
-     * Attempt to find a DataSchemaNode based on its path from root, similar to
-     * {@link #findDataSchemaNode(SchemaContext, Module, PathExpression)} without requiring an expression.
-     *
-     * @param context Schema Context
-     * @param path Path to search for
-     * @return SchemaNode from the end of the Schema Path or {@code null} if the Node is not present.
-     * @throws NullPointerException if a any argument is null or if the path contains a null element
-     */
-    @Beta
-    public static SchemaNode findDataSchemaNode(final SchemaContext context, final QName... path) {
-        return findDataSchemaNode(context, Arrays.asList(path));
-    }
-
-    /**
-     * Method attempts to find DataSchemaNode inside of provided Schema Context
-     * and Yang Module accordingly to Non-conditional Revision Aware XPath. The
-     * specified Module MUST be present in Schema Context otherwise the
-     * operation would fail and return <code>null</code>. <br>
-     * The Revision Aware XPath MUST be specified WITHOUT the conditional
-     * statement (i.e. without [cond]) in path, because in this state the Schema
-     * Context is completely unaware of data state and will be not able to
-     * properly resolve XPath. If the XPath contains condition the method will
-     * return IllegalArgumentException. <br>
-     * If the Revision Aware XPath is correct and desired Data Schema Node is
-     * present in Yang module or in depending module in Schema Context the
-     * method will return specified Data Schema Node, otherwise the operation
-     * will fail and method will return <code>null</code>.
-     *
-     * @param context
-     *            Schema Context
-     * @param module
-     *            Yang Module
-     * @param nonCondXPath
-     *            Non Conditional Revision Aware XPath
-     * @return Returns Data Schema Node for specified Schema Context for given
-     *         Non-conditional Revision Aware XPath, or <code>null</code> if the
-     *         DataSchemaNode is not present in Schema Context.
-     * @throws NullPointerException if any of the arguments is null
-     * @deprecated Use {@link #findDataTreeSchemaNode(SchemaContext, QNameModule, YangLocationPath)} or
-     *             {@link #findDataTreeSchemaNode(SchemaContext, QNameModule, PathExpression)} instead.
-     */
-    // FIXME: This entire method is ill-defined, as the resolution process depends on  where the XPath is defined --
-    //        notably RPCs, actions and notifications modify the data tree temporarily. See sections 6.4.1 and 9.9.2
-    //        of RFC7950.
-    //
-    //        Most notably we need to understand whether the XPath is being resolved in the data tree, or as part of
-    //        a notification/action/RPC, as then the SchemaContext grows tentative nodes ... which could be addressed
-    //        via a derived SchemaContext (i.e. this class would have to have a
-    //
-    //            SchemaContext notificationSchemaContext(SchemaContext delegate, NotificationDefinition notif)
-    //
-    //        which would then be passed in to a method similar to this one. In static contexts, like MD-SAL codegen,
-    //        that feels like an overkill.
-    @Deprecated
-    public static SchemaNode findDataSchemaNode(final SchemaContext context, final Module module,
-            final PathExpression nonCondXPath) {
-        requireNonNull(context, "context");
-        requireNonNull(module, "module");
-
-        final String strXPath = nonCondXPath.getOriginalString();
-        checkArgument(strXPath.indexOf('[') == -1, "Revision Aware XPath may not contain a condition");
-        if (nonCondXPath.isAbsolute()) {
-            return findTargetNode(context, xpathToQNamePath(context, module, strXPath));
-        }
-        return null;
-    }
-
-    @Beta
-    public static SchemaNode findDataTreeSchemaNode(final SchemaContext ctx, final QNameModule localModule,
-            final YangLocationPath absPath) {
-        checkArgument(absPath.isAbsolute(), "Unsupported relative path %s", absPath);
-        return findTargetNode(ctx, localModule, absPath);
-    }
-
-    @Beta
-    public static SchemaNode findDataTreeSchemaNode(final SchemaContext ctx, final QNameModule localModule,
-            final PathExpression absPath) {
-        final Steps pathSteps = absPath.getSteps();
-        if (pathSteps instanceof LocationPathSteps) {
-            return findDataTreeSchemaNode(ctx, localModule, ((LocationPathSteps) pathSteps).getLocationPath());
-        }
-
-        // We would need a reference schema node and no, we do not want to use SchemaContext in its SchemaNode capacity
-        checkArgument(!(pathSteps instanceof DerefSteps), "No reference node for steps %s", pathSteps);
-
-        // We are missing proper API alignment, if this ever triggers
-        throw new IllegalStateException("Unsupported path " + pathSteps);
-    }
-
-    /**
-     * Method attempts to find DataSchemaNode inside of provided Schema Context
-     * and Yang Module accordingly to Non-conditional relative Revision Aware
-     * XPath. The specified Module MUST be present in Schema Context otherwise
-     * the operation would fail and return <code>null</code>. <br>
-     * The relative Revision Aware XPath MUST be specified WITHOUT the
-     * conditional statement (i.e. without [cond]) in path, because in this
-     * state the Schema Context is completely unaware of data state and will be
-     * not able to properly resolve XPath. If the XPath contains condition the
-     * method will return IllegalArgumentException. <br>
-     * The Actual Schema Node MUST be specified correctly because from this
-     * Schema Node will search starts. If the Actual Schema Node is not correct
-     * the operation will simply fail, because it will be unable to find desired
-     * DataSchemaNode. <br>
-     * If the Revision Aware XPath doesn't have flag
-     * <code>isAbsolute == false</code> the method will throw
-     * IllegalArgumentException. <br>
-     * If the relative Revision Aware XPath is correct and desired Data Schema
-     * Node is present in Yang module or in depending module in Schema Context
-     * the method will return specified Data Schema Node, otherwise the
-     * operation will fail and method will return <code>null</code>.
-     *
-     * @param context
-     *            Schema Context
-     * @param module
-     *            Yang Module
-     * @param actualSchemaNode
-     *            Actual Schema Node
-     * @param relativeXPath
-     *            Relative Non Conditional Revision Aware XPath
-     * @return DataSchemaNode if is present in specified Schema Context for
-     *         given relative Revision Aware XPath, otherwise will return
-     *         <code>null</code>.
-     * @throws NullPointerException if any argument is null
-     */
-    // FIXME: This entire method is ill-defined, as the resolution process depends on  where the XPath is defined --
-    //        notably RPCs, actions and notifications modify the data tree temporarily. See sections 6.4.1 and 9.9.2
-    //        of RFC7950.
-    //
-    //        Most notably we need to understand whether the XPath is being resolved in the data tree, or as part of
-    //        a notification/action/RPC, as then the SchemaContext grows tentative nodes ... which could be addressed
-    //        via a derived SchemaContext (i.e. this class would have to have a
-    //
-    //            SchemaContext notificationSchemaContext(SchemaContext delegate, NotificationDefinition notif)
-    //
-    //        which would then be passed in to a method similar to this one. In static contexts, like MD-SAL codegen,
-    //        that feels like an overkill.
-    // FIXME: YANGTOOLS-1052: this is a static analysis util, move it to a dedicated class
-    public static SchemaNode findDataSchemaNodeForRelativeXPath(final SchemaContext context, final Module module,
-            final SchemaNode actualSchemaNode, final PathExpression relativeXPath) {
-        checkState(!relativeXPath.isAbsolute(), "Revision Aware XPath MUST be relative i.e. MUST contains ../, "
-                + "for non relative Revision Aware XPath use findDataSchemaNode method");
-        return resolveRelativeXPath(context, module, removePredicatesFromXpath(relativeXPath.getOriginalString()),
-                actualSchemaNode);
-    }
-
-    private static String removePredicatesFromXpath(final String xpath) {
-        return GROUPS_PATTERN.matcher(xpath).replaceAll("");
-    }
-
     /**
      * Returns parent Yang Module for specified Schema Context in which Schema
      * Node is declared. If the Schema Node is not present in Schema Context the
@@ -554,423 +357,4 @@ public final class SchemaContextUtil {
         return null;
     }
 
-    /**
-     * Transforms string representation of XPath to Queue of QNames. The XPath
-     * is split by "/" and for each part of XPath is assigned correct module in
-     * Schema Path. <br>
-     * If Schema Context, Parent Module or XPath string contains
-     * <code>null</code> values, the method will throws IllegalArgumentException
-     *
-     * @param context
-     *            Schema Context
-     * @param parentModule
-     *            Parent Module
-     * @param xpath
-     *            XPath String
-     * @return return a list of QName
-     */
-    private static List<QName> xpathToQNamePath(final SchemaContext context, final Module parentModule,
-            final String xpath) {
-        final List<QName> path = new ArrayList<>();
-        for (final String pathComponent : SLASH_SPLITTER.split(xpath)) {
-            path.add(stringPathPartToQName(context, parentModule, pathComponent));
-        }
-        return path;
-    }
-
-    /**
-     * Transforms part of Prefixed Path as java String to QName. <br>
-     * If the string contains module prefix separated by ":" (i.e.
-     * mod:container) this module is provided from from Parent Module list of
-     * imports. If the Prefixed module is present in Schema Context the QName
-     * can be constructed. <br>
-     * If the Prefixed Path Part does not contains prefix the Parent's Module
-     * namespace is taken for construction of QName. <br>
-     *
-     * @param context Schema Context
-     * @param parentModule Parent Module
-     * @param prefixedPathPart Prefixed Path Part string
-     * @return QName from prefixed Path Part String.
-     * @throws NullPointerException if any arguments are null
-     */
-    private static QName stringPathPartToQName(final SchemaContext context, final Module parentModule,
-            final String prefixedPathPart) {
-        requireNonNull(context, "context");
-
-        if (prefixedPathPart.indexOf(':') != -1) {
-            final Iterator<String> prefixedName = COLON_SPLITTER.split(prefixedPathPart).iterator();
-            final String modulePrefix = prefixedName.next();
-
-            final Module module = resolveModuleForPrefix(context, parentModule, modulePrefix);
-            checkArgument(module != null, "Failed to resolve xpath: no module found for prefix %s in module %s",
-                    modulePrefix, parentModule.getName());
-
-            return QName.create(module.getQNameModule(), prefixedName.next());
-        }
-
-        return QName.create(parentModule.getQNameModule(), prefixedPathPart);
-    }
-
-    /**
-     * Method will attempt to resolve and provide Module reference for specified module prefix. Each Yang module could
-     * contains multiple imports which MUST be associated with corresponding module prefix. The method simply looks into
-     * module imports and returns the module that is bounded with specified prefix. If the prefix is not present
-     * in module or the prefixed module is not present in specified Schema Context, the method will return {@code null}.
-     * <br>
-     * If String prefix is the same as prefix of the specified Module the reference to this module is returned.<br>
-     *
-     * @param context Schema Context
-     * @param module Yang Module
-     * @param prefix Module Prefix
-     * @return Module for given prefix in specified Schema Context if is present, otherwise returns <code>null</code>
-     * @throws NullPointerException if any arguments are null
-     */
-    private static Module resolveModuleForPrefix(final SchemaContext context, final Module module,
-            final String prefix) {
-        requireNonNull(context, "context");
-
-        if (prefix.equals(module.getPrefix())) {
-            return module;
-        }
-
-        for (final ModuleImport mi : module.getImports()) {
-            if (prefix.equals(mi.getPrefix())) {
-                return context.findModule(mi.getModuleName(), mi.getRevision()).orElse(null);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Resolve a relative XPath into a set of QNames.
-     *
-     * @param context
-     *            Schema Context
-     * @param module
-     *            Yang Module
-     * @param pathStr
-     *            xPath of leafref
-     * @param actualSchemaNode
-     *            actual schema node
-     * @return target schema node
-     * @throws IllegalArgumentException if any arguments are null
-     */
-    private static @Nullable SchemaNode resolveRelativeXPath(final SchemaContext context, final Module module,
-            final String pathStr, final SchemaNode actualSchemaNode) {
-        checkState(actualSchemaNode.getPath() != null, "Schema Path reference for Leafref cannot be NULL");
-
-        return pathStr.startsWith("deref(") ? resolveDerefPath(context, module, actualSchemaNode, pathStr)
-                : findTargetNode(context, resolveRelativePath(context, module, actualSchemaNode,
-                    doSplitXPath(pathStr)));
-    }
-
-    private static Iterable<QName> resolveRelativePath(final SchemaContext context, final Module module,
-            final SchemaNode actualSchemaNode, final List<String> steps) {
-        // Find out how many "parent" components there are and trim them
-        final int colCount = normalizeXPath(steps);
-        final List<String> xpaths = colCount == 0 ? steps : steps.subList(colCount, steps.size());
-
-        final List<QName> walkablePath = createWalkablePath(actualSchemaNode.getPath().getPathFromRoot(),
-                context, colCount);
-
-        if (walkablePath.size() - colCount >= 0) {
-            return Iterables.concat(Iterables.limit(walkablePath, walkablePath.size() - colCount),
-                    Iterables.transform(xpaths, input -> stringPathPartToQName(context, module, input)));
-        }
-        return Iterables.concat(walkablePath,
-                Iterables.transform(xpaths, input -> stringPathPartToQName(context, module, input)));
-    }
-
-    /**
-     * Return List of qNames that are walkable using xPath. When getting a path from schema node it will return path
-     * with parents like CaseSchemaNode and ChoiceSchemaNode as well if they are parents of the node. We need to get
-     * rid of these in order to find the node that xPath is pointing to. Also we can not remove any node beyond the
-     * amount of "../" because we will not be able to find the correct schema node from schema context
-     *
-     * @param schemaNodePath list of qNames as a path to the leaf of type leafref
-     * @param context        create schema context
-     * @param colCount       amount of "../" in the xPath expression
-     * @return list of QNames as a path where we should be able to find referenced node
-     */
-    private static List<QName> createWalkablePath(final Iterable<QName> schemaNodePath, final SchemaContext context,
-            final int colCount) {
-        final List<Integer> indexToRemove = new ArrayList<>();
-        List<QName> schemaNodePathRet = Lists.newArrayList(schemaNodePath);
-        for (int j = 0, i = schemaNodePathRet.size() - 1; i >= 0 && j != colCount; i--, j++) {
-            final SchemaNode nodeIn = findTargetNode(context, schemaNodePathRet);
-            if (nodeIn instanceof CaseSchemaNode || nodeIn instanceof ChoiceSchemaNode) {
-                indexToRemove.add(i);
-                j--;
-            }
-            schemaNodePathRet.remove(i);
-        }
-        schemaNodePathRet = Lists.newArrayList(schemaNodePath);
-        for (int i : indexToRemove) {
-            schemaNodePathRet.remove(i);
-        }
-        return schemaNodePathRet;
-    }
-
-    private static SchemaNode resolveDerefPath(final SchemaContext context, final Module module,
-            final SchemaNode actualSchemaNode, final String xpath) {
-        final int paren = xpath.indexOf(')', 6);
-        checkArgument(paren != -1, "Cannot find matching parentheses in %s", xpath);
-
-        final String derefArg = xpath.substring(6, paren).strip();
-        // Look up the node which we need to reference
-        final SchemaNode derefTarget = findTargetNode(context, resolveRelativePath(context, module, actualSchemaNode,
-            doSplitXPath(derefArg)));
-        checkArgument(derefTarget != null, "Cannot find deref(%s) target node %s in context of %s", derefArg,
-                actualSchemaNode);
-        checkArgument(derefTarget instanceof TypedDataSchemaNode, "deref(%s) resolved to non-typed %s", derefArg,
-            derefTarget);
-
-        // We have a deref() target, decide what to do about it
-        final TypeDefinition<?> targetType = ((TypedDataSchemaNode) derefTarget).getType();
-        if (targetType instanceof InstanceIdentifierTypeDefinition) {
-            // Static inference breaks down, we cannot determine where this points to
-            // FIXME: dedicated exception, users can recover from it, derive from IAE
-            throw new UnsupportedOperationException("Cannot infer instance-identifier reference " + targetType);
-        }
-
-        // deref() is define only for instance-identifier and leafref types, handle the latter
-        checkArgument(targetType instanceof LeafrefTypeDefinition, "Illegal target type %s", targetType);
-
-        final PathExpression targetPath = ((LeafrefTypeDefinition) targetType).getPathStatement();
-        LOG.debug("Derefencing path {}", targetPath);
-
-        final SchemaNode deref = targetPath.isAbsolute()
-                ? findTargetNode(context, actualSchemaNode.getQName().getModule(),
-                    ((LocationPathSteps) targetPath.getSteps()).getLocationPath())
-                        : findDataSchemaNodeForRelativeXPath(context, module, actualSchemaNode, targetPath);
-        if (deref == null) {
-            LOG.debug("Path {} could not be derefenced", targetPath);
-            return null;
-        }
-
-        checkArgument(deref instanceof LeafSchemaNode, "Unexpected %s reference in %s", deref, targetPath);
-
-        final List<String> qnames = doSplitXPath(xpath.substring(paren + 1).stripLeading());
-        return findTargetNode(context, resolveRelativePath(context, module, deref, qnames));
-    }
-
-    private static @Nullable SchemaNode findTargetNode(final SchemaContext context, final QNameModule localNamespace,
-            final YangLocationPath path) {
-        final Deque<QName> ret = new ArrayDeque<>();
-        for (Step step : path.getSteps()) {
-            if (step instanceof AxisStep) {
-                // We only support parent axis steps
-                final YangXPathAxis axis = ((AxisStep) step).getAxis();
-                checkState(axis == YangXPathAxis.PARENT, "Unexpected axis %s", axis);
-                ret.removeLast();
-                continue;
-            }
-
-            // This has to be a QNameStep
-            checkState(step instanceof QNameStep, "Unhandled step %s in %s", step, path);
-            ret.addLast(resolve(((QNameStep) step).getQName(), localNamespace));
-        }
-
-        return findTargetNode(context, ret);
-    }
-
-    private static @Nullable SchemaNode findTargetNode(final SchemaContext context, final Iterable<QName> qnamePath) {
-        // We do not have enough information about resolution context, hence cannot account for actions, RPCs
-        // and notifications. We therefore attempt to make a best estimate, but this can still fail.
-        final Optional<DataSchemaNode> pureData = context.findDataTreeChild(qnamePath);
-        return pureData.isPresent() ? pureData.get() : findNodeInSchemaContext(context, qnamePath);
-    }
-
-    private static QName resolve(final AbstractQName toResolve, final QNameModule localNamespace) {
-        if (toResolve instanceof QName) {
-            return (QName) toResolve;
-        } else if (toResolve instanceof UnqualifiedQName) {
-            return ((UnqualifiedQName) toResolve).bindTo(localNamespace);
-        } else {
-            throw new IllegalStateException("Unhandled step " + toResolve);
-        }
-    }
-
-    @VisibleForTesting
-    static int normalizeXPath(final List<String> xpath) {
-        LOG.trace("Normalize {}", xpath);
-
-        // We need to make multiple passes here, as the leading XPaths as we can have "../abc/../../def", which really
-        // is "../../def"
-        while (true) {
-            // Next up: count leading ".." components
-            int leadingParents = 0;
-            while (true) {
-                if (leadingParents == xpath.size()) {
-                    return leadingParents;
-                }
-                if (!"..".equals(xpath.get(leadingParents))) {
-                    break;
-                }
-
-                ++leadingParents;
-            }
-
-            // Now let's see if there there is a '..' in the rest
-            final int dots = findDots(xpath, leadingParents + 1);
-            if (dots == -1) {
-                return leadingParents;
-            }
-
-            xpath.remove(dots - 1);
-            xpath.remove(dots - 1);
-            LOG.trace("Next iteration {}", xpath);
-        }
-    }
-
-    private static int findDots(final List<String> xpath, final int startIndex) {
-        for (int i = startIndex; i < xpath.size(); ++i) {
-            if ("..".equals(xpath.get(i))) {
-                return i;
-            }
-        }
-
-        return -1;
-    }
-
-    private static List<String> doSplitXPath(final String xpath) {
-        final List<String> ret = new ArrayList<>();
-        for (String str : SLASH_SPLITTER.split(xpath)) {
-            ret.add(str);
-        }
-        return ret;
-    }
-
-    /**
-     * Extracts the base type of node on which schema node points to. If target node is again of type
-     * LeafrefTypeDefinition, methods will be call recursively until it reach concrete type definition.
-     *
-     * @param typeDefinition
-     *            type of node which will be extracted
-     * @param schemaContext
-     *            Schema Context
-     * @param schema
-     *            Schema Node
-     * @return recursively found type definition this leafref is pointing to or null if the xpath is incorrect (null
-     *         is there to preserve backwards compatibility)
-     */
-    public static TypeDefinition<?> getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition,
-            final SchemaContext schemaContext, final SchemaNode schema) {
-        final PathExpression pathStatement = typeDefinition.getPathStatement();
-        final String pathStr = stripConditionsFromXPathString(pathStatement);
-
-        final DataSchemaNode dataSchemaNode;
-        if (pathStatement.isAbsolute()) {
-            SchemaNode baseSchema = schema;
-            while (baseSchema instanceof DerivableSchemaNode) {
-                final Optional<? extends SchemaNode> basePotential = ((DerivableSchemaNode) baseSchema).getOriginal();
-                if (basePotential.isPresent()) {
-                    baseSchema = basePotential.get();
-                } else {
-                    break;
-                }
-            }
-
-            final Module parentModule = findParentModuleOfReferencingType(schemaContext, baseSchema);
-            dataSchemaNode = (DataSchemaNode) findTargetNode(schemaContext,
-                xpathToQNamePath(schemaContext, parentModule, pathStr));
-        } else {
-            Module parentModule = findParentModule(schemaContext, schema);
-            dataSchemaNode = (DataSchemaNode) resolveRelativeXPath(schemaContext, parentModule, pathStr, schema);
-        }
-
-        // FIXME this is just to preserve backwards compatibility since yangtools do not mind wrong leafref xpaths
-        // and current expected behaviour for such cases is to just use pure string
-        // This should throw an exception about incorrect XPath in leafref
-        if (dataSchemaNode == null) {
-            return null;
-        }
-
-        final TypeDefinition<?> targetTypeDefinition = typeDefinition(dataSchemaNode);
-
-        if (targetTypeDefinition instanceof LeafrefTypeDefinition) {
-            return getBaseTypeForLeafRef((LeafrefTypeDefinition) targetTypeDefinition, schemaContext, dataSchemaNode);
-        }
-
-        return targetTypeDefinition;
-    }
-
-    /**
-     * Returns base type for {@code typeDefinition} which belongs to module specified via {@code qname}. This handle
-     * the case when leafref type isn't specified as type substatement of leaf or leaf-list but is defined in other
-     * module as typedef which is then imported to referenced module.
-     *
-     * <p>
-     * Because {@code typeDefinition} is definied via typedef statement, only absolute path is meaningful.
-     */
-    public static TypeDefinition<?> getBaseTypeForLeafRef(final LeafrefTypeDefinition typeDefinition,
-            final SchemaContext schemaContext, final QName qname) {
-        final PathExpression pathStatement = typeDefinition.getPathStatement();
-        if (!pathStatement.isAbsolute()) {
-            return null;
-        }
-
-        final Optional<Module> parentModule = schemaContext.findModule(qname.getModule());
-        checkArgument(parentModule.isPresent(), "Failed to find parent module for %s", qname);
-
-        final DataSchemaNode dataSchemaNode = (DataSchemaNode) findTargetNode(schemaContext,
-            xpathToQNamePath(schemaContext, parentModule.get(), stripConditionsFromXPathString(pathStatement)));
-        final TypeDefinition<?> targetTypeDefinition = typeDefinition(dataSchemaNode);
-        if (targetTypeDefinition instanceof LeafrefTypeDefinition) {
-            return getBaseTypeForLeafRef((LeafrefTypeDefinition) targetTypeDefinition, schemaContext, dataSchemaNode);
-        }
-
-        return targetTypeDefinition;
-    }
-
-    private static Module findParentModuleOfReferencingType(final SchemaContext schemaContext,
-            final SchemaNode schemaNode) {
-        checkArgument(schemaContext != null, "Schema Context reference cannot be NULL!");
-        checkArgument(schemaNode instanceof TypedDataSchemaNode, "Unsupported node %s", schemaNode);
-
-        TypeDefinition<?> nodeType = ((TypedDataSchemaNode) schemaNode).getType();
-        if (nodeType.getBaseType() != null) {
-            while (nodeType.getBaseType() != null) {
-                nodeType = nodeType.getBaseType();
-            }
-
-            return schemaContext.findModule(nodeType.getQName().getModule()).orElse(null);
-        }
-
-        return findParentModule(schemaContext, schemaNode);
-    }
-
-    private static final Pattern STRIP_PATTERN = Pattern.compile("\\[[^\\[\\]]*\\]");
-
-    /**
-     * Removes conditions from xPath pointed to target node.
-     *
-     * @param pathStatement
-     *            xPath to target node
-     * @return string representation of xPath without conditions
-     */
-    @VisibleForTesting
-    static String stripConditionsFromXPathString(final PathExpression pathStatement) {
-        return STRIP_PATTERN.matcher(pathStatement.getOriginalString()).replaceAll("");
-    }
-
-    /**
-     * Gets the base type of DataSchemaNode value.
-     *
-     * @param node
-     *            a node representing DataSchemaNode
-     * @return concrete type definition of node value
-     */
-    private static TypeDefinition<?> typeDefinition(final DataSchemaNode node) {
-        checkArgument(node instanceof TypedDataSchemaNode, "Unhandled parameter type %s", node);
-
-        TypeDefinition<?> current = ((TypedDataSchemaNode) node).getType();
-        // TODO: don't we have a utility for this?
-        TypeDefinition<?> base = current.getBaseType();
-        while (base != null) {
-            current = base;
-            base = current.getBaseType();
-        }
-        return current;
-    }
 }
index caef0311acd7c4723bf9f56fb72d58941306f3c9..40f0203c63b832e65b905fae6b94327acecf80ad 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.model.util;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
@@ -26,12 +27,23 @@ import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.common.AbstractQName;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
 import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.PathExpression;
+import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
+import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
+import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.SchemaTreeInference;
+import org.opendaylight.yangtools.yang.model.api.TypeAware;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.CaseEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
@@ -42,8 +54,15 @@ import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference;
 import org.opendaylight.yangtools.yang.model.spi.DefaultSchemaTreeInference;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.AxisStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Step;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
 
 /**
  * A state tracking utility for walking {@link EffectiveModelContext}'s contents along schema/grouping namespaces. This
@@ -57,7 +76,7 @@ import org.opendaylight.yangtools.yang.model.spi.DefaultSchemaTreeInference;
  * This class is designed for single-threaded uses and does not make any guarantees around concurrent access.
  */
 @Beta
-public final class SchemaInferenceStack implements Mutable, EffectiveModelContextProvider {
+public final class SchemaInferenceStack implements Mutable, EffectiveModelContextProvider, LeafrefResolver {
     /**
      * Semantic binding of {@link EffectiveStatementInference} produced by {@link SchemaInferenceStack}. Sequence of
      * {@link #statementPath()} is implementation-specific.
@@ -420,6 +439,121 @@ public final class SchemaInferenceStack implements Mutable, EffectiveModelContex
         return (DataTreeEffectiveStatement<?>) child;
     }
 
+
+    @Override
+    public TypeDefinition<?> resolveLeafref(final LeafrefTypeDefinition type) {
+        final SchemaInferenceStack tmp = copy();
+
+        LeafrefTypeDefinition current = type;
+        while (true) {
+            final EffectiveStatement<?, ?> resolved = tmp.resolvePathExpression(current.getPathStatement());
+            checkState(resolved instanceof TypeAware, "Unexpected result %s resultion of %s", resolved, type);
+            final TypeDefinition<?> result = ((TypedDataSchemaNode) resolved).getType();
+            if (result instanceof LeafrefTypeDefinition) {
+                checkArgument(result != type, "Resolution of %s loops back onto itself via %s", type, current);
+                current = (LeafrefTypeDefinition) result;
+            } else {
+                return result;
+            }
+        }
+    }
+
+    /**
+     * Resolve a {@link PathExpression}.
+     *
+     * <p>
+     * Note if this method throws, this stack may be in an undefined state.
+     *
+     * @param path Requested path
+     * @return Resolved schema tree child
+     * @throws NullPointerException if {@code path} is null
+     * @throws IllegalArgumentException if the target node cannot be found
+     * @throws VerifyException if path expression is invalid
+     */
+    public @NonNull EffectiveStatement<?, ?> resolvePathExpression(final PathExpression path) {
+        final Steps steps = path.getSteps();
+        if (steps instanceof LocationPathSteps) {
+            return resolveLocationPath(((LocationPathSteps) steps).getLocationPath());
+        } else if (steps instanceof DerefSteps) {
+            return resolveDeref((DerefSteps) steps);
+        } else {
+            throw new VerifyException("Unhandled steps " + steps);
+        }
+    }
+
+    private @NonNull EffectiveStatement<?, ?> resolveDeref(final DerefSteps deref) {
+        final EffectiveStatement<?, ?> leafRefSchemaNode = currentStatement();
+        final YangLocationPath.Relative derefArg = deref.getDerefArgument();
+        final EffectiveStatement<?, ?> derefStmt = resolveLocationPath(derefArg);
+        checkArgument(derefStmt != null, "Cannot find deref(%s) target node %s in context of %s",
+                derefArg, leafRefSchemaNode);
+        checkArgument(derefStmt instanceof TypedDataSchemaNode, "deref(%s) resolved to non-typed %s", derefArg,
+                derefStmt);
+
+        // We have a deref() target, decide what to do about it
+        final TypeDefinition<?> targetType = ((TypedDataSchemaNode) derefStmt).getType();
+        if (targetType instanceof InstanceIdentifierTypeDefinition) {
+            // Static inference breaks down, we cannot determine where this points to
+            // FIXME: dedicated exception, users can recover from it, derive from IAE
+            throw new UnsupportedOperationException("Cannot infer instance-identifier reference " + targetType);
+        }
+
+        // deref() is defined only for instance-identifier and leafref types, handle the latter
+        checkArgument(targetType instanceof LeafrefTypeDefinition, "Illegal target type %s", targetType);
+
+        final PathExpression dereferencedLeafRefPath = ((LeafrefTypeDefinition) targetType).getPathStatement();
+        EffectiveStatement<?, ?> derefNode = resolvePathExpression(dereferencedLeafRefPath);
+        checkArgument(derefStmt != null, "Can not find target node of dereferenced node %s", derefStmt);
+        checkArgument(derefNode instanceof LeafSchemaNode, "Unexpected %s reference in %s", deref,
+                dereferencedLeafRefPath);
+        return resolveLocationPath(deref.getRelativePath());
+    }
+
+    private @NonNull EffectiveStatement<?, ?> resolveLocationPath(final YangLocationPath path) {
+        // get the default namespace before we clear and loose our deque
+        final QNameModule defaultNamespace = deque.isEmpty() ? null : ((QName) deque.peek().argument()).getModule();
+        if (path.isAbsolute()) {
+            clear();
+        }
+
+        EffectiveStatement<?, ?> current = null;
+        for (Step step : path.getSteps()) {
+            final YangXPathAxis axis = step.getAxis();
+            switch (axis) {
+                case PARENT:
+                    verify(step instanceof AxisStep, "Unexpected parent step %s", step);
+                    try {
+                        current = exitToDataTree();
+                    } catch (IllegalStateException e) {
+                        throw new IllegalArgumentException("Illegal parent access in " + path, e);
+                    }
+                    break;
+                case CHILD:
+                    verify(step instanceof QNameStep, "Unexpected child step %s", step);
+                    current = enterChild((QNameStep) step, defaultNamespace);
+                    break;
+                default:
+                    throw new VerifyException("Unexpected step " + step);
+            }
+        }
+
+        return verifyNotNull(current);
+    }
+
+    private @NonNull EffectiveStatement<?, ?> enterChild(final QNameStep step, final QNameModule defaultNamespace) {
+        final AbstractQName toResolve = step.getQName();
+        final QName qname;
+        if (toResolve instanceof QName) {
+            qname = (QName) toResolve;
+        } else if (toResolve instanceof UnqualifiedQName) {
+            checkArgument(defaultNamespace != null, "Can not find target module of step %s", step);
+            qname = ((UnqualifiedQName) toResolve).bindTo(defaultNamespace);
+        } else {
+            throw new VerifyException("Unexpected child step QName " + toResolve);
+        }
+        return enterDataTree(qname);
+    }
+
     /**
      * Return an {@link Inference} equivalent of current state.
      *
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Bug4969Test.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/Bug4969Test.java
deleted file mode 100644 (file)
index d7c7fe9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.opendaylight.yangtools.yang.model.api.PathExpression;
-
-public class Bug4969Test {
-    @Test
-    public void testRegex() {
-        PathExpression xpath = new PathExpressionImpl(
-                "nd:network[nd:network-id=current()/../network-ref]/nd:node[nd:node-id=current()/../node-ref]"
-                + "/termination-point/tp-id", true);
-        assertEquals("nd:network/nd:node/termination-point/tp-id",
-                SchemaContextUtil.stripConditionsFromXPathString(xpath));
-    }
-}
index b651a5237abaf68a5f905dab7f0036e1ace8bfd0..65da97f894c78b24121367e26200d2265c7d9572 100644 (file)
@@ -7,10 +7,12 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -22,7 +24,6 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
@@ -49,35 +50,43 @@ public class LeafrefStaticAnalysisTest {
     public void testGrpOuterId() {
         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(QName.create(FOO, "outer-id")).get();
         // Cannot be found as the reference goes outside of the grouping
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(grp.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "outer-id"));
+        assertThrowsInvalidPath(stack, leaf);
     }
 
     @Test
     public void testFooOuterId() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(QName.create(FOO, "outer-id")).get();
-        final SchemaNode found = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement());
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "outer-id"));
+        final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
+                .getPathStatement());
 
         assertThat(found, isA(LeafSchemaNode.class));
-        assertEquals(SchemaPath.create(true, FOO, QName.create(FOO, "id")), found.getPath());
+        assertEquals(QName.create(FOO, "id"), found.getQName());
     }
 
     @Test
     public void testGrpOuterIndirectProp() {
         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
             QName.create(FOO, "outer-indirect-prop")).get();
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(grp.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
         // Cannot resolve deref outer-id
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        assertThrowsInvalidPath(stack, leaf);
     }
 
     @Test
     public void testFooOuterIndirectProp() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
             QName.create(FOO, "outer-indirect-prop")).get();
-        final SchemaNode found = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement());
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "outer-indirect-prop"));
+        final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
+                .getPathStatement());
 
         assertThat(found, isA(LeafSchemaNode.class));
         assertEquals(QName.create(FOO, "prop"), found.getQName());
@@ -86,8 +95,11 @@ public class LeafrefStaticAnalysisTest {
     @Test
     public void testGrpIndirect() {
         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(QName.create(FOO, "indirect")).get();
-        final SchemaNode found = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement());
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(grp.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "indirect"));
+        final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
+                .getPathStatement());
 
         assertThat(found, isA(LeafSchemaNode.class));
         assertEquals(QName.create(FOO, "prop"), found.getQName());
@@ -96,8 +108,10 @@ public class LeafrefStaticAnalysisTest {
     @Test
     public void testFooIndirect() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(QName.create(FOO, "indirect")).get();
-        final SchemaNode found = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement());
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "indirect"));
+        final SchemaNode found = (SchemaNode) stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType())
+                .getPathStatement());
 
         assertThat(found, isA(LeafSchemaNode.class));
         assertEquals(QName.create(FOO, "prop"), found.getQName());
@@ -107,39 +121,69 @@ public class LeafrefStaticAnalysisTest {
     public void testGrpDerefNonExistent() {
         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
             QName.create(FOO, "deref-non-existent")).get();
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(grp.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
+        assertThrowsMissingXyzzy(stack, leaf);
     }
 
     @Test
     public void testFooDerefNonExistent() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
             QName.create(FOO, "deref-non-existent")).get();
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "deref-non-existent"));
+        assertThrowsMissingXyzzy(stack, leaf);
     }
 
     @Test
     public void testGrpNonExistentDeref() {
         final LeafSchemaNode leaf = (LeafSchemaNode) grp.findDataChildByName(
             QName.create(FOO, "non-existent-deref")).get();
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(grp.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
+        assertThrowsMissingXyzzy(stack, leaf);
     }
 
     @Test
     public void testFooNonExistentDeref() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
             QName.create(FOO, "non-existent-deref")).get();
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-            ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context, foo.getQName(), bar.getQName());
+        stack.enterSchemaTree(QName.create(FOO, "non-existent-deref"));
+        assertThrowsMissingXyzzy(stack, leaf);
     }
 
     @Test
     public void testNonExistentRelativeXpath() {
         final LeafSchemaNode leaf = (LeafSchemaNode) bar.findDataChildByName(
                 QName.create(FOO, "indirect-with-current")).get();
-        assertNull(SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf,
-                ((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
+        final SchemaInferenceStack stack = SchemaInferenceStack.ofDataTreePath(context,
+            foo.getQName(), bar.getQName(), QName.create(FOO, "indirect-with-current"));
+        assertThrowsMissingChild(stack, leaf, "(leafrefs)n");
+    }
+
+    private static void assertThrowsInvalidPath(final SchemaInferenceStack stack, final LeafSchemaNode leaf) {
+        final IllegalArgumentException ex = assertThrowsIAE(stack, leaf);
+        assertThat(ex.getMessage(), startsWith("Illegal parent access in "));
+        final Throwable cause = ex.getCause();
+        assertThat(cause, instanceOf(IllegalStateException.class));
+        assertEquals("Unexpected current GroupingEffectiveStatementImpl[qname=(leafrefs)grp]", cause.getMessage());
+    }
+
+    private static void assertThrowsMissingXyzzy(final SchemaInferenceStack stack, final LeafSchemaNode leaf) {
+        assertThrowsMissingChild(stack, leaf, "(leafrefs)xyzzy");
+    }
+
+    private static void assertThrowsMissingChild(final SchemaInferenceStack stack, final LeafSchemaNode leaf,
+            final String childName) {
+        assertEquals("Data tree child " + childName + " not present", assertThrowsIAE(stack, leaf).getMessage());
+    }
+
+    private static IllegalArgumentException assertThrowsIAE(final SchemaInferenceStack stack,
+            final LeafSchemaNode leaf) {
+        return assertThrows(IllegalArgumentException.class,
+            () -> stack.resolvePathExpression(((LeafrefTypeDefinition) leaf.getType()).getPathStatement()));
     }
 }
index 7676fad6f3dc7b58bd2c969b820b9df4fab97434..644dd18aac2953c121d870aac909db62d84162fd 100644 (file)
@@ -10,6 +10,9 @@ package org.opendaylight.yangtools.yang.model.util;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -20,19 +23,22 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 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.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.PathExpression;
+import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
 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.test.util.YangParserTestUtils;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
 
 public class SchemaContextUtilIntegrationTest {
-    private static SchemaContext context;
+    private static EffectiveModelContext context;
     private static Module myModule;
 
     @BeforeClass
@@ -286,29 +292,33 @@ public class SchemaContextUtilIntegrationTest {
         final Module importedModule = context.findModule(XMLNamespace.of("uri:imported-module"),
             Revision.of("2014-10-07")).get();
 
-        final SchemaNode testNode = ((ContainerSchemaNode) importedModule.getDataChildByName(QName.create(
-                importedModule.getQNameModule(), "my-imported-container"))).getDataChildByName(QName.create(
-                importedModule.getQNameModule(), "my-imported-leaf"));
+        final QName myImportedContainer = QName.create(importedModule.getQNameModule(), "my-imported-container");
+        final QName myImportedLeaf = QName.create(importedModule.getQNameModule(), "my-imported-leaf");
 
-        final PathExpression xpath = new PathExpressionImpl("imp:my-imported-container/imp:my-imported-leaf", true);
+        final SchemaNode testNode = ((ContainerSchemaNode) importedModule.getDataChildByName(myImportedContainer))
+            .getDataChildByName(myImportedLeaf);
 
-        final SchemaNode foundNode = SchemaContextUtil.findDataSchemaNode(context, myModule, xpath);
-        assertNotNull(foundNode);
-        assertEquals(testNode, foundNode);
+        final PathExpression expr = mock(PathExpression.class);
+        doReturn(true).when(expr).isAbsolute();
+        doReturn(new LocationPathSteps(YangLocationPath.absolute(
+            YangXPathAxis.CHILD.asStep(myImportedContainer), YangXPathAxis.CHILD.asStep(myImportedLeaf))))
+                .when(expr).getSteps();
+
+        assertEquals(testNode, SchemaInferenceStack.of(context).resolvePathExpression(expr));
     }
 
     @Test
     public void findDataSchemaNodeTest2() {
-        final GroupingDefinition grouping = getGroupingByName(myModule, "my-grouping");
-        final SchemaNode testNode = grouping.getDataChildByName(QName.create(myModule.getQNameModule(),
-                "my-leaf-in-gouping2"));
-
-        final PathExpression xpath = new PathExpressionImpl("my:my-grouping/my:my-leaf-in-gouping2", true);
+        final QName myLeafInGrouping2 = QName.create(myModule.getQNameModule(), "my-leaf-in-gouping2");
+        final PathExpression expr = mock(PathExpression.class);
+        doReturn(true).when(expr).isAbsolute();
+        doReturn(new LocationPathSteps(YangLocationPath.relative(YangXPathAxis.CHILD.asStep(myLeafInGrouping2))))
+            .when(expr).getSteps();
 
-        final SchemaNode foundNode = SchemaContextUtil.findDataSchemaNode(context, myModule, xpath);
-
-        assertNotNull(foundNode);
-        assertEquals(testNode, foundNode);
+        final GroupingDefinition grouping = getGroupingByName(myModule, "my-grouping");
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        assertSame(grouping, stack.enterGrouping(grouping.getQName()));
+        assertEquals(grouping.getDataChildByName(myLeafInGrouping2), stack.resolvePathExpression(expr));
     }
 
     @Test
index be19429bea127177652c97860e2c7329b328d2db..5f1682578ec42940bfdd9dece3d31050b9221052 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
@@ -15,12 +14,8 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
 import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.List;
 import java.util.Optional;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -30,11 +25,9 @@ import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.Revision;
 import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.PathExpression;
 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.ri.type.BaseTypes;
 
 @RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class SchemaContextUtilTest {
@@ -49,72 +42,16 @@ public class SchemaContextUtilTest {
     public SchemaNode schemaNode;
 
     @Test
-    @Ignore
-    // FIXME: YANGTOOLS-1127: rewrite this test in terms of a real PathExpression
     public void testFindDummyData() {
         doReturn(Optional.empty()).when(mockSchemaContext).findModule(any(QNameModule.class));
-        doReturn(Optional.empty()).when(mockSchemaContext).findDataTreeChild(any(Iterable.class));
-
-        doReturn("test").when(mockModule).getName();
-        doReturn("test").when(mockModule).getPrefix();
-        doReturn(QNameModule.create(NAMESPACE)).when(mockModule).getQNameModule();
 
         QName qname = QName.create("namespace", "localname");
         SchemaPath schemaPath = SchemaPath.create(Collections.singletonList(qname), true);
         assertNull("Should be null. Module TestQName not found",
                 SchemaContextUtil.findDataSchemaNode(mockSchemaContext, schemaPath));
 
-        PathExpression xpath = new PathExpressionImpl("/test:bookstore/test:book/test:title", true);
-        assertNull("Should be null. Module bookstore not found",
-                SchemaContextUtil.findDataSchemaNode(mockSchemaContext, mockModule, xpath));
-
-
-        final PathExpression xPath = new PathExpressionImpl("/bookstore/book/title", true);
-        assertEquals("Should be null. Module bookstore not found", null,
-                SchemaContextUtil.findDataSchemaNode(mockSchemaContext, mockModule, xPath));
-
-        SchemaNode int32node = BaseTypes.int32Type();
-        PathExpression xpathRelative = new PathExpressionImpl("../prefix", false);
-        assertNull("Should be null, Module prefix not found",
-                SchemaContextUtil.findDataSchemaNodeForRelativeXPath(
-                        mockSchemaContext, mockModule, int32node, xpathRelative));
-
         assertNull("Should be null. Module TestQName not found",
                 SchemaContextUtil.findNodeInSchemaContext(mockSchemaContext, Collections.singleton(qname)));
-
-        assertNull("Should be null.", SchemaContextUtil.findParentModule(mockSchemaContext, int32node));
-    }
-
-    @Test
-    public void findDataSchemaNodeFromXPathIllegalArgumentTest() {
-        assertThrows(NullPointerException.class,
-            () -> SchemaContextUtil.findDataSchemaNode(mock(SchemaContext.class), mock(Module.class), null));
-    }
-
-    @Test
-    public void findDataSchemaNodeFromXPathIllegalArgumentTest2() {
-        final SchemaContext mockContext = mock(SchemaContext.class);
-        final PathExpression xpath = new PathExpressionImpl("my:my-grouping/my:my-leaf-in-gouping2", true);
-
-        assertThrows(NullPointerException.class, () -> SchemaContextUtil.findDataSchemaNode(mockContext, null, xpath));
-    }
-
-    @Test
-    public void findDataSchemaNodeFromXPathIllegalArgumentTest3() {
-        final Module module = mock(Module.class);
-        final PathExpression xpath = new PathExpressionImpl("my:my-grouping/my:my-leaf-in-gouping2", true);
-
-        assertThrows(NullPointerException.class, () -> SchemaContextUtil.findDataSchemaNode(null, module, xpath));
-    }
-
-    @Test
-    public void findDataSchemaNodeFromXPathIllegalArgumentTest4() {
-        final SchemaContext mockContext = mock(SchemaContext.class);
-        final Module module = mock(Module.class);
-        final PathExpression xpath = new PathExpressionImpl("my:my-grouping[@con='NULL']/my:my-leaf-in-gouping2", true);
-
-        assertThrows(IllegalArgumentException.class,
-            () -> SchemaContextUtil.findDataSchemaNode(mockContext, module, xpath));
     }
 
     @Test
@@ -140,32 +77,4 @@ public class SchemaContextUtilTest {
         assertThrows(NullPointerException.class, () -> SchemaContextUtil.findDataSchemaNode(null,
             SchemaPath.create(true, QName.create(XMLNamespace.of("uri:my-module"), Revision.of("2014-10-07"), "foo"))));
     }
-
-    @Test
-    public void findDataSchemaNodeFromXPathNullTest2() {
-        final SchemaContext mockContext = mock(SchemaContext.class);
-        final Module module = mock(Module.class);
-        final PathExpression xpath = new PathExpressionImpl("my:my-grouping/my:my-leaf-in-gouping2", false);
-
-        assertNull(SchemaContextUtil.findDataSchemaNode(mockContext, module, xpath));
-    }
-
-    @Test
-    public void testNormalizeXPath() {
-        assertNormalizedPath(0, ImmutableList.of(""), "");
-        assertNormalizedPath(0, ImmutableList.of("a"), "a");
-        assertNormalizedPath(0, ImmutableList.of("a", "b"), "a b");
-        assertNormalizedPath(1, ImmutableList.of("..", "b"), ".. b");
-        assertNormalizedPath(0, ImmutableList.of(), "a ..");
-        assertNormalizedPath(0, ImmutableList.of("b"), "a .. b");
-        assertNormalizedPath(2, ImmutableList.of("..", "..", "a", "c"), ".. .. a b .. c");
-        assertNormalizedPath(3, ImmutableList.of("..", "..", "..", "b"), ".. .. a .. .. b");
-    }
-
-    private static void assertNormalizedPath(final int expectedLead, final List<String> expectedList,
-            final String input) {
-        final List<String> list = new ArrayList<>(SPACE_SPLITTER.splitToList(input));
-        assertEquals(expectedLead, SchemaContextUtil.normalizeXPath(list));
-        assertEquals(expectedList, list);
-    }
 }
index cb124aa3e5d499b775279b0b0680ac3b986d2122..6d5092e32ab3e7d4a263e4d1ce37e06c3bab3dc7 100644 (file)
@@ -19,8 +19,8 @@ import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
@@ -52,8 +52,12 @@ public class YT1050Test {
         final TypeDefinition<?> typeNodeType = secondaryType.getType();
         assertThat(typeNodeType, isA(LeafrefTypeDefinition.class));
 
-        final SchemaNode found =  SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, secondaryType,
-            ((LeafrefTypeDefinition) typeNodeType).getPathStatement());
+        final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+        stack.enterGrouping(QName.create(module.getQNameModule(), "grp"));
+        stack.enterSchemaTree(QName.create(module.getQNameModule(), "secondary"));
+        stack.enterSchemaTree(secondaryType.getQName());
+        final EffectiveStatement<?, ?> found = stack.resolvePathExpression(((LeafrefTypeDefinition) typeNodeType)
+                .getPathStatement());
         assertSame(primaryType, found);
     }
 }
index 693884dc252e01dee35de41ede86b2580c7b67ae..2e274d42b5a061cac0dc1b724a1a8c50dfe6989d 100644 (file)
@@ -10,12 +10,14 @@ package org.opendaylight.yangtools.yang.model.util;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.isA;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.ImmutableList;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
@@ -23,8 +25,7 @@ import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.PathExpression;
 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
 import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
@@ -58,10 +59,14 @@ public class YT1060Test {
     }
 
     @Test
-    public void testFindDataSchemaNode() {
-        final SchemaNode found = SchemaContextUtil.findDataTreeSchemaNode(context, CONT.getModule(), path);
-        assertThat(found, isA(LeafSchemaNode.class));
-        assertEquals(SchemaPath.create(true, QName.create("imported", "root"), QName.create("imported", "leaf1")),
-            found.getPath());
+    public void testFindDataSchemaNodeAbsolutePathImportedModule() {
+        final EffectiveStatement<?, ?> foundStmt = SchemaInferenceStack.ofDataTreePath(context, CONT, LEAF1)
+            .resolvePathExpression(path);
+        assertThat(foundStmt, isA(LeafSchemaNode.class));
+        assertEquals(QName.create(XMLNamespace.of("imported"), "leaf1"), ((LeafSchemaNode) foundStmt).getQName());
+
+        // since this is absolute path with prefixes stack should be able to resolve it from any state
+        final EffectiveStatement<?, ?> foundStmtSecond = SchemaInferenceStack.of(context).resolvePathExpression(path);
+        assertSame(foundStmt, foundStmtSecond);
     }
 }
index 9de18c85942241010951f2383d6ab637e76710b4..5a4de9514aec41d0057e97a8e1da3cde776ea784 100644 (file)
@@ -19,8 +19,8 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.PathExpression;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
@@ -31,18 +31,22 @@ public class YT1100Test {
         final EffectiveModelContext context = YangParserTestUtils.parseYangResource("/yt1100.yang");
         final Module module = context.findModule("yt1100").orElseThrow();
         final QNameModule qnm = module.getQNameModule();
-        final DataSchemaNode leaf = module.findDataTreeChild(
-            QName.create(qnm, "foo"), QName.create(qnm, "scheduler-node"), QName.create(qnm, "child-scheduler-nodes"),
-            QName.create(qnm, "name")).orElseThrow();
+        final QName foo = QName.create(qnm, "foo");
+        final QName schedulerNode = QName.create(qnm, "scheduler-node");
+        final QName childSchedulerNodes = QName.create(qnm, "child-scheduler-nodes");
+        final QName name = QName.create(qnm, "name");
+        final DataSchemaNode leaf = module.findDataTreeChild(foo, schedulerNode, childSchedulerNodes, name)
+                .orElseThrow();
         assertThat(leaf, instanceOf(LeafSchemaNode.class));
 
         final TypeDefinition<?> type = ((LeafSchemaNode) leaf).getType();
         assertThat(type, instanceOf(LeafrefTypeDefinition.class));
         final PathExpression leafref = ((LeafrefTypeDefinition) type).getPathStatement();
 
-        final SchemaNode ref = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(context, module, leaf, leafref);
-        assertThat(ref, instanceOf(LeafSchemaNode.class));
-        final LeafSchemaNode targetLeaf = (LeafSchemaNode) ref;
+        final EffectiveStatement<?, ?> resolvedLeafRef = SchemaInferenceStack.ofDataTreePath(
+            context, foo, schedulerNode,childSchedulerNodes, name).resolvePathExpression(leafref);
+        assertThat(resolvedLeafRef, instanceOf(LeafSchemaNode.class));
+        final LeafSchemaNode targetLeaf = (LeafSchemaNode) resolvedLeafRef;
         assertEquals(QName.create(qnm, "name"), targetLeaf.getQName());
         assertThat(targetLeaf.getType(), instanceOf(StringTypeDefinition.class));
     }
index c75b93ad59bb950ef98a3a77242c8b3ad1ddf588..429ac32d88c18a2176b150a6f38d74d7865ac7b3 100644 (file)
@@ -12,10 +12,11 @@ import static org.hamcrest.Matchers.isA;
 
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
@@ -26,8 +27,8 @@ public class YT588Test {
     private static final String REV = "2016-03-01";
 
     @Test
-    public void test() throws Exception {
-        SchemaContext context = YangParserTestUtils.parseYangResource("/yt588.yang");
+    public void test() {
+        EffectiveModelContext context = YangParserTestUtils.parseYangResource("/yt588.yang");
 
         QName root = QName.create(NS, REV, "root");
         QName leafRef2 = QName.create(NS, REV, "leaf-ref-2");
@@ -45,12 +46,12 @@ public class YT588Test {
         assertThat(leafRefNode.getType(), isA(LeafrefTypeDefinition.class));
         assertThat(leafRefNode2.getType(), isA(LeafrefTypeDefinition.class));
 
-        TypeDefinition<?> baseTypeForLeafRef = SchemaContextUtil.getBaseTypeForLeafRef(
-                (LeafrefTypeDefinition) leafRefNode.getType(), context, leafRefNode);
-        TypeDefinition<?> baseTypeForLeafRef2 = SchemaContextUtil.getBaseTypeForLeafRef(
-                (LeafrefTypeDefinition) leafRefNode2.getType(), context, leafRefNode2);
+        EffectiveStatement<?, ?> found = SchemaInferenceStack.ofDataTreePath(context, root, conGrp, leafRef)
+                .resolvePathExpression(((LeafrefTypeDefinition) leafRefNode.getType()).getPathStatement());
+        assertThat(((TypedDataSchemaNode)found).getType(), isA(BinaryTypeDefinition.class));
 
-        assertThat(baseTypeForLeafRef, isA(BinaryTypeDefinition.class));
-        assertThat(baseTypeForLeafRef2, isA(Int16TypeDefinition.class));
+        found = SchemaInferenceStack.ofDataTreePath(context, root, leafRef2)
+            .resolvePathExpression(((LeafrefTypeDefinition) leafRefNode2.getType()).getPathStatement());
+        assertThat(((TypedDataSchemaNode)found).getType(), isA(Int16TypeDefinition.class));
     }
 }
index d9b63b792ee2d605ce77f747877077d11aac3409..dd7f258dd1e4c0d0ae3c63bd9f3c9db82fae6073 100644 (file)
@@ -17,7 +17,6 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 
@@ -89,7 +88,7 @@ public class Bug5335Test {
 
     @Test
     public void correctTest4() throws Exception {
-        final SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-4");
+        final EffectiveModelContext context = StmtTestUtils.parseYangSources("/bugs/bug5335/correct/case-4");
         final DataSchemaNode mandatoryLeaf = context.findDataTreeChild(ROOT, NON_PRESENCE_CONTAINER_F, MANDATORY_LEAF_F)
             .orElse(null);
         assertThat(mandatoryLeaf, instanceOf(LeafSchemaNode.class));
index 6d308571d78f507a1c4aa7cf685b5dc4fa5032f0..50fcda68d9319a445bc85994d2371e8cf41922bc 100644 (file)
@@ -5,7 +5,6 @@
  * 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.stmt;
 
 import static org.junit.Assert.assertEquals;
@@ -21,6 +20,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Revision;
 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
@@ -32,10 +32,9 @@ import org.opendaylight.yangtools.yang.parser.rfc7950.reactor.RFC7950Reactors;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 
 public class RpcStmtTest {
-
     @Test
     public void rpcTest() throws ReactorException {
-        final SchemaContext result = RFC7950Reactors.defaultReactor().newBuild()
+        final EffectiveModelContext result = RFC7950Reactors.defaultReactor().newBuild()
                 .addSource(sourceForResource("/model/baz.yang"))
                 .addSource(sourceForResource("/model/bar.yang"))
                 .addSource(sourceForResource("/rpc-stmt-test/foo.yang"))