Fix for Bug 527. 51/5751/2
authorMartin Vitez <mvitez@cisco.com>
Mon, 24 Mar 2014 09:23:28 +0000 (10:23 +0100)
committerMartin Vitez <mvitez@cisco.com>
Thu, 27 Mar 2014 16:13:43 +0000 (17:13 +0100)
Fixed codec loading for choice case nodes.
Fixed bug in parser when handling uses/augment target path.
Helper methods from BindingGeneratorImpl moved to SchemaContextUtil class.
Added test.

Change-Id: Id1b835150cdad2c278bd9c125d5369822b75639a
Signed-off-by: Martin Vitez <mvitez@cisco.com>
12 files changed:
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.xtend
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/LazyGeneratedCodecRegistry.java
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/TransformerGenerator.xtend
integration-test/bug527-test-model/pom.xml [new file with mode: 0644]
integration-test/bug527-test-model/src/main/yang/bar.yang [new file with mode: 0644]
integration-test/bug527-test-model/src/main/yang/foo.yang [new file with mode: 0644]
integration-test/pom.xml
restconf/restconf-util/pom.xml
restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/Bug527Test.java [new file with mode: 0644]
restconf/restconf-util/src/test/resources/topology-bug527.xml [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/SchemaContextUtil.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java

index 94d4812cd039f3c5e72b6f46d85f503d51f761fb..bfbbf2f65b6823ab64a4e42200a191f95ffaa43d 100644 (file)
@@ -69,7 +69,6 @@ import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder
 import org.opendaylight.yangtools.yang.model.api.ModuleImport
 import org.opendaylight.yangtools.yang.binding.DataContainer
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
@@ -80,8 +79,6 @@ import org.opendaylight.yangtools.yang.binding.BindingMapping
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase
 
 import com.google.common.collect.Sets
-import java.net.URI
-import java.util.Date
 
 public class BindingGeneratorImpl implements BindingGenerator {
 
@@ -745,7 +742,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
         if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
-            targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
+            targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode, schemaContext);
             if (targetSchemaNode == null) {
                 throw new NullPointerException(
                     "Failed to find target node from grouping in augmentation " + augSchema + " in module " +
@@ -814,228 +811,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    /**
-     * Utility method which search for original node defined in grouping.
-     */
-    private def DataSchemaNode findOriginal(DataSchemaNode node) {
-        var DataSchemaNode result = findCorrectTargetFromGrouping(node);
-        if (result == null) {
-            result = findCorrectTargetFromAugment(node);
-            if (result != null) {
-                if (result.addedByUses) {
-                    result = findOriginal(result);
-                }
-            }
-        }
-        return result;
-    }
-
-    private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
-        if (!node.augmenting) {
-            return null
-        }
-
-        var QName currentName = node.QName
-        var Object currentNode = node
-        var Object parent = node;
-        val tmpPath = new ArrayList<QName>()
-        val tmpTree = new ArrayList<SchemaNode>()
-
-        var AugmentationSchema augment = null;
-        do {
-            val SchemaPath sp = (parent as SchemaNode).path
-            val List<QName> names = sp.path
-            val List<QName> newNames = new ArrayList(names)
-            newNames.remove(newNames.size - 1)
-            val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)
-            parent = findDataSchemaNode(schemaContext, newSp)
-            if (parent instanceof AugmentationTarget) {
-                tmpPath.add(currentName);
-                tmpTree.add(currentNode as SchemaNode)
-                augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
-                if (augment == null) {
-                    currentName = (parent as DataSchemaNode).QName
-                    currentNode = parent
-                }
-            }
-        } while ((parent as DataSchemaNode).augmenting && augment == null);
-
-        if (augment == null) {
-            return null;
-        } else {
-            Collections.reverse(tmpPath);
-            Collections.reverse(tmpTree);
-            var Object actualParent = augment;
-            var DataSchemaNode result = null;
-            for (name : tmpPath) {
-                if (actualParent instanceof DataNodeContainer) {
-                    result = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
-                    actualParent = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
-                } else {
-                    if (actualParent instanceof ChoiceNode) {
-                        result = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
-                        actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
-                    }
-                }
-            }
-
-            if (result.addedByUses) {
-                result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree);
-            }
-
-            return result;
-        }
-    }
-
-    private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
-        for (augment : augments) {
-            val DataSchemaNode node = augment.getDataChildByName(name);
-            if (node != null) {
-                return augment;
-            }
-        }
-        return null;
-    }
-
-    private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
-        if (node.path.path.size == 1) {
-            // uses is under module statement
-            val Module m = findParentModule(schemaContext, node);
-            var DataSchemaNode result = null;
-            for (u : m.uses) {
-                var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
-                if (!(targetGrouping instanceof GroupingDefinition)) {
-                    throw new IllegalArgumentException("Failed to generate code for augment in " + u);
-                }
-                var gr = targetGrouping as GroupingDefinition;
-                result = gr.getDataChildByName(node.QName.localName);
-            }
-            if (result == null) {
-                throw new IllegalArgumentException("Failed to generate code for augment")
-            }
-            return result
-        } else {
-            var DataSchemaNode result = null;
-            var QName currentName = node.QName
-            var tmpPath = new ArrayList<QName>()
-            var Object parent = null
-
-            val SchemaPath sp = node.path
-            val List<QName> names = sp.path
-            val List<QName> newNames = new ArrayList(names)
-            newNames.remove(newNames.size - 1)
-            val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)
-            parent = findDataSchemaNode(schemaContext, newSp)
-
-            do {
-                tmpPath.add(currentName);
-                if (parent instanceof DataNodeContainer) {
-                    val dataNodeParent = parent as DataNodeContainer;
-                    for (u : dataNodeParent.uses) {
-                        if (result == null) {
-                            result = getResultFromUses(u, currentName.localName)
-                        }
-                    }
-                }
-                if (result == null) {
-                    currentName = (parent as SchemaNode).QName
-                    if (parent instanceof SchemaNode) {
-                        val SchemaPath nodeSp = (parent as SchemaNode).path
-                        val List<QName> nodeNames = nodeSp.path
-                        val List<QName> nodeNewNames = new ArrayList(nodeNames)
-                        nodeNewNames.remove(nodeNewNames.size - 1)
-                        if (nodeNewNames.empty) {
-                            parent = getParentModule(parent as SchemaNode)
-                        } else {
-                            val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute)
-                            parent = findDataSchemaNode(schemaContext, nodeNewSp)
-                        }
-                    } else {
-                        throw new IllegalArgumentException("Failed to generate code for augment")
-                    }
-                }
-            } while (result == null && !(parent instanceof Module));
-
-            if (result != null) {
-                result = getTargetNode(tmpPath, result)
-            }
-            return result;
-        }
-    }
-
-    private def DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node, AugmentationSchema parentNode,
-        List<SchemaNode> dataTree) {
-
-        var DataSchemaNode result = null;
-        var QName currentName = node.QName
-        var tmpPath = new ArrayList<QName>()
-        tmpPath.add(currentName)
-        var int i = 1;
-        var Object parent = null
-
-        do {
-            if (dataTree.size < 2 || dataTree.size == i) {
-                parent = parentNode
-            } else {
-                parent = dataTree.get(dataTree.size - (i+1))
-                tmpPath.add((parent as SchemaNode).QName)
-            }
-
-            val dataNodeParent = parent as DataNodeContainer;
-            for (u : dataNodeParent.uses) {
-                if (result == null) {
-                    result = getResultFromUses(u, currentName.localName)
-                }
-            }
-            if (result == null) {
-                i = i + 1
-                currentName = (parent as SchemaNode).QName
-            }
-        } while (result == null);
-
-        if (result != null) {
-            result = getTargetNode(tmpPath, result)
-        }
-        return result;
-    }
-
-    private def getResultFromUses(UsesNode u, String currentName) {
-        var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path)
-        if (!(targetGrouping instanceof GroupingDefinition)) {
-            throw new IllegalArgumentException("Failed to generate code for augment in " + u)
-        }
-        var gr = targetGrouping as GroupingDefinition
-        return gr.getDataChildByName(currentName)
-    }
-
-    private def getTargetNode(List<QName> tmpPath, DataSchemaNode node) {
-        var DataSchemaNode result = node
-        if (tmpPath.size == 1) {
-            if (result != null && result.addedByUses) {
-                result = findOriginal(result);
-            }
-            return result;
-        } else {
-            var DataSchemaNode newParent = result;
-            Collections.reverse(tmpPath);
-
-            tmpPath.remove(0);
-            for (name : tmpPath) {
-                // searching by local name is must, because node has different namespace in its original location
-                if (newParent instanceof DataNodeContainer) {
-                    newParent = (newParent as DataNodeContainer).getDataChildByName(name.localName);
-                } else {
-                    newParent = (newParent as ChoiceNode).getCaseNodeByName(name.localName);
-                }
-            }
-            if (newParent != null && newParent.addedByUses) {
-                newParent = findOriginal(newParent);
-            }
-            return newParent;
-        }
-    }
-
-
     /**
      * Convenient method to find node added by uses statement.
      */
@@ -1356,7 +1131,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath)
                         if (targetSchemaNode instanceof DataSchemaNode &&
                             (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
-                            targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
+                            targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode, schemaContext);
                             if (targetSchemaNode == null) {
                                 throw new NullPointerException(
                                     "Failed to find target node from grouping for augmentation " + augSchema +
@@ -2114,13 +1889,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null
     }
 
-    private def Module getParentModule(SchemaNode node) {
-        val QName qname = node.getPath().getPath().get(0);
-        val URI namespace = qname.getNamespace();
-        val Date revision = qname.getRevision();
-        return schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
-    }
-
     public def getModuleContexts() {
         genCtx;
     }
index 93969b798c1a756468189a6568dd8164fcc14fe4..a761f9aa90d47683b65f327034eedde4a2c2e6e0 100644 (file)
@@ -478,8 +478,16 @@ public class LazyGeneratedCodecRegistry implements //
     }
 
     private void tryToCreateCasesCodecs(ChoiceNode schema) {
-        for (ChoiceCaseNode caseNode : schema.getCases()) {
+        for (ChoiceCaseNode choiceCase : schema.getCases()) {
+            ChoiceCaseNode caseNode = choiceCase;
+            if (caseNode.isAddedByUses()) {
+                DataSchemaNode origCaseNode = SchemaContextUtil.findOriginal(caseNode, currentSchema);
+                if (origCaseNode instanceof ChoiceCaseNode) {
+                    caseNode = (ChoiceCaseNode) origCaseNode;
+                }
+            }
             SchemaPath path = caseNode.getPath();
+
             GeneratedTypeBuilder type;
             if (path != null && (type = pathToType.get(path)) != null) {
                 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
@@ -640,6 +648,7 @@ public class LazyGeneratedCodecRegistry implements //
     private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
             Delegator<BindingCodec> {
         private boolean augmenting;
+        private boolean uses;
         private BindingCodec delegate;
 
         private Set<String> validNames;
@@ -656,6 +665,7 @@ public class LazyGeneratedCodecRegistry implements //
                 validNames.add(qname.getLocalName());
             }
             augmenting = caseNode.isAugmenting();
+            uses = caseNode.isAddedByUses();
         }
 
         public ChoiceCaseCodecImpl() {
@@ -693,7 +703,7 @@ public class LazyGeneratedCodecRegistry implements //
         @Override
         public boolean isAcceptable(Node<?> input) {
             if (input instanceof CompositeNode) {
-                if (augmenting) {
+                if (augmenting && !uses) {
                     return checkAugmenting((CompositeNode) input);
                 } else {
                     return checkLocal((CompositeNode) input);
index 9b3a516cbe6a647b17114e669cbe06b0957869a0..cd5d93a5648b1d187708ad91f4c7bf2fa5c2c1db 100644 (file)
@@ -160,13 +160,10 @@ class TransformerGenerator {
             if (typeSpecBuilder == null) {
                 typeSpecBuilder = pathToType.get(node.path);
             }
-            var schemaNode = typeToSchemaNode.get(ref);
-            if (schemaNode === null) {
-                schemaNode = node;
-            }
+
             checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
             val typeSpec = typeSpecBuilder.toInstance();
-            val newret = generateTransformerFor(inputType, typeSpec, schemaNode);
+            val newret = generateTransformerFor(inputType, typeSpec, node);
             listener.onClassProcessed(inputType);
             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
         ]
diff --git a/integration-test/bug527-test-model/pom.xml b/integration-test/bug527-test-model/pom.xml
new file mode 100644 (file)
index 0000000..a9f516a
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2013 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 -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.opendaylight.yangtools.model</groupId>
+        <artifactId>model-parent</artifactId>
+        <version>0.6.2-SNAPSHOT</version>
+        <relativePath>../../model/pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.opendaylight.yangtools</groupId>
+    <artifactId>bug527-test-model</artifactId>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
+
diff --git a/integration-test/bug527-test-model/src/main/yang/bar.yang b/integration-test/bug527-test-model/src/main/yang/bar.yang
new file mode 100644 (file)
index 0000000..d40faad
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2013 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
+ */
+module bar {
+    yang-version 1;
+    namespace "urn:yang:bar";
+    prefix "bar";
+
+    revision "2014-03-21" {
+    }
+
+    container alpha {
+        container beta {
+        }
+    }
+
+    grouping group-a {
+        container xcont {
+            choice xchoice {
+            }
+        }
+    }
+
+    grouping group-b {
+        uses group-a {
+            augment "xcont/xchoice" {
+                case xcase {
+                    leaf idx {
+                        type string;
+                    }
+                }
+            }
+        }
+    }
+
+}
diff --git a/integration-test/bug527-test-model/src/main/yang/foo.yang b/integration-test/bug527-test-model/src/main/yang/foo.yang
new file mode 100644 (file)
index 0000000..0db6231
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2013 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
+ */
+module foo {
+    yang-version 1;
+    namespace "urn:yang:foo";
+    prefix "foo";
+
+    import bar {
+        prefix bar;
+    }
+
+    revision "2014-03-21" {
+    }
+
+
+
+    augment "/bar:alpha/bar:beta" {
+        uses bar:group-b;
+    }
+
+}
+
index 02a92720c27f93a12aa06be1232c190382877e4a..6e71866664ad6f6acc250414b6b7f32c678370d6 100644 (file)
@@ -18,6 +18,7 @@
     <packaging>pom</packaging>
 
     <modules>
+        <module>bug527-test-model</module>
         <module>regression-test-model</module>
         <module>yang-runtime-tests</module>
     </modules>
index 3174f7ca0e81cab9bfae16b8b3eb10882ebea891..06c4863a07e3dba0adf81e538cb5c16659031146 100644 (file)
@@ -1,14 +1,11 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- Copyright (c) 2013 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
--->
+<!-- Copyright (c) 2013 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 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>binding-generator-impl</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>bug527-test-model</artifactId>
+            <version>0.6.2-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/Bug527Test.java b/restconf/restconf-util/src/test/java/org/opendaylight/yangtools/restconf/utils/Bug527Test.java
new file mode 100644 (file)
index 0000000..2f60871
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014 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.restconf.utils;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.*;
+
+import java.io.InputStream;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.Alpha;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.alpha.Beta;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.group.a.xcont.Xchoice;
+import org.opendaylight.yang.gen.v1.urn.yang.bar.rev140321.group.b.xcont.xchoice.Xcase;
+import org.opendaylight.yang.gen.v1.urn.yang.foo.rev140321.Beta1;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+
+public class Bug527Test {
+
+    private RuntimeGeneratedMappingServiceImpl mappingService;
+
+    @Before
+    public void setup() {
+        this.mappingService = new RuntimeGeneratedMappingServiceImpl();
+        this.mappingService.setPool(new ClassPool());
+        this.mappingService.init();
+
+        final ModuleInfoBackedContext moduleInfo = ModuleInfoBackedContext.create();
+        moduleInfo.addModuleInfos(BindingReflections.loadModuleInfos());
+        this.mappingService.onGlobalContextUpdated(moduleInfo.tryToCreateSchemaContext().get());
+    }
+
+    @Test
+    public void testToDataObjectMappingWithNestedAugmentations() {
+        InstanceIdentifier<Alpha> alphaId = InstanceIdentifier.builder(Alpha.class).toInstance();
+        InputStream is = this.getClass().getClassLoader().getResourceAsStream("topology-bug527.xml");
+        DataSchemaNode dataSchema = RestconfUtils.toRestconfIdentifier(alphaId, mappingService,
+                mappingService.getSchemaContext()).getValue();
+        Alpha alpha = (Alpha) RestconfUtils.dataObjectFromInputStream(alphaId, is, mappingService.getSchemaContext(),
+                mappingService, dataSchema);
+        assertNotNull(alpha);
+
+        Beta beta = alpha.getBeta();
+        Beta1 beta1 = beta.getAugmentation(Beta1.class);
+
+        Xchoice xchoice = beta1.getXcont().getXchoice();
+        assertNotNull(xchoice);
+
+        Xcase acase = (Xcase) xchoice;
+        assertEquals("idx2", acase.getIdx());
+    }
+
+}
diff --git a/restconf/restconf-util/src/test/resources/topology-bug527.xml b/restconf/restconf-util/src/test/resources/topology-bug527.xml
new file mode 100644 (file)
index 0000000..938717b
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright (c) 2013 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 -->
+<alpha xmlns="urn:yang:bar">
+    <beta>
+        <xcont xmlns="urn:yang:foo">
+            <idx>idx2</idx>
+        </xcont>
+    </beta>
+</alpha>
index 1d7813f2baf0951a086f84c75bcede6d9faf29f8..14f495058152d09fcac15b1ce5edd490f3003b59 100644 (file)
@@ -7,28 +7,17 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
-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.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.*;
 
 import com.google.common.base.Preconditions;
 
@@ -392,6 +381,244 @@ public class SchemaContextUtil {
         return null;
     }
 
+    /**
+     * Utility method which search for original node defined in grouping.
+     *
+     * @param node
+     * @return
+     */
+    public static DataSchemaNode findOriginal(DataSchemaNode node, SchemaContext ctx) {
+        DataSchemaNode result = findCorrectTargetFromGrouping(node, ctx);
+        if (result == null) {
+            result = findCorrectTargetFromAugment(node, ctx);
+            if (result != null) {
+                if (result.isAddedByUses()) {
+                    result = findOriginal(result, ctx);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node, SchemaContext ctx) {
+        if (node.getPath().getPath().size() == 1) {
+            // uses is under module statement
+            Module m = findParentModule(ctx, node);
+            DataSchemaNode result = null;
+            for (UsesNode u : m.getUses()) {
+                SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
+                if (!(targetGrouping instanceof GroupingDefinition)) {
+                    throw new IllegalArgumentException("Failed to generate code for augment in " + u);
+                }
+                GroupingDefinition gr = (GroupingDefinition) targetGrouping;
+                result = gr.getDataChildByName(node.getQName().getLocalName());
+            }
+            if (result == null) {
+                throw new IllegalArgumentException("Failed to generate code for augment");
+            }
+            return result;
+        } else {
+            DataSchemaNode result = null;
+            QName currentName = node.getQName();
+            List<QName> tmpPath = new ArrayList<>();
+            Object parent = null;
+
+            SchemaPath sp = node.getPath();
+            List<QName> names = sp.getPath();
+            List<QName> newNames = new ArrayList<>(names);
+            newNames.remove(newNames.size() - 1);
+            SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
+            parent = findDataSchemaNode(ctx, newSp);
+
+            do {
+                tmpPath.add(currentName);
+                if (parent instanceof DataNodeContainer) {
+                    DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
+                    for (UsesNode u : dataNodeParent.getUses()) {
+                        if (result == null) {
+                            result = getResultFromUses(u, currentName.getLocalName(), ctx);
+                        }
+                    }
+                }
+                if (result == null) {
+                    currentName = ((SchemaNode) parent).getQName();
+                    if (parent instanceof SchemaNode) {
+                        SchemaPath nodeSp = ((SchemaNode) parent).getPath();
+                        List<QName> nodeNames = nodeSp.getPath();
+                        List<QName> nodeNewNames = new ArrayList<>(nodeNames);
+                        nodeNewNames.remove(nodeNewNames.size() - 1);
+                        if (nodeNewNames.isEmpty()) {
+                            parent = getParentModule((SchemaNode) parent, ctx);
+                        } else {
+                            SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.isAbsolute());
+                            parent = findDataSchemaNode(ctx, nodeNewSp);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Failed to generate code for augment");
+                    }
+                }
+            } while (result == null && !(parent instanceof Module));
+
+            if (result != null) {
+                result = getTargetNode(tmpPath, result, ctx);
+            }
+            return result;
+        }
+    }
+
+    private static DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node, SchemaContext ctx) {
+        if (!node.isAugmenting()) {
+            return null;
+        }
+
+        QName currentName = node.getQName();
+        Object currentNode = node;
+        Object parent = node;
+        List<QName> tmpPath = new ArrayList<QName>();
+        List<SchemaNode> tmpTree = new ArrayList<SchemaNode>();
+
+        AugmentationSchema augment = null;
+        do {
+            SchemaPath sp = ((SchemaNode) parent).getPath();
+            List<QName> names = sp.getPath();
+            List<QName> newNames = new ArrayList<>(names);
+            newNames.remove(newNames.size() - 1);
+            SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
+            parent = findDataSchemaNode(ctx, newSp);
+            if (parent instanceof AugmentationTarget) {
+                tmpPath.add(currentName);
+                tmpTree.add((SchemaNode) currentNode);
+                augment = findNodeInAugment(((AugmentationTarget) parent).getAvailableAugmentations(), currentName);
+                if (augment == null) {
+                    currentName = ((DataSchemaNode) parent).getQName();
+                    currentNode = parent;
+                }
+            }
+        } while (((DataSchemaNode) parent).isAugmenting() && augment == null);
+
+        if (augment == null) {
+            return null;
+        } else {
+            Collections.reverse(tmpPath);
+            Collections.reverse(tmpTree);
+            Object actualParent = augment;
+            DataSchemaNode result = null;
+            for (QName name : tmpPath) {
+                if (actualParent instanceof DataNodeContainer) {
+                    result = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
+                    actualParent = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
+                } else {
+                    if (actualParent instanceof ChoiceNode) {
+                        result = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
+                        actualParent = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
+                    }
+                }
+            }
+
+            if (result.isAddedByUses()) {
+                result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree, ctx);
+            }
+
+            return result;
+        }
+    }
+
+    private static DataSchemaNode getResultFromUses(UsesNode u, String currentName, SchemaContext ctx) {
+        SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
+        if (!(targetGrouping instanceof GroupingDefinition)) {
+            throw new IllegalArgumentException("Failed to generate code for augment in " + u);
+        }
+        GroupingDefinition gr = (GroupingDefinition) targetGrouping;
+        return gr.getDataChildByName(currentName);
+    }
+
+    private static Module getParentModule(SchemaNode node, SchemaContext ctx) {
+        QName qname = node.getPath().getPath().get(0);
+        URI namespace = qname.getNamespace();
+        Date revision = qname.getRevision();
+        return ctx.findModuleByNamespaceAndRevision(namespace, revision);
+    }
+
+    private static DataSchemaNode getTargetNode(List<QName> tmpPath, DataSchemaNode node, SchemaContext ctx) {
+        DataSchemaNode result = node;
+        if (tmpPath.size() == 1) {
+            if (result != null && result.isAddedByUses()) {
+                result = findOriginal(result, ctx);
+            }
+            return result;
+        } else {
+            DataSchemaNode newParent = result;
+            Collections.reverse(tmpPath);
+
+            tmpPath.remove(0);
+            for (QName name : tmpPath) {
+                // searching by local name is must, because node has different
+                // namespace in its original location
+                if (newParent == null) {
+                    break;
+                }
+                if (newParent instanceof DataNodeContainer) {
+                    newParent = ((DataNodeContainer) newParent).getDataChildByName(name.getLocalName());
+                } else {
+                    newParent = ((ChoiceNode) newParent).getCaseNodeByName(name.getLocalName());
+                }
+            }
+            if (newParent != null && newParent.isAddedByUses()) {
+                newParent = findOriginal(newParent, ctx);
+            }
+            return newParent;
+        }
+    }
+
+    private static AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
+        for (AugmentationSchema augment : augments) {
+            DataSchemaNode node = augment.getDataChildByName(name);
+            if (node != null) {
+                return augment;
+            }
+        }
+        return null;
+    }
+
+    private static DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node,
+            AugmentationSchema parentNode, List<SchemaNode> dataTree, SchemaContext ctx) {
+
+        DataSchemaNode result = null;
+        QName currentName = node.getQName();
+        List<QName> tmpPath = new ArrayList<>();
+        tmpPath.add(currentName);
+        int i = 1;
+        Object parent = null;
+
+        do {
+            if (dataTree.size() < 2 || dataTree.size() == i) {
+                parent = parentNode;
+            } else {
+                parent = dataTree.get(dataTree.size() - (i + 1));
+                tmpPath.add(((SchemaNode) parent).getQName());
+            }
+
+            if (parent instanceof DataNodeContainer) {
+                DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
+                for (UsesNode u : dataNodeParent.getUses()) {
+                    if (result == null) {
+                        result = getResultFromUses(u, currentName.getLocalName(), ctx);
+                    }
+                }
+            }
+
+            if (result == null) {
+                i = i + 1;
+                currentName = ((SchemaNode) parent).getQName();
+            }
+        } while (result == null);
+
+        if (result != null) {
+            result = getTargetNode(tmpPath, result, ctx);
+        }
+        return result;
+    }
+
     /**
      * 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
index 1ad6ca37527984221c66d159b4e7166ee8abff0e..7448f130b2c3f615ab22d4e2f695b7ccc4bd1879 100644 (file)
@@ -854,7 +854,7 @@ public final class YangParserImpl implements YangModelParser {
                 newPath.add(new QName(ns, rev, localPrefix, qn.getLocalName()));
             }
         }
-        augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
+        augment.setTargetNodeSchemaPath(new SchemaPath(newPath, true));
 
         for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
             correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());