Bug4231 - Yang tools failing to parse Augmentations under "uses" clause. 29/26329/4
authorPeter Kajsa <pkajsa@cisco.com>
Wed, 2 Sep 2015 11:49:20 +0000 (13:49 +0200)
committerRobert Varga <nite@hq.sk>
Thu, 24 Sep 2015 18:25:11 +0000 (18:25 +0000)
The problem occurs when uses-augment is nested in another Augment statement.
In this case the parent node of uses node is not subclass of SchemaNode
but it is AugmentationSchemaNode (it is not subclass of SchemaNode) and in
consequence class cast exception occurs.

Change-Id: I674392889e561f357297fa220051e8c3728f537d
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/builder/impl/BuilderUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug4231Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/TestUtils.java
yang/yang-parser-impl/src/test/resources/bugs/bug4231/foo.yang [new file with mode: 0644]

index 3a17fdeda56e49ee25578e699d86b2491aa6f58c..1c202f61004c5d7ac84a57532571897da679cf80 100644 (file)
@@ -344,6 +344,41 @@ public final class BuilderUtils {
         }
     }
 
+    /**
+     * Find builder of schema node under parent builder (including under
+     * AugmentationSchemaBuilder).
+     *
+     * @param path
+     *            - path of target schema node builder
+     * @param parent
+     *            - base data node container builder under which the target
+     *            schema node builder should be found
+     * @return builder of schema node
+     */
+    public static SchemaNodeBuilder findTargetNode(final Iterable<QName> path,
+            final DataNodeContainerBuilder parent) {
+
+        Preconditions.checkNotNull(parent);
+        Preconditions.checkNotNull(path);
+
+        SchemaNodeBuilder foundNode = null;
+
+        final Iterator<QName> pathIterator = path.iterator();
+        if (pathIterator.hasNext()) {
+            String name = pathIterator.next().getLocalName();
+            foundNode = parent.getDataChildByName(name);
+            if (foundNode == null) {
+                foundNode = findUnknownNode(name, parent);
+            }
+        }
+
+        if (pathIterator.hasNext() && foundNode != null) {
+            return findSchemaNode(Iterables.skip(path, 1), foundNode);
+        } else {
+            return foundNode;
+        }
+    }
+
     public static SchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
         SchemaNodeBuilder node = null;
         SchemaNodeBuilder parent = parentNode;
index 25abb54e83246d971d94a42dfee8bb8d4cc0cf0c..1aafe20ae4a5505aae50f3cfee7449fa3734c155 100644 (file)
@@ -11,8 +11,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.fillAugmentTarget;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findBaseIdentity;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findModuleFromContext;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNode;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNodeInModule;
+import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findTargetNode;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.processAugmentation;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveType;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveTypeUnion;
@@ -957,8 +957,8 @@ public final class YangParserImpl implements YangContextParser {
             // Conflicting elements in other namespaces are still not present
             // since resolveUsesAugment occurs before augmenting from external
             // modules.
-            potentialTargetNode = Optional.<SchemaNodeBuilder> fromNullable(findSchemaNode(augment.getTargetPath()
-                    .getPathFromRoot(), (SchemaNodeBuilder) parentNode));
+            potentialTargetNode = Optional.<SchemaNodeBuilder> fromNullable(findTargetNode(augment.getTargetPath()
+                    .getPathFromRoot(), parentNode));
         }
 
         if (potentialTargetNode.isPresent()) {
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug4231Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/Bug4231Test.java
new file mode 100644 (file)
index 0000000..1f7ec43
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.text.ParseException;
+
+import java.net.URI;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import org.junit.Test;
+
+public class Bug4231Test {
+
+    @Test
+    public void test() throws IOException, URISyntaxException, ParseException {
+        SchemaContext context = TestUtils.loadSchemaContext(getClass()
+                .getResource("/bugs/bug4231").toURI());
+
+        assertNotNull(context);
+
+        QNameModule foo = QNameModule.create(new URI("foo"),
+                SimpleDateFormatUtil.getRevisionFormat().parse("2015-09-02"));
+
+        SchemaPath targetPath = SchemaPath
+                .create(true, QName.create(foo, "augment-target"))
+                .createChild(QName.create(foo, "my-container-in-grouping"))
+                .createChild(QName.create(foo, "l2"));
+
+        SchemaNode targetNode = SchemaContextUtil.findNodeInSchemaContext(
+                context, targetPath.getPathFromRoot());
+        assertNotNull(targetNode);
+    }
+
+}
index dbf74387ce5a9f4f75a82f1569a70c55d6909503..dcbaa85a065eb6e6cf626ef7d8769eec13ddaef2 100644 (file)
@@ -46,8 +46,8 @@ final class TestUtils {
     private TestUtils() {
     }
 
-
-    public static Set<Module> loadModules(final URI resourceDirectory) throws IOException {
+    public static SchemaContext loadSchemaContext(final URI resourceDirectory)
+            throws IOException {
         final YangContextParser parser = new YangParserImpl();
         final File testDir = new File(resourceDirectory);
         final String[] fileList = testDir.list();
@@ -58,8 +58,12 @@ final class TestUtils {
         for (String fileName : fileList) {
             testFiles.add(new File(testDir, fileName));
         }
-        SchemaContext ctx = parser.parseFiles(testFiles);
-        return ctx.getModules();
+        return parser.parseFiles(testFiles);
+    }
+
+    public static Set<Module> loadModules(final URI resourceDirectory)
+            throws IOException {
+        return loadSchemaContext(resourceDirectory).getModules();
     }
 
     public static Set<Module> loadModules(final List<InputStream> input) throws IOException, YangSyntaxErrorException {
diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug4231/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug4231/foo.yang
new file mode 100644 (file)
index 0000000..d994c03
--- /dev/null
@@ -0,0 +1,38 @@
+module foo {
+    namespace "foo";
+    prefix "foo";
+    yang-version 1;
+
+    revision 2015-09-02 {
+        description "Test";
+    }
+
+    grouping my-grouping {
+        container my-container-in-grouping {
+        }
+    }
+
+    augment /augment-target {
+        uses my-grouping {
+            augment my-container-in-grouping {
+                leaf-list l2 {
+                    type string;
+                    ordered-by "user";
+                    foo:bar "argument";
+                    foo:baz "$X(/a/a/a/@@)";
+                }
+            }
+        }
+    }
+
+    container augment-target {
+    }
+
+    extension bar {
+        argument "arg";
+    }
+
+    extension baz {
+        argument "arg";
+    }
+}