Bug 2333 - Java code generation error, when yang model contains Choice node 84/19784/2
authorpkajsa <pkajsa@cisco.com>
Thu, 13 Nov 2014 13:51:20 +0000 (14:51 +0100)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 12 May 2015 12:47:03 +0000 (12:47 +0000)
in module body at top level

BindingGeneratorImpl fails (NoSuchElementException) during java source code
generation from yang model which contains Choice node directly in module body
at top level. The parent path of Choice node is empty (because the parent
is the module) and therefore iterator.next() on the path fails. For more
information see Bug 2333.

Change-Id: I6e617eca91bb5d8d2b91ad058a4df5c2793ec81d
Signed-off-by: pkajsa <pkajsa@cisco.com>
(cherry picked from commit 9af32f6d5f9da9f384d491e5066ea2423763e9c9)

code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImplTest.java [new file with mode: 0644]
code-generator/binding-generator-impl/src/test/resources/binding-generator-impl-test/choice-test.yang [new file with mode: 0644]

index 15b818e43ddbb9754eb159349c8ed63ca3831ce4..995d5ab1c10d30c451439612ec8153e35b6c3a68 100644 (file)
@@ -25,7 +25,6 @@ import static org.opendaylight.yangtools.binding.generator.util.Types.typeForCla
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
-
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
@@ -1220,37 +1219,40 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
                 final Iterable<DataSchemaNode> caseChildNodes = caseNode.getChildNodes();
                 if (caseChildNodes != null) {
-                    final SchemaPath nodeSp = choiceNode.getPath();
-                    final Object parentNode = findDataSchemaNode(schemaContext, nodeSp.getParent());
-
-                    SchemaNode parent;
-                    if (parentNode instanceof AugmentationSchema) {
-                        final AugmentationSchema augSchema = (AugmentationSchema) parentNode;
-                        final SchemaPath targetPath = augSchema.getTargetPath();
-                        SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
-                        if (targetSchemaNode instanceof DataSchemaNode
-                                && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-                            if (targetSchemaNode instanceof DerivableSchemaNode) {
-                                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
-                            }
-                            if (targetSchemaNode == null) {
-                                throw new IllegalStateException(
-                                        "Failed to find target node from grouping for augmentation " + augSchema
-                                        + " in module " + module.getName());
+                    final SchemaPath choiceNodeParentPath = choiceNode.getPath().getParent();
+
+                    if (!Iterables.isEmpty(choiceNodeParentPath.getPathFromRoot())) {
+                        SchemaNode parent = findDataSchemaNode(schemaContext, choiceNodeParentPath);
+
+                        if (parent instanceof AugmentationSchema) {
+                            final AugmentationSchema augSchema = (AugmentationSchema) parent;
+                            final SchemaPath targetPath = augSchema.getTargetPath();
+                            SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
+                            if (targetSchemaNode instanceof DataSchemaNode
+                                    && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
+                                if (targetSchemaNode instanceof DerivableSchemaNode) {
+                                    targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+                                }
+                                if (targetSchemaNode == null) {
+                                    throw new IllegalStateException(
+                                            "Failed to find target node from grouping for augmentation " + augSchema
+                                                    + " in module " + module.getName());
+                                }
                             }
+                            parent = targetSchemaNode;
                         }
-                        parent = targetSchemaNode;
-                    } else {
-                        final SchemaPath sp = choiceNode.getPath();
-                        parent = findDataSchemaNode(schemaContext, sp.getParent());
-                    }
-                    Preconditions.checkState(parent != null, "Could not find Choice node parent "+choiceNode.getPath().getParent());
-                    GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
-                    if (childOfType == null) {
-                        childOfType = findGroupingByPath(parent.getPath());
-                    }
-                    resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
-                }
+
+                        Preconditions.checkState(parent != null, "Could not find Choice node parent %s",
+                                choiceNodeParentPath);
+                        GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
+                        if (childOfType == null) {
+                            childOfType = findGroupingByPath(parent.getPath());
+                        }
+                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
+                    } else
+                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, moduleToDataType(module),
+                                caseChildNodes);
+               }
             }
             processUsesAugments(caseNode, module);
         }
diff --git a/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImplTest.java b/code-generator/binding-generator-impl/src/test/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImplTest.java
new file mode 100644 (file)
index 0000000..c926c77
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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.sal.binding.generator.impl;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class BindingGeneratorImplTest {
+
+    @Test
+    public void choiceNodeGenerationTest() throws IOException,
+            YangSyntaxErrorException, URISyntaxException {
+        File resourceFile = new File(getClass().getResource(
+                "/binding-generator-impl-test/choice-test.yang").toURI());
+        File resourceDir = resourceFile.getParentFile();
+
+        YangParserImpl parser = YangParserImpl.getInstance();
+        SchemaContext context = parser.parseFile(resourceFile, resourceDir);
+
+        List<Type> generateTypes = new BindingGeneratorImpl(false)
+                .generateTypes(context);
+
+        GeneratedType choiceTestData = null;
+        GeneratedType myRootContainer = null;
+        GeneratedType myList = null;
+        GeneratedType myContainer = null;
+        GeneratedType myList2 = null;
+        GeneratedType myContainer2 = null;
+
+        for (Type type : generateTypes) {
+            switch (type.getName()) {
+            case "ChoiceTestData":
+                choiceTestData = (GeneratedType) type;
+                break;
+            case "Myrootcontainer":
+                myRootContainer = (GeneratedType) type;
+                break;
+            case "Mylist":
+                myList = (GeneratedType) type;
+                break;
+            case "Mylist2":
+                myList2 = (GeneratedType) type;
+                break;
+            case "Mycontainer":
+                myContainer = (GeneratedType) type;
+                break;
+            case "Mycontainer2":
+                myContainer2 = (GeneratedType) type;
+                break;
+            }
+        }
+
+        assertNotNull(choiceTestData);
+        assertNotNull(myRootContainer);
+        assertNotNull(myList);
+        assertNotNull(myContainer);
+        assertNotNull(myList2);
+        assertNotNull(myContainer2);
+
+        List<Type> implements1 = myContainer.getImplements();
+        Type childOfParamType = null;
+        for (Type type : implements1) {
+            if (type.getName().equals("ChildOf")) {
+                childOfParamType = ((ParameterizedType) type)
+                        .getActualTypeArguments()[0];
+                break;
+            }
+        }
+        assertNotNull(childOfParamType);
+        assertTrue(childOfParamType.getName().equals("ChoiceTestData"));
+
+        implements1 = myList.getImplements();
+        childOfParamType = null;
+        for (Type type : implements1) {
+            if (type.getName().equals("ChildOf")) {
+                childOfParamType = ((ParameterizedType) type)
+                        .getActualTypeArguments()[0];
+                break;
+            }
+        }
+        assertNotNull(childOfParamType);
+        assertTrue(childOfParamType.getName().equals("ChoiceTestData"));
+
+        implements1 = myContainer2.getImplements();
+        childOfParamType = null;
+        for (Type type : implements1) {
+            if (type.getName().equals("ChildOf")) {
+                childOfParamType = ((ParameterizedType) type)
+                        .getActualTypeArguments()[0];
+                break;
+            }
+        }
+        assertNotNull(childOfParamType);
+        assertTrue(childOfParamType.getName().equals("Myrootcontainer"));
+
+        implements1 = myList2.getImplements();
+        childOfParamType = null;
+        for (Type type : implements1) {
+            if (type.getName().equals("ChildOf")) {
+                childOfParamType = ((ParameterizedType) type)
+                        .getActualTypeArguments()[0];
+                break;
+            }
+        }
+        assertNotNull(childOfParamType);
+        assertTrue(childOfParamType.getName().equals("Myrootcontainer"));
+
+    }
+
+}
diff --git a/code-generator/binding-generator-impl/src/test/resources/binding-generator-impl-test/choice-test.yang b/code-generator/binding-generator-impl/src/test/resources/binding-generator-impl-test/choice-test.yang
new file mode 100644 (file)
index 0000000..6b8ff93
--- /dev/null
@@ -0,0 +1,47 @@
+module choice-test {
+    yang-version 1;
+    namespace "uri:choice-test";
+    prefix tst;
+
+    revision 2014-10-07 {
+        description
+                "Choice test.";
+    }
+
+    choice mychoice {
+        case one {
+            container mycontainer {
+                leaf mychoiceleafone {
+                    type string;
+                }
+            }
+        }
+        case two {
+            list mylist {
+                leaf mychoiceleaftwo {
+                    type int16;
+                }
+            }
+        }
+    }
+
+    container myrootcontainer {
+        choice mychoice2 {
+            case one2 {
+                container mycontainer2 {
+                    leaf mychoiceleafone2 {
+                        type string;
+                    }
+                }
+            }
+            case two2 {
+                list mylist2 {
+                    leaf mychoiceleaftwo2 {
+                        type int16;
+                    }
+                }
+            }
+        }
+    }
+}
+