Projects moved under correct parent. 93/693/1
authorMartin Vitez <mvitez@cisco.com>
Fri, 19 Jul 2013 09:15:10 +0000 (11:15 +0200)
committerMartin Vitez <mvitez@cisco.com>
Wed, 24 Jul 2013 11:44:54 +0000 (13:44 +0200)
Moved code-generator/maven-yang -> yang/.
Moved code-generator/maven-yang-plugin -> yang/.
Moved code-generator/maven-yang-plugin-it -> yang/.
Moved code-generator/yang-model-parser-api -> yang/.
Moved code-generator/yang-model-parser-impl -> yang/.

Configured site plugin for project. Fixed some javadocs.
Fixed bug in ParserUtils causing NullPointerException.
Fixed bug in resolving uses statement.
Improved tests.

Change-Id: Ia7567544fbe006f0cf87055c6633c04b5ce2c50e
Signed-off-by: Martin Vitez <mvitez@cisco.com>
155 files changed:
maven-yang-plugin-it/.gitignore [new file with mode: 0644]
maven-yang-plugin-it/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTestIT.java [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/AdditionalConfig/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/Correct/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest1/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile1.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile2.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile3.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest2/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/GenerateTest2/yang/private.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/Generator/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/MissingYangInDep/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/MissingYangInDep/yang/private.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/NoGenerators/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/NoOutputDir/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/YangRootNotExist/pom.xml [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/files/testfile1.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/files/testfile2.yang [new file with mode: 0644]
maven-yang-plugin-it/src/test/resources/files/testfile3.yang [new file with mode: 0644]
maven-yang-plugin/pom.xml [new file with mode: 0644]
maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java [new file with mode: 0644]
maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java [new file with mode: 0644]
maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java [new file with mode: 0644]
maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesProcessor.java [new file with mode: 0644]
maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java [new file with mode: 0644]
maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java [new file with mode: 0644]
maven-yang-plugin/src/test/resources/yang/mock.yang [new file with mode: 0644]
maven-yang/pom.xml [new file with mode: 0644]
maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java [new file with mode: 0644]
maven-yang/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java [new file with mode: 0644]
pom.xml
src/site/site.xml [new file with mode: 0644]
yang-binding/pom.xml
yang-common/pom.xml
yang-data-api/pom.xml
yang-data-impl/pom.xml
yang-data-util/pom.xml
yang-ext/pom.xml
yang-model-api/pom.xml
yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/type/DecimalTypeDefinition.java
yang-model-parser-api/pom.xml [new file with mode: 0644]
yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/YangModelParser.java [new file with mode: 0644]
yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/package-info.java [new file with mode: 0644]
yang-model-parser-impl/pom.xml [new file with mode: 0644]
yang-model-parser-impl/src/main/antlr/YangLexer.g4 [new file with mode: 0644]
yang-model-parser-impl/src/main/antlr/YangParser.g4 [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractTypeAwareBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationSchemaBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationTargetBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/Builder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataNodeContainerBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingMember.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/SchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeAwareBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeDefinitionBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/UsesNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AnyXmlBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AugmentationSchemaBuilderImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceCaseBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ConstraintsBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ContainerSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/DeviationBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ExtensionBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/FeatureBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/GroupingBuilderImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentitySchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentityrefTypeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ListSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ModuleBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/NotificationBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/RpcDefinitionBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnionTypeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnknownSchemaNodeBuilder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UsesNodeBuilderImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/SchemaContextImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangErrorListener.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserListenerImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/BitImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/Comparators.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySort.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/MustDefinitionImpl.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserListenerUtils.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserUtils.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineHolder.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineUtils.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TopologicalSort.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TypeConstraints.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/UnknownBoundaryNumber.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangParseException.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangValidationException.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/BasicValidations.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/ValidationUtil.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidationListener.java [new file with mode: 0644]
yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidator.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/AugmentTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/GroupingTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TestUtils.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TypesResolutionTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserNegativeTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserWithContextTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySortTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/TopologicalSortTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationListTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationModuleTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationSubModuleTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationTest.java [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-augment-test/test1.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-augment-test/test2.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-augment-test/test3.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-augment-test/test4.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-test/deviation-test.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-test/test1.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-test/test2.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/context-test/test3.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/model/custom.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/model/nodes.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/model/types.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment0.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment1.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment2.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-leaf.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-list.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/identity.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/typedef.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile0.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile1.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile2.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile3.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile4.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile5.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/negative-scenario/testfile6.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/iana-afn-safi@2012-06-04.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/iana-if-type@2012-06-05.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/iana-timezones@2012-07-09.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/ietf-inet-types@2010-09-24.yang [new file with mode: 0644]
yang-model-parser-impl/src/test/resources/types/ietf-yang-types@2010-09-24.yang [new file with mode: 0644]
yang-model-util/pom.xml
yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java
yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/BitsType.java

diff --git a/maven-yang-plugin-it/.gitignore b/maven-yang-plugin-it/.gitignore
new file mode 100644 (file)
index 0000000..f63984a
--- /dev/null
@@ -0,0 +1,2 @@
+log.txt
+/target
diff --git a/maven-yang-plugin-it/pom.xml b/maven-yang-plugin-it/pom.xml
new file mode 100644 (file)
index 0000000..bec1acb
--- /dev/null
@@ -0,0 +1,36 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>yang</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.5.4-SNAPSHOT</version>
+    </parent>
+    <artifactId>yang-maven-plugin-it</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.shared</groupId>
+            <artifactId>maven-verifier</artifactId>
+            <version>1.4</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <version>2.6</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTestIT.java b/maven-yang-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTestIT.java
new file mode 100644 (file)
index 0000000..bbece72
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin.it;
+
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import java.io.File;
+import java.net.URL;
+
+import org.apache.maven.it.VerificationException;
+import org.apache.maven.it.Verifier;
+import org.junit.Test;
+
+public class YangToSourcesPluginTestIT {
+
+    // TODO Test yang files in transitive dependencies
+
+    @Test
+    public void testYangRootNotExist() {
+        try {
+            setUp("YangRootNotExist/", false);
+        } catch (VerificationException e) {
+            assertVerificationException(e,
+                    "[ERROR] yang-to-sources: Unable to parse yang files from ");
+            assertVerificationException(
+                    e,
+                    "Caused by: org.apache.maven.plugin.MojoExecutionException: yang-to-sources: Unable to parse yang files from ");
+            return;
+        }
+
+        fail("Verification exception should have been thrown");
+    }
+
+    @Test
+    public void testCorrect() throws VerificationException {
+        Verifier v = setUp("Correct/", false);
+        verifyCorrectLog(v);
+    }
+
+    @Test
+    public void testAdditionalConfiguration() throws VerificationException {
+        Verifier v = setUp("AdditionalConfig/", false);
+        v.verifyTextInLog("[DEBUG] yang-to-sources: Additional configuration picked up for : org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: {nm1=abcd=a.b.c.d, nm2=abcd2=a.b.c.d.2}");
+        v.verifyTextInLog("[DEBUG] yang-to-sources: Additional configuration picked up for : org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: {c1=config}");
+        v.verifyTextInLog(File.separator
+                + "files marked as resources: META-INF/yang");
+        v.verifyTextInLog("target"
+                + File.separator
+                + "generated-resources marked as resources for generator: org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+    }
+
+    @Test
+    public void testMissingYangInDep() throws VerificationException {
+        try {
+            setUp("MissingYangInDep/", false);
+        } catch (VerificationException e) {
+            assertVerificationException(
+                    e,
+                    "org.opendaylight.controller.yang.parser.util.YangValidationException: Not existing module imported:unknownDep:2013-02-27 by:private:2013-02-27");
+            return;
+        }
+
+        fail("Verification exception should have been thrown");
+    }
+
+    static void verifyCorrectLog(Verifier v) throws VerificationException {
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[INFO] yang-to-sources: YANG files parsed from");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+    }
+
+    @Test
+    public void testNoGenerators() throws VerificationException {
+        Verifier v = setUp("NoGenerators/", false);
+        v.verifyErrorFreeLog();
+        v.verifyTextInLog("[WARNING] yang-to-sources: No code generators provided");
+    }
+
+    @Test
+    public void testUnknownGenerator() throws VerificationException {
+        Verifier v = setUp("UnknownGenerator/", true);
+        v.verifyTextInLog("[ERROR] yang-to-sources: Unable to generate sources with unknown generator");
+        v.verifyTextInLog("java.lang.ClassNotFoundException: unknown");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+        v.verifyTextInLog("[ERROR] yang-to-sources: One or more code generators failed, including failed list(generatorClass=exception) {unknown=java.lang.ClassNotFoundException}");
+    }
+
+    @Test
+    public void testNoYangFiles() throws VerificationException {
+        Verifier v = setUp("NoYangFiles/", false);
+        v.verifyTextInLog("[INFO] yang-to-sources: YANG files parsed from []");
+        v.verifyTextInLog("[INFO] yang-to-sources: Code generator instantiated from org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl");
+        v.verifyTextInLog("[INFO] yang-to-sources: Sources generated by org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl: null");
+    }
+
+    static void assertVerificationException(VerificationException e,
+            String string) {
+        assertThat(e.getMessage(), containsString(string));
+    }
+
+    static Verifier setUp(String project, boolean ignoreF)
+            throws VerificationException {
+        final URL path = YangToSourcesPluginTestIT.class.getResource("/"
+                + project + "pom.xml");
+        File parent = new File(path.getPath());
+        Verifier verifier = new Verifier(parent.getParent());
+        if (ignoreF)
+            verifier.addCliOption("-fn");
+        verifier.setMavenDebug(true);
+        verifier.executeGoal("generate-sources");
+        return verifier;
+    }
+
+    @Test
+    public void testNoOutputDir() throws VerificationException {
+        Verifier v = YangToSourcesPluginTestIT.setUp("NoOutputDir/", false);
+        verifyCorrectLog(v);
+    }
+
+    @Test
+    public void testFindResourceOnCp() throws VerificationException {
+        Verifier v1 = new Verifier(new File(getClass().getResource(
+                "/GenerateTest1/pom.xml").getPath()).getParent());
+        v1.executeGoal("clean");
+        v1.executeGoal("package");
+        v1.assertFilePresent("target/classes/META-INF/yang/testfile1.yang");
+        v1.assertFilePresent("target/classes/META-INF/yang/testfile2.yang");
+        v1.assertFilePresent("target/classes/META-INF/yang/testfile3.yang");
+
+        Verifier v2 = YangToSourcesPluginTestIT.setUp("GenerateTest2/", false);
+        v2.executeGoal("clean");
+        v2.executeGoal("package");
+        v2.assertFilePresent("target/classes/META-INF/yang/private.yang");
+        v2.assertFileNotPresent("target/classes/META-INF/yang/testfile1.yang");
+        v2.assertFileNotPresent("target/classes/META-INF/yang/testfile2.yang");
+        v2.assertFileNotPresent("target/classes/META-INF/yang/testfile3.yang");
+    }
+}
diff --git a/maven-yang-plugin-it/src/test/resources/AdditionalConfig/pom.xml b/maven-yang-plugin-it/src/test/resources/AdditionalConfig/pom.xml
new file mode 100644 (file)
index 0000000..c871bb1
--- /dev/null
@@ -0,0 +1,66 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+    <artifactId>test</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-maven-plugin-spi</artifactId>
+            <version>0.5.4-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <additionalConfiguration>
+                                        <nm1>abcd=a.b.c.d</nm1>
+                                        <nm2>abcd2=a.b.c.d.2</nm2>
+                                    </additionalConfiguration>
+                                    <resourceBaseDir>/target/resourcesGenerated</resourceBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <additionalConfiguration>
+                                        <c1>config</c1>
+                                    </additionalConfiguration>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/Correct/pom.xml b/maven-yang-plugin-it/src/test/resources/Correct/pom.xml
new file mode 100644 (file)
index 0000000..1deb202
--- /dev/null
@@ -0,0 +1,53 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+    <artifactId>test</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-maven-plugin-spi</artifactId>
+            <version>0.5.4-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest1/pom.xml b/maven-yang-plugin-it/src/test/resources/GenerateTest1/pom.xml
new file mode 100644 (file)
index 0000000..5842b0b
--- /dev/null
@@ -0,0 +1,45 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>generator-test1</artifactId>
+    <version>0.5.4-SNAPSHOT</version>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}/src/main/resources</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile1.yang b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile1.yang
new file mode 100644 (file)
index 0000000..5bf7ece
--- /dev/null
@@ -0,0 +1,23 @@
+module types1 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    import types2 {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+   import types3 {
+        prefix "t3";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile2.yang b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile2.yang
new file mode 100644 (file)
index 0000000..7f7b306
--- /dev/null
@@ -0,0 +1,176 @@
+module types2 {
+    yang-version 1;
+    namespace "urn:simple.types.data.demo";
+    prefix "t2";
+    
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+    
+    description "This is types-data test description";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+    typedef my-base-int32-type {
+        type int32 {
+            range "2..20";
+        }
+    }
+
+    typedef my-type1 {
+        type my-base-int32-type {
+            range "11..max";
+        }
+        units "mile";
+        default "11";
+    }
+    
+    typedef my-custom-string {
+        type string {
+            pattern "[a-k]*";
+            length "5..11";
+        }
+    }
+    
+    typedef my-string-type {
+        type my-custom-string {
+            length "5..10";
+        }
+    }
+    
+    typedef my-string-type2 {
+        type my-string-type {
+            pattern "[b-u]*";
+        }
+    }
+
+    typedef my-string-type-ext {
+        type my-string-type2 {
+            pattern "[e-z]*";
+        }
+    }
+
+    typedef my-int-type {
+        type int32 {
+            range "10..20";
+        }
+    }
+    
+    typedef my-int-type2 {
+        type my-int-type {
+            range "12..18";
+        }
+    }
+    
+    typedef my-int-type-ext {
+        type my-int-type2 {
+            range "14..16";
+        }
+    }
+    
+    typedef my-decimal-type {
+        type decimal64 {
+            fraction-digits 6;
+        }
+    }
+    
+    typedef my-decimal-type-ext {
+        type decimal64 {
+            fraction-digits 5;
+        }
+    }
+
+    typedef my-union {
+       type union {
+               type int16 {
+                       range "1..100";
+               }
+               type int32;
+       }
+    }
+
+    typedef my-union-ext {
+       type my-union;
+    }
+
+    typedef nested-union1 {
+       type nested-union2;
+    }
+
+    typedef nested-union2 {
+       type union {
+               type my-union-ext;
+               type string;
+       }
+    }
+
+    leaf if-name {
+        type leafref {
+            path "/interface/name";
+        }
+    }
+     
+    leaf name {
+        type string;
+    }
+     
+    leaf nested-type-leaf {
+        type my-type1;
+    }
+    
+    extension c-define {
+        description
+        "Takes as argument a name string.
+        Makes the code generator use the given name in the
+        #define.";
+        argument "name" {
+            yin-element "true";
+        }
+    }
+    
+    container system {
+        leaf user {
+            type string;
+        }
+    }
+    
+    grouping target {
+        leaf address {
+            type string;
+            description "Target IP address";
+        }
+        container port {
+            description "Target port container";
+        }
+    }
+
+    container peer {
+        container destination {
+            uses target {
+                refine address {
+                    default "1.2.3.4";
+                }
+                refine port {
+                    description "new port description updated by refine";
+                }
+            }
+        }
+    }
+    
+    container interfaces {
+         list ifEntry {
+             key "ifIndex";
+
+             leaf ifIndex {
+                 type uint32;
+                 units minutes;
+             }
+             
+             leaf ifMtu {
+                 type int32;
+             }
+         }
+    }
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile3.yang b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile3.yang
new file mode 100644 (file)
index 0000000..8e5b86a
--- /dev/null
@@ -0,0 +1,18 @@
+module types3 {
+    yang-version 1;
+    namespace "urn:simple.container.demo.test";
+    prefix "t3";
+
+    import types2 {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest2/pom.xml b/maven-yang-plugin-it/src/test/resources/GenerateTest2/pom.xml
new file mode 100644 (file)
index 0000000..501fd1d
--- /dev/null
@@ -0,0 +1,59 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+    <artifactId>generator-test2</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>generator-test1</artifactId>
+            <version>0.5.4-SNAPSHOT</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/../GenerateTest1/target/generator-test1-0.5.4-SNAPSHOT.jar</systemPath>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${project.basedir}/yang</yangFilesRootDir>
+                            <inspectDependencies>true</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/GenerateTest2/yang/private.yang b/maven-yang-plugin-it/src/test/resources/GenerateTest2/yang/private.yang
new file mode 100644 (file)
index 0000000..db346ca
--- /dev/null
@@ -0,0 +1,19 @@
+module private {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "p";
+
+    import types2 {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/Generator/pom.xml b/maven-yang-plugin-it/src/test/resources/Generator/pom.xml
new file mode 100644 (file)
index 0000000..b33abb3
--- /dev/null
@@ -0,0 +1,50 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>binding-generator</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.5.4-SNAPSHOT</version>
+    </parent>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/MissingYangInDep/pom.xml b/maven-yang-plugin-it/src/test/resources/MissingYangInDep/pom.xml
new file mode 100644 (file)
index 0000000..6e25e48
--- /dev/null
@@ -0,0 +1,59 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+    <artifactId>generator-test2</artifactId>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${project.basedir}/yang</yangFilesRootDir>
+                            <inspectDependencies>true</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                            <resourceProviders>
+                                <provider>
+                                    <resourceProviderClass>
+                                        org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </provider>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/MissingYangInDep/yang/private.yang b/maven-yang-plugin-it/src/test/resources/MissingYangInDep/yang/private.yang
new file mode 100644 (file)
index 0000000..8d7227b
--- /dev/null
@@ -0,0 +1,19 @@
+module private {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "p";
+
+    import unknownDep {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/NoGenerators/pom.xml b/maven-yang-plugin-it/src/test/resources/NoGenerators/pom.xml
new file mode 100644 (file)
index 0000000..5349154
--- /dev/null
@@ -0,0 +1,49 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.5.4-SNAPSHOT</version>
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                            </codeGenerators>
+                            <resourceProviders>
+                                <provider>
+                                    <resourceProviderClass>
+                                        org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl
+                                    </resourceProviderClass>
+                                    <outputBaseDir>
+                                        outDir/
+                                    </outputBaseDir>
+                                </provider>
+                            </resourceProviders>
+                        </configuration>
+                    </execution>
+                </executions>
+                               <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/NoOutputDir/pom.xml b/maven-yang-plugin-it/src/test/resources/NoOutputDir/pom.xml
new file mode 100644 (file)
index 0000000..b73a53e
--- /dev/null
@@ -0,0 +1,46 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml b/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml
new file mode 100644 (file)
index 0000000..df7519e
--- /dev/null
@@ -0,0 +1,49 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>${basedir}</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml b/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml
new file mode 100644 (file)
index 0000000..e8b6eca
--- /dev/null
@@ -0,0 +1,57 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>../files</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        unknown
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+
+                <dependencies>
+                    <dependency>
+                        <groupId>org.opendaylight.controller</groupId>
+                        <artifactId>yang-maven-plugin-spi</artifactId>
+                        <version>0.5.4-SNAPSHOT</version>
+                        <type>test-jar</type>
+                    </dependency>
+                </dependencies>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/YangRootNotExist/pom.xml b/maven-yang-plugin-it/src/test/resources/YangRootNotExist/pom.xml
new file mode 100644 (file)
index 0000000..af11a69
--- /dev/null
@@ -0,0 +1,40 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.opendaylight.controller</groupId>
+    <version>0.5.4-SNAPSHOT</version>
+
+    <artifactId>test</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>yang-maven-plugin</artifactId>
+                <version>0.5.4-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>generate-sources</goal>
+                        </goals>
+                        <configuration>
+                            <yangFilesRootDir>unknown</yangFilesRootDir>
+                            <inspectDependencies>false</inspectDependencies>
+                            <codeGenerators>
+                                <generator>
+                                    <codeGeneratorClass>
+                                        org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl
+                                    </codeGeneratorClass>
+                                    <outputBaseDir>
+                                        /outDir/
+                                    </outputBaseDir>
+                                </generator>
+                            </codeGenerators>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-yang-plugin-it/src/test/resources/files/testfile1.yang b/maven-yang-plugin-it/src/test/resources/files/testfile1.yang
new file mode 100644 (file)
index 0000000..5bf7ece
--- /dev/null
@@ -0,0 +1,23 @@
+module types1 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    import types2 {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+   import types3 {
+        prefix "t3";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/files/testfile2.yang b/maven-yang-plugin-it/src/test/resources/files/testfile2.yang
new file mode 100644 (file)
index 0000000..2d16b99
--- /dev/null
@@ -0,0 +1,15 @@
+module types2 {
+    yang-version 1;
+    namespace "urn:simple.types.data.demo";
+    prefix "t2";
+    
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+    
+    description "This is types-data test description";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+}
diff --git a/maven-yang-plugin-it/src/test/resources/files/testfile3.yang b/maven-yang-plugin-it/src/test/resources/files/testfile3.yang
new file mode 100644 (file)
index 0000000..8e5b86a
--- /dev/null
@@ -0,0 +1,18 @@
+module types3 {
+    yang-version 1;
+    namespace "urn:simple.container.demo.test";
+    prefix "t3";
+
+    import types2 {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+}
diff --git a/maven-yang-plugin/pom.xml b/maven-yang-plugin/pom.xml
new file mode 100644 (file)
index 0000000..444fa1f
--- /dev/null
@@ -0,0 +1,110 @@
+<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">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>yang</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.5.4-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>yang-maven-plugin</artifactId>
+    <packaging>maven-plugin</packaging>
+    <description>
+        This plugin is a wrapper for "yang to source code" generation.
+        It can be configured by a set of third-party code generators and resource providers.
+        For further info see available goals.
+        Sample usage:
+
+        TODO: add sample usage when finished
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>3.0.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.plugin-tools</groupId>
+            <artifactId>maven-plugin-annotations</artifactId>
+            <version>3.2</version>
+            <scope>provided</scope>
+        </dependency>
+               <dependency>
+                       <groupId>org.apache.maven</groupId>
+                       <artifactId>maven-artifact</artifactId>
+                       <version>2.0</version>
+               </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-parser-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-maven-plugin-spi</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-maven-plugin-spi</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>1.8.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+               <groupId>junit</groupId>
+               <artifactId>junit</artifactId>
+               <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.2</version>
+            </plugin>
+        </plugins>
+    </reporting>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-plugin-plugin</artifactId>
+                <version>3.2</version>
+                <configuration>
+                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>mojo-descriptor</id>
+                        <goals>
+                            <goal>descriptor</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java
new file mode 100644 (file)
index 0000000..88f4dde
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.maven.project.MavenProject;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+
+/**
+ * Base complex configuration arguments
+ */
+public abstract class ConfigArg {
+
+    private final File outputBaseDir;
+
+    public ConfigArg(String outputBaseDir) {
+        this.outputBaseDir = outputBaseDir == null ? null : new File(outputBaseDir);
+    }
+
+    public File getOutputBaseDir(MavenProject project) {
+        if (outputBaseDir == null) {
+            return null;
+        }
+        if (outputBaseDir.isAbsolute()) {
+            return outputBaseDir;
+        } else {
+            return new File(project.getBasedir(), outputBaseDir.getPath());
+        }
+    }
+
+    public abstract void check();
+
+    /**
+     * Configuration argument for code generator class and output directory.
+     */
+    public static final class CodeGeneratorArg extends ConfigArg {
+        private static final String CODE_GEN_DEFAULT_RESOURCE_DIR = "target" + File.separator + "generated-resources";
+
+        private String codeGeneratorClass;
+        private File resourceBaseDir = new File(CODE_GEN_DEFAULT_RESOURCE_DIR);
+
+        private Map<String, String> additionalConfiguration = Maps.newHashMap();
+
+        public CodeGeneratorArg() {
+            super(null);
+        }
+
+        public CodeGeneratorArg(String codeGeneratorClass) {
+            this(codeGeneratorClass, null);
+        }
+
+        public CodeGeneratorArg(String codeGeneratorClass, String outputBaseDir) {
+            super(outputBaseDir);
+            this.codeGeneratorClass = codeGeneratorClass;
+        }
+
+        public CodeGeneratorArg(String codeGeneratorClass, String outputBaseDir, String resourceBaseDir) {
+            super(outputBaseDir);
+            this.codeGeneratorClass = codeGeneratorClass;
+            this.resourceBaseDir = new File(resourceBaseDir);
+        }
+
+        @Override
+        public void check() {
+            Preconditions.checkNotNull(codeGeneratorClass, "codeGeneratorClass for CodeGenerator cannot be null");
+        }
+
+        public String getCodeGeneratorClass() {
+            return codeGeneratorClass;
+        }
+
+        public File getResourceBaseDir(MavenProject project) {
+            if (resourceBaseDir.isAbsolute()) {
+                return resourceBaseDir;
+            } else {
+                return new File(project.getBasedir(), resourceBaseDir.getPath());
+            }
+        }
+
+        public Map<String, String> getAdditionalConfiguration() {
+            return additionalConfiguration;
+        }
+    }
+}
diff --git a/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java
new file mode 100644 (file)
index 0000000..e3b0b31
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+final class Util {
+    static final String YANG_SUFFIX = "yang";
+
+    // Cache for listed directories and found yang files. Typically yang files
+    // are utilized twice. First: code is generated during generate-sources
+    // phase Second: yang files are copied as resources during
+    // generate-resources phase. This cache ensures that yang files are listed
+    // only once.
+    private static Map<File, Collection<File>> cache = Maps
+            .newHashMapWithExpectedSize(10);
+
+    /**
+     * List files recursively and return as array of String paths. Use cache of
+     * size 1.
+     */
+    static Collection<File> listFiles(File root) throws FileNotFoundException {
+        if (cache.get(root) != null)
+            return cache.get(root);
+
+        if (!root.exists()) {
+            throw new FileNotFoundException(root.toString());
+        }
+
+        Collection<File> yangFiles = FileUtils.listFiles(root,
+                new String[] { YANG_SUFFIX }, true);
+
+        toCache(root, yangFiles);
+        return yangFiles;
+    }
+
+    static List<InputStream> listFilesAsStream(File rootDir)
+            throws FileNotFoundException {
+        List<InputStream> is = new ArrayList<InputStream>();
+
+        Collection<File> files = listFiles(rootDir);
+        for (File f : files) {
+            is.add(new NamedFileInputStream(f));
+        }
+
+        return is;
+    }
+
+    static class NamedFileInputStream extends FileInputStream {
+        private final File file;
+
+        NamedFileInputStream(File file) throws FileNotFoundException {
+            super(file);
+            this.file = file;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "{" + file + "}";
+        }
+    }
+
+    private static void toCache(final File rootDir,
+            final Collection<File> yangFiles) {
+        cache.put(rootDir, yangFiles);
+    }
+
+    /**
+     * Instantiate object from fully qualified class name
+     */
+    static <T> T getInstance(String codeGeneratorClass, Class<T> baseType)
+            throws ClassNotFoundException, InstantiationException,
+            IllegalAccessException {
+        return baseType.cast(resolveClass(codeGeneratorClass, baseType)
+                .newInstance());
+    }
+
+    private static Class<?> resolveClass(String codeGeneratorClass,
+            Class<?> baseType) throws ClassNotFoundException {
+        Class<?> clazz = Class.forName(codeGeneratorClass);
+
+        if (!isImplemented(baseType, clazz))
+            throw new IllegalArgumentException("Code generator " + clazz
+                    + " has to implement " + baseType);
+        return clazz;
+    }
+
+    private static boolean isImplemented(Class<?> expectedIface,
+            Class<?> byClazz) {
+        for (Class<?> iface : byClazz.getInterfaces()) {
+            if (iface.equals(expectedIface))
+                return true;
+        }
+        return false;
+    }
+
+    static String message(String message, String logPrefix, Object... args) {
+        String innerMessage = String.format(message, args);
+        return String.format("%s %s", logPrefix, innerMessage);
+    }
+
+    static List<File> getClassPath(MavenProject project) {
+        List<File> dependencies = Lists.newArrayList();
+        for (Artifact element : project.getArtifacts()) {
+            File asFile = element.getFile();
+            if (isJar(asFile) || asFile.isDirectory()) {
+                dependencies.add(asFile);
+            }
+        }
+        return dependencies;
+    }
+
+    private static final String JAR_SUFFIX = ".jar";
+
+    private static boolean isJar(File element) {
+        return (element.isFile() && element.getName().endsWith(JAR_SUFFIX)) ? true
+                : false;
+    }
+
+    static <T> T checkNotNull(T obj, String paramName) {
+        return Preconditions.checkNotNull(obj, "Parameter " + paramName
+                + " is null");
+    }
+
+    final static class YangsInZipsResult implements Closeable {
+        final List<InputStream> yangStreams;
+        private final List<Closeable> zipInputStreams;
+
+        private YangsInZipsResult(List<InputStream> yangStreams,
+                List<Closeable> zipInputStreams) {
+            this.yangStreams = yangStreams;
+            this.zipInputStreams = zipInputStreams;
+        }
+
+        @Override
+        public void close() throws IOException {
+            for (InputStream is : yangStreams) {
+                is.close();
+            }
+            for (Closeable is : zipInputStreams) {
+                is.close();
+            }
+        }
+    }
+
+    static YangsInZipsResult findYangFilesInDependenciesAsStream(Log log,
+            MavenProject project)
+            throws MojoFailureException {
+        List<InputStream> yangsFromDependencies = new ArrayList<>();
+        List<Closeable> zips = new ArrayList<>();
+        try {
+            List<File> filesOnCp = Util.getClassPath(project);
+            log.info(Util.message(
+                    "Searching for yang files in following dependencies: %s",
+                    YangToSourcesProcessor.LOG_PREFIX, filesOnCp));
+
+            for (File file : filesOnCp) {
+                List<String> foundFilesForReporting = new ArrayList<>();
+                // is it jar file or directory?
+                if (file.isDirectory()) {
+                    File yangDir = new File(file,
+                            YangToSourcesProcessor.META_INF_YANG_STRING);
+                    if (yangDir.exists() && yangDir.isDirectory()) {
+                        File[] yangFiles = yangDir
+                                .listFiles(new FilenameFilter() {
+                                    @Override
+                                    public boolean accept(File dir, String name) {
+                                        return name.endsWith(".yang")
+                                                && new File(dir, name).isFile();
+                                    }
+                                });
+                        for (File yangFile : yangFiles) {
+                            yangsFromDependencies.add(new NamedFileInputStream(
+                                    yangFile));
+                        }
+                    }
+
+                } else {
+                    ZipFile zip = new ZipFile(file);
+                    zips.add(zip);
+
+                    Enumeration<? extends ZipEntry> entries = zip.entries();
+                    while (entries.hasMoreElements()) {
+                        ZipEntry entry = entries.nextElement();
+                        String entryName = entry.getName();
+
+                        if (entryName
+                                .startsWith(YangToSourcesProcessor.META_INF_YANG_STRING_JAR)) {
+                            if (entry.isDirectory() == false
+                                    && entryName.endsWith(".yang")) {
+                                foundFilesForReporting.add(entryName);
+                                // This will be closed after all strams are
+                                // parsed.
+                                InputStream entryStream = zip
+                                        .getInputStream(entry);
+                                yangsFromDependencies.add(entryStream);
+                            }
+                        }
+                    }
+                }
+                if (foundFilesForReporting.size() > 0) {
+                    log.info(Util.message("Found %d yang files in %s: %s",
+                            YangToSourcesProcessor.LOG_PREFIX,
+                            foundFilesForReporting.size(), file,
+                            foundFilesForReporting));
+                }
+
+            }
+        } catch (Exception e) {
+            throw new MojoFailureException(e.getMessage(), e);
+        }
+        return new YangsInZipsResult(yangsFromDependencies, zips);
+    }
+
+    final static class ContextHolder {
+        private final SchemaContext context;
+        private final Set<Module> yangModules;
+
+        ContextHolder(SchemaContext context, Set<Module> yangModules) {
+            this.context = context;
+            this.yangModules = yangModules;
+        }
+
+        SchemaContext getContext() {
+            return context;
+        }
+
+        Set<Module> getYangModules() {
+            return yangModules;
+        }
+    }
+
+}
diff --git a/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java
new file mode 100644 (file)
index 0000000..6e43b30
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.controller.yang2sources.spi.CodeGenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+
+/**
+ * Generate sources from yang files using user provided set of
+ * {@link CodeGenerator}s. Steps of this process:
+ * <ol>
+ * <li>List yang files from {@link #yangFilesRootDir}</li>
+ * <li>Process yang files using {@link YangModelParserImpl}</li>
+ * <li>For each {@link CodeGenerator} from {@link #codeGenerators}:</li>
+ * <ol>
+ * <li>Instantiate using default constructor</li>
+ * <li>Call {@link CodeGenerator#generateSources(SchemaContext, File)}</li>
+ * </ol>
+ * </ol>
+ */
+@Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE, requiresProject = true)
+public final class YangToSourcesMojo extends AbstractMojo {
+
+    /**
+     * Classes implementing {@link CodeGenerator} interface. An instance will be
+     * created out of every class using default constructor. Method {@link
+     * CodeGenerator#generateSources(SchemaContext, File, Set<String>
+     * yangModulesNames)} will be called on every instance.
+     */
+    @Parameter(required = false)
+    private CodeGeneratorArg[] codeGenerators;
+
+    /**
+     * Source directory that will be recursively searched for yang files (ending
+     * with .yang suffix).
+     */
+    @Parameter(required = false)
+    private String yangFilesRootDir; // defaults to ${basedir}/src/main/yang
+
+    @Parameter(property = "project", required = true, readonly = true)
+    protected MavenProject project;
+
+    @Parameter(property = "inspectDependencies", required = true, readonly = true)
+    private boolean inspectDependencies;
+
+    private YangToSourcesProcessor yangToSourcesProcessor;
+
+    public YangToSourcesMojo() {
+
+    }
+
+    @VisibleForTesting
+    YangToSourcesMojo(YangToSourcesProcessor processor) {
+        this.yangToSourcesProcessor = processor;
+    }
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        if (yangToSourcesProcessor == null) {
+            List<CodeGeneratorArg> codeGeneratorArgs = processCodeGenerators(codeGenerators);
+
+            // defaults to ${basedir}/src/main/yang
+            File yangFilesRootFile = processYangFilesRootDir(yangFilesRootDir,
+                    project.getBasedir());
+
+            yangToSourcesProcessor = new YangToSourcesProcessor(getLog(),
+                    yangFilesRootFile, codeGeneratorArgs, project,
+                    inspectDependencies);
+        }
+        yangToSourcesProcessor.execute();
+    }
+
+    private static List<CodeGeneratorArg> processCodeGenerators(
+            CodeGeneratorArg[] codeGenerators) {
+        List<CodeGeneratorArg> codeGeneratorArgs;
+        if (codeGenerators == null) {
+            codeGeneratorArgs = Collections.emptyList();
+        } else {
+            codeGeneratorArgs = Arrays.asList(codeGenerators);
+        }
+        return codeGeneratorArgs;
+    }
+
+    private static File processYangFilesRootDir(String yangFilesRootDir,
+            File baseDir) {
+        File yangFilesRootFile;
+        if (yangFilesRootDir == null) {
+            yangFilesRootFile = new File(baseDir, "src" + File.separator
+                    + "main" + File.separator + "yang");
+        } else {
+            File file = new File(yangFilesRootDir);
+            if (file.isAbsolute()) {
+                yangFilesRootFile = file;
+            } else {
+                yangFilesRootFile = new File(baseDir, file.getPath());
+            }
+        }
+        return yangFilesRootFile;
+    }
+}
diff --git a/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesProcessor.java b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesProcessor.java
new file mode 100644 (file)
index 0000000..b781d72
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.model.Resource;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.parser.impl.YangParserImpl;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.controller.yang2sources.plugin.Util.ContextHolder;
+import org.opendaylight.controller.yang2sources.plugin.Util.YangsInZipsResult;
+import org.opendaylight.controller.yang2sources.spi.CodeGenerator;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+
+class YangToSourcesProcessor {
+    static final String LOG_PREFIX = "yang-to-sources:";
+    static final String META_INF_YANG_STRING = "META-INF" + File.separator
+            + "yang";
+    static final String META_INF_YANG_STRING_JAR = "META-INF" + "/" + "yang";
+    static final File META_INF_YANG_DIR = new File(META_INF_YANG_STRING);
+
+    private final Log log;
+    private final File yangFilesRootDir;
+    private final List<CodeGeneratorArg> codeGenerators;
+    private final MavenProject project;
+    private final boolean inspectDependencies;
+    private YangProvider yangProvider;
+
+    @VisibleForTesting
+    YangToSourcesProcessor(Log log, File yangFilesRootDir,
+                           List<CodeGeneratorArg> codeGenerators, MavenProject project,
+                           boolean inspectDependencies, YangProvider yangProvider) {
+        this.log = Util.checkNotNull(log, "log");
+        this.yangFilesRootDir = Util.checkNotNull(yangFilesRootDir,
+                "yangFilesRootDir");
+        this.codeGenerators = Collections.unmodifiableList(Util.checkNotNull(
+                codeGenerators, "codeGenerators"));
+        this.project = Util.checkNotNull(project, "project");
+        this.inspectDependencies = inspectDependencies;
+        this.yangProvider = yangProvider;
+    }
+
+    YangToSourcesProcessor(Log log, File yangFilesRootDir,
+                           List<CodeGeneratorArg> codeGenerators, MavenProject project,
+                           boolean inspectDependencies) {
+        this(log, yangFilesRootDir, codeGenerators, project,
+                inspectDependencies, new YangProvider());
+    }
+
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        ContextHolder context = processYang();
+        generateSources(context);
+        yangProvider.addYangsToMETA_INF(log, project, yangFilesRootDir);
+    }
+
+    private ContextHolder processYang() throws MojoExecutionException {
+        YangParserImpl parser = new YangParserImpl();
+        List<Closeable> closeables = new ArrayList<>();
+        log.info(Util.message("Inspecting %s", LOG_PREFIX, yangFilesRootDir));
+        try {
+            List<InputStream> yangsInProject = Util
+                    .listFilesAsStream(yangFilesRootDir);
+            List<InputStream> all = new ArrayList<>(yangsInProject);
+            closeables.addAll(yangsInProject);
+            Map<InputStream, Module> allYangModules;
+            Set<Module> projectYangModules;
+            try {
+                if (inspectDependencies) {
+                    YangsInZipsResult dependentYangResult = Util
+                            .findYangFilesInDependenciesAsStream(log, project);
+                    Closeable dependentYangResult1 = dependentYangResult;
+                    closeables.add(dependentYangResult1);
+                    all.addAll(dependentYangResult.yangStreams);
+                }
+
+                allYangModules = parser.parseYangModelsFromStreamsMapped(all);
+
+                projectYangModules = new HashSet<>();
+                for (InputStream inProject : yangsInProject) {
+                    projectYangModules.add(allYangModules.get(inProject));
+                }
+
+            } finally {
+                for (AutoCloseable closeable : closeables) {
+                    closeable.close();
+                }
+            }
+
+            Set<Module> parsedAllYangModules = new HashSet<>(
+                    allYangModules.values());
+            SchemaContext resolveSchemaContext = parser
+                    .resolveSchemaContext(parsedAllYangModules);
+            log.info(Util.message("%s files parsed from %s", LOG_PREFIX,
+                    Util.YANG_SUFFIX.toUpperCase(), yangsInProject));
+            return new ContextHolder(resolveSchemaContext, projectYangModules);
+
+            // MojoExecutionException is thrown since execution cannot continue
+        } catch (Exception e) {
+            String message = Util.message("Unable to parse %s files from %s",
+                    LOG_PREFIX, Util.YANG_SUFFIX, yangFilesRootDir);
+            log.error(message, e);
+            throw new MojoExecutionException(message, e);
+        }
+    }
+
+    static class YangProvider {
+
+        private static final String yangResourceDir = "target" + File.separator
+                + "yang";
+
+        void addYangsToMETA_INF(Log log, MavenProject project,
+                                File yangFilesRootDir) throws MojoFailureException {
+            File targetYangDir = new File(project.getBasedir(), yangResourceDir);
+
+            try {
+                FileUtils.copyDirectory(yangFilesRootDir, targetYangDir);
+            } catch (IOException e) {
+                String message = "Unable to copy yang files into resource folder";
+                log.warn(message, e);
+                throw new MojoFailureException(message, e);
+            }
+
+            setResource(targetYangDir, META_INF_YANG_STRING_JAR, project);
+
+            log.debug(Util.message(
+                    "Yang files from: %s marked as resources: %s", LOG_PREFIX,
+                    yangFilesRootDir, META_INF_YANG_STRING_JAR));
+        }
+
+        private static void setResource(File targetYangDir, String targetPath,
+                                        MavenProject project) {
+            Resource res = new Resource();
+            res.setDirectory(targetYangDir.getPath());
+            if (targetPath != null)
+                res.setTargetPath(targetPath);
+            project.addResource(res);
+        }
+    }
+
+    /**
+     * Call generate on every generator from plugin configuration
+     */
+    private void generateSources(ContextHolder context)
+            throws MojoFailureException {
+        if (codeGenerators.size() == 0) {
+            log.warn(Util.message("No code generators provided", LOG_PREFIX));
+            return;
+        }
+
+        Map<String, String> thrown = Maps.newHashMap();
+        for (CodeGeneratorArg codeGenerator : codeGenerators) {
+            try {
+                generateSourcesWithOneGenerator(context, codeGenerator);
+            } catch (Exception e) {
+                // try other generators, exception will be thrown after
+                log.error(Util.message(
+                        "Unable to generate sources with %s generator",
+                        LOG_PREFIX, codeGenerator.getCodeGeneratorClass()), e);
+                thrown.put(codeGenerator.getCodeGeneratorClass(), e.getClass()
+                        .getCanonicalName());
+            }
+        }
+
+        if (!thrown.isEmpty()) {
+            String message = Util
+                    .message(
+                            "One or more code generators failed, including failed list(generatorClass=exception) %s",
+                            LOG_PREFIX, thrown.toString());
+            log.error(message);
+            throw new MojoFailureException(message);
+        }
+    }
+
+    /**
+     * Instantiate generator from class and call required method
+     */
+    private void generateSourcesWithOneGenerator(ContextHolder context,
+                                                 CodeGeneratorArg codeGeneratorCfg) throws ClassNotFoundException,
+            InstantiationException, IllegalAccessException, IOException {
+
+        codeGeneratorCfg.check();
+
+        CodeGenerator g = Util.getInstance(
+                codeGeneratorCfg.getCodeGeneratorClass(), CodeGenerator.class);
+        log.info(Util.message("Code generator instantiated from %s",
+                LOG_PREFIX, codeGeneratorCfg.getCodeGeneratorClass()));
+
+        File outputDir = codeGeneratorCfg.getOutputBaseDir(project);
+
+        log.info(Util.message("Sources will be generated to %s", LOG_PREFIX,
+                outputDir));
+        log.debug(Util.message("Project root dir is %s", LOG_PREFIX,
+                project.getBasedir()));
+        log.debug(Util.message(
+                "Additional configuration picked up for : %s: %s", LOG_PREFIX,
+                codeGeneratorCfg.getCodeGeneratorClass(),
+                codeGeneratorCfg.getAdditionalConfiguration()));
+
+        if(outputDir != null) {
+            project.addCompileSourceRoot(outputDir.getAbsolutePath());
+        }
+        g.setLog(log);
+        g.setMavenProject(project);
+        g.setAdditionalConfig(codeGeneratorCfg.getAdditionalConfiguration());
+        File resourceBaseDir = codeGeneratorCfg.getResourceBaseDir(project);
+
+        YangProvider.setResource(resourceBaseDir, null, project);
+        g.setResourceBaseDir(resourceBaseDir);
+        log.debug(Util.message(
+                "Folder: %s marked as resources for generator: %s", LOG_PREFIX,
+                resourceBaseDir, codeGeneratorCfg.getCodeGeneratorClass()));
+
+        Collection<File> generated = g.generateSources(context.getContext(),
+                outputDir, context.getYangModules());
+
+        log.info(Util.message("Sources generated by %s: %s", LOG_PREFIX,
+                codeGeneratorCfg.getCodeGeneratorClass(), generated));
+    }
+
+}
diff --git a/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java b/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java
new file mode 100644 (file)
index 0000000..14e9d34
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import static org.hamcrest.core.Is.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang2sources.plugin.ConfigArg.CodeGeneratorArg;
+import org.opendaylight.controller.yang2sources.plugin.YangToSourcesProcessor.YangProvider;
+import org.opendaylight.controller.yang2sources.spi.CodeGenerator;
+
+import com.google.common.collect.Lists;
+
+public class GenerateSourcesTest {
+
+    private String yang;
+    private YangToSourcesMojo mojo;
+    private File outDir;
+    @Mock
+    private MavenProject project;
+
+    @Before
+    public void setUp() throws MojoFailureException {
+        MockitoAnnotations.initMocks(this);
+
+        yang = new File(getClass().getResource("/yang/mock.yang").getFile())
+                .getParent();
+        outDir = new File("/outputDir");
+        YangProvider mock = mock(YangProvider.class);
+        doNothing().when(mock).addYangsToMETA_INF(any(Log.class),
+                any(MavenProject.class), any(File.class));
+
+        YangToSourcesProcessor processor = new YangToSourcesProcessor(
+                mock(Log.class), new File(yang),
+                Lists.newArrayList(new CodeGeneratorArg(GeneratorMock.class
+                        .getName(), "outputDir")), project, false,
+                mock);
+        mojo = new YangToSourcesMojo(processor);
+        doReturn(new File("")).when(project).getBasedir();
+        mojo.project = project;
+    }
+
+    @Test
+    public void test() throws Exception {
+        mojo.execute();
+        assertThat(GeneratorMock.called, is(1));
+        assertThat(GeneratorMock.outputDir, is(outDir));
+        assertThat(GeneratorMock.project, is(project));
+        assertNotNull(GeneratorMock.log);
+        assertTrue(GeneratorMock.additionalCfg.isEmpty());
+        assertThat(GeneratorMock.resourceBaseDir.toString(),
+                containsString("target" + File.separator
+                        + "generated-resources"));
+    }
+
+    public static class GeneratorMock implements CodeGenerator {
+
+        private static int called = 0;
+        private static File outputDir;
+        private static Log log;
+        private static Map<String, String> additionalCfg;
+        private static File resourceBaseDir;
+        private static MavenProject project;
+
+        @Override
+        public Collection<File> generateSources(SchemaContext context,
+                File outputBaseDir, Set<Module> currentModules)
+                throws IOException {
+            called++;
+            outputDir = outputBaseDir;
+            return Lists.newArrayList();
+        }
+
+        @Override
+        public void setLog(Log log) {
+            GeneratorMock.log = log;
+        }
+
+        @Override
+        public void setAdditionalConfig(
+                Map<String, String> additionalConfiguration) {
+            GeneratorMock.additionalCfg = additionalConfiguration;
+        }
+
+        @Override
+        public void setResourceBaseDir(File resourceBaseDir) {
+            GeneratorMock.resourceBaseDir = resourceBaseDir;
+
+        }
+
+        @Override
+        public void setMavenProject(MavenProject project) {
+            GeneratorMock.project = project;
+        }
+    }
+
+}
diff --git a/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java b/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java
new file mode 100644 (file)
index 0000000..2408254
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.plugin;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Collection;
+
+import org.junit.Test;
+
+public class UtilTest {
+
+    @Test
+    public void testCache() throws FileNotFoundException {
+        String yang = new File(getClass().getResource("/yang/mock.yang")
+                .getFile())
+                .getParent();
+        Collection<File> files = Util.listFiles(new File(yang));
+        Collection<File> files2 = Util.listFiles(new File(yang));
+        assertTrue(files == files2);
+    }
+
+}
diff --git a/maven-yang-plugin/src/test/resources/yang/mock.yang b/maven-yang-plugin/src/test/resources/yang/mock.yang
new file mode 100644 (file)
index 0000000..72e4d2c
--- /dev/null
@@ -0,0 +1,11 @@
+ module mock {
+
+   namespace "a:b:c";
+   prefix "m";
+
+   revision 2010-09-24 {
+     description
+      "Initial revision.";
+   }
+
+ }
diff --git a/maven-yang/pom.xml b/maven-yang/pom.xml
new file mode 100644 (file)
index 0000000..6754c8c
--- /dev/null
@@ -0,0 +1,51 @@
+<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>
+        <artifactId>yang</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.5.4-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yang-maven-plugin-spi</artifactId>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>3.0.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>3.0.5</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java b/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java
new file mode 100644 (file)
index 0000000..3042160
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.spi;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+/**
+ * Classes implementing this interface can be submitted to maven-yang-plugin's
+ * generate-sources goal.
+ */
+public interface CodeGenerator {
+
+    /**
+     * Generate sources from provided {@link SchemaContext}
+     *
+     * @param context
+     *            parsed from yang files
+     * @param outputBaseDir
+     *            expected output directory for generated sources configured by
+     *            user
+     * @param currentModules
+     *            yang modules parsed from yangFilesRootDir
+     * @return collection of files that were generated from schema context
+     * @throws IOException
+     */
+    Collection<File> generateSources(SchemaContext context, File outputBaseDir, Set<Module> currentModules)
+            throws IOException;
+
+    /**
+     * Utilize maven logging if necessary
+     *
+     * @param log
+     */
+    void setLog(Log log);
+
+    /**
+     * Provided map contains all configuration that was set in pom for code
+     * generator in additionalConfiguration tag
+     *
+     * @param additionalConfiguration
+     */
+    void setAdditionalConfig(Map<String, String> additionalConfiguration);
+
+    /**
+     * Provided folder is marked as resources and its content will be packaged
+     * in resulting jar. Feel free to add necessary resources
+     *
+     * @param resourceBaseDir
+     */
+    void setResourceBaseDir(File resourceBaseDir);
+
+    /**
+     * Provided maven project object. Any additional information about current
+     * maven project can be accessed from it.
+     *
+     * @param project
+     */
+    void setMavenProject(MavenProject project);
+}
diff --git a/maven-yang/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java b/maven-yang/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java
new file mode 100644 (file)
index 0000000..3103042
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang2sources.spi;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+public class CodeGeneratorTestImpl implements CodeGenerator {
+
+    private Log log;
+
+    @Override
+    public Collection<File> generateSources(SchemaContext context,
+            File outputBaseDir, Set<Module> currentModuleBuilders) {
+        if (log != null) {
+            log.debug(getClass().getCanonicalName()
+                    + " generateSources:context: " + context);
+            log.debug(getClass().getCanonicalName()
+                    + " generateSources:outputBaseDir: " + outputBaseDir);
+            log.debug(getClass().getCanonicalName()
+                    + " generateSources:currentModuleBuilders: "
+                    + currentModuleBuilders);
+
+        }
+        return null;
+    }
+
+    @Override
+    public void setLog(Log log) {
+        this.log = log;
+    }
+
+    @Override
+    public void setAdditionalConfig(Map<String, String> additionalConfiguration) {
+        if (log != null)
+            log.debug(getClass().getCanonicalName() + " additionalConfig: "
+                    + additionalConfiguration);
+    }
+
+
+    @Override
+    public void setResourceBaseDir(File resourceBaseDir) {
+        if (log != null)
+            log.debug(getClass().getCanonicalName() + " resourceBaseDir: "
+                    + resourceBaseDir);
+    }
+
+    @Override
+    public void setMavenProject(MavenProject project) {
+        if (log != null)
+            log.debug(getClass().getCanonicalName() + " maven project: "
+                    + project);
+    }
+
+}
diff --git a/pom.xml b/pom.xml
index fc506049946eab15cb02fd307ddac6e72712423f..5c3617c98856ad86247025d58d490c7b94aa1064 100644 (file)
--- a/pom.xml
+++ b/pom.xml
         <module>yang-common</module>
         <module>yang-data-api</module>
         <module>yang-data-util</module>
-               <module>yang-data-impl</module>
+        <module>yang-data-impl</module>
         <module>yang-model-api</module>
         <module>yang-model-util</module>
         <module>yang-binding</module>
         <module>yang-ext</module>
-        <module>../code-generator/yang-model-parser-api</module>
-        <module>../code-generator/yang-model-parser-impl</module>
-        <module>../code-generator/maven-yang</module>
-        <module>../code-generator/maven-yang-plugin</module>
-        <module>../code-generator/maven-yang-plugin-it</module>
+        <module>yang-model-parser-api</module>
+        <module>yang-model-parser-impl</module>
+        <module>maven-yang</module>
+        <module>maven-yang-plugin</module>
+        <module>maven-yang-plugin-it</module>
     </modules>
 
     <dependencyManagement>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-javadoc-plugin</artifactId>
-                <version>2.8.1</version>
                 <configuration>
                     <stylesheet>maven</stylesheet>
                 </configuration>
             </plugin>
         </plugins>
     </build>
+
     <reporting>
         <plugins>
             <plugin>
             </plugin>
         </plugins>
     </reporting>
+
 </project>
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644 (file)
index 0000000..80ff3a4
--- /dev/null
@@ -0,0 +1,16 @@
+<project name="${project.name}">
+
+    <skin>
+        <groupId>org.apache.maven.skins</groupId>
+        <artifactId>maven-fluido-skin</artifactId>
+        <version>1.3.0</version>
+    </skin>
+
+    <body>
+        <menu ref="parent"/>
+        <menu ref="modules"/>
+        <menu ref="reports"/>
+    </body>
+
+</project>
+
index 79add782544be821f3fc57edb55cf1e6eaf6cb9d..70b7a5a311d217bd0119d9da85f3975c1ce800d2 100644 (file)
@@ -1,9 +1,15 @@
-<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">\r
-  <modelVersion>4.0.0</modelVersion>\r
-  <parent>\r
-    <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>yang</artifactId>\r
-    <version>0.5.4-SNAPSHOT</version>\r
-  </parent>\r
-  <artifactId>yang-binding</artifactId>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+\r
+    <parent>\r
+        <groupId>org.opendaylight.controller</groupId>\r
+        <artifactId>yang</artifactId>\r
+        <version>0.5.4-SNAPSHOT</version>\r
+    </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
+    <artifactId>yang-binding</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>Java binding for YANG</description>\r
+\r
 </project>\r
index a94013b288957a9cbd3ba907a41d0792013f9340..445e310a2a624546f235834ecc1491a047ea44ef 100644 (file)
@@ -1,16 +1,23 @@
-<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">\r
-  <modelVersion>4.0.0</modelVersion>\r
-  <parent>\r
-    <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>yang</artifactId>\r
-    <version>0.5.4-SNAPSHOT</version>\r
-  </parent>\r
-  <artifactId>yang-common</artifactId>\r
-  <dependencies>\r
-      <dependency>\r
-          <groupId>org.slf4j</groupId>\r
-          <artifactId>slf4j-api</artifactId>\r
-          <version>${slf4j.version}</version>\r
-      </dependency>\r
-  </dependencies>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+\r
+    <parent>\r
+        <groupId>org.opendaylight.controller</groupId>\r
+        <artifactId>yang</artifactId>\r
+        <version>0.5.4-SNAPSHOT</version>\r
+    </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
+    <artifactId>yang-common</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
+\r
+    <dependencies>\r
+        <dependency>\r
+            <groupId>org.slf4j</groupId>\r
+            <artifactId>slf4j-api</artifactId>\r
+        </dependency>\r
+    </dependencies>\r
+\r
 </project>\r
+\r
index 28f25946ba6dee9a4bd07688e20cf7a07de9112a..145daf9561a0554f81087e34e8ab65e3e6b96a1b 100644 (file)
@@ -1,12 +1,16 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
+\r
     <parent>\r
         <groupId>org.opendaylight.controller</groupId>\r
         <artifactId>yang</artifactId>\r
         <version>0.5.4-SNAPSHOT</version>\r
     </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
     <artifactId>yang-data-api</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
 \r
     <dependencies>\r
         <dependency>\r
@@ -14,4 +18,5 @@
             <artifactId>yang-common</artifactId>\r
         </dependency>\r
     </dependencies>\r
-</project>
\ No newline at end of file
+\r
+</project>\r
index 7a1b75633280a6a077eb29aea942076fcaccb46f..ca5bd5ced0dcd83b77ebebb56e766aca3e78caa6 100644 (file)
@@ -1,13 +1,16 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"\r
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
+\r
     <parent>\r
         <groupId>org.opendaylight.controller</groupId>\r
         <artifactId>yang</artifactId>\r
         <version>0.5.4-SNAPSHOT</version>\r
     </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
     <artifactId>yang-data-impl</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
 \r
     <properties>\r
         <groovy.version>2.1.6</groovy.version>\r
@@ -25,7 +28,6 @@
         </plugins>\r
     </build>\r
 \r
-\r
     <dependencies>\r
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
@@ -81,4 +83,5 @@
             <scope>test</scope>\r
         </dependency>\r
     </dependencies>\r
+\r
 </project>\r
index 722a379aa31a4ecaad4dab9928ba40397b830f56..bbd6cd63828a37057c8f731d7f92543dc8537e29 100644 (file)
@@ -1,16 +1,22 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
+\r
     <parent>\r
         <groupId>org.opendaylight.controller</groupId>\r
         <artifactId>yang</artifactId>\r
         <version>0.5.4-SNAPSHOT</version>\r
     </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
     <artifactId>yang-data-util</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
+\r
     <dependencies>\r
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
             <artifactId>yang-data-api</artifactId>\r
         </dependency>\r
     </dependencies>\r
-</project>
\ No newline at end of file
+\r
+</project>\r
index 85ecb91b332db2151f8acf3370a216eaae2aebc2..d1d543abb5626fe4ec7d462da0076871b351f3dc 100644 (file)
@@ -1,13 +1,17 @@
 <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">
-    <modelVersion>4.0.0</modelVersion>
+
     <parent>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>yang</artifactId>
         <version>0.5.4-SNAPSHOT</version>
     </parent>
+
+    <modelVersion>4.0.0</modelVersion>
     <artifactId>yang-ext</artifactId>
     <version>2013.09.07-SNAPSHOT</version>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
 
     <build>
         <plugins>
index 8c4cb351967dcc96fe6c9ded26ac130d5950f0a2..14e7d20350da5ab65c06612c74b5600612408961 100644 (file)
@@ -1,16 +1,22 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-    <modelVersion>4.0.0</modelVersion>\r
+\r
     <parent>\r
         <groupId>org.opendaylight.controller</groupId>\r
         <artifactId>yang</artifactId>\r
         <version>0.5.4-SNAPSHOT</version>\r
     </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
     <artifactId>yang-model-api</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
+\r
     <dependencies>\r
         <dependency>\r
             <groupId>org.opendaylight.controller</groupId>\r
             <artifactId>yang-common</artifactId>\r
         </dependency>\r
     </dependencies>\r
+\r
 </project>\r
index 74a420a3f885f9b88ea7df04f2803e353893948d..068d4a977c74f883f601007b2643cdf0cb068cfb 100644 (file)
@@ -11,21 +11,20 @@ import java.util.List;
 
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
 
-public interface DecimalTypeDefinition extends
-        TypeDefinition<DecimalTypeDefinition> {
+public interface DecimalTypeDefinition extends TypeDefinition<DecimalTypeDefinition> {
 
     List<RangeConstraint> getRangeStatements();
 
     /**
      * Returns integer between 1 and 18 inclusively. <br>
      * <br>
-     * 
+     *
      * The "fraction-digits" statement controls the size of the minimum
      * difference between values of a decimal64 type, by restricting the value
      * space to numbers that are expressible as "i x 10^-n" where n is the
      * fraction-digits argument.
-     * 
-     * @return
+     *
+     * @return number of fraction digits
      */
     Integer getFractionDigits();
 }
diff --git a/yang-model-parser-api/pom.xml b/yang-model-parser-api/pom.xml
new file mode 100644 (file)
index 0000000..5bd261c
--- /dev/null
@@ -0,0 +1,21 @@
+<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.controller</groupId>
+    <artifactId>yang</artifactId>
+    <version>0.5.4-SNAPSHOT</version>
+  </parent>
+  
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>yang-model-parser-api</artifactId>
+  <name>${project.artifactId}</name>
+  <description>YANG parser API</description>
+  
+  <dependencies>
+      <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>yang-model-api</artifactId>
+      </dependency>
+  </dependencies>
+  
+</project>
diff --git a/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/YangModelParser.java b/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/YangModelParser.java
new file mode 100644 (file)
index 0000000..142f199
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.model.parser.api;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.type.UnknownTypeDefinition;
+
+/**
+ * Yang Model Parser interface is designed for parsing yang models and convert
+ * the information to Data Schema Tree.
+ *
+ */
+public interface YangModelParser {
+
+    /**
+     * Parse one or more Yang model files and return the definitions of Yang
+     * modules defined in *.yang files; <br>
+     * This method SHOULD be used if user need to parse multiple yang models
+     * that are referenced either through import or include statements.
+     *
+     * @param yangFiles
+     *            yang files to parse
+     * @return Set of Yang Modules
+     */
+    Set<Module> parseYangModels(final List<File> yangFiles);
+
+    /**
+     * Parse one or more Yang model files and return the definitions of Yang
+     * modules defined in *.yang files. <br>
+     * This method SHOULD be used if user has already parsed context and need to
+     * parse additinal yang models which can have dependencies on models in this
+     * context.
+     *
+     * @param yangFiles
+     *            yang files to parse
+     * @param context
+     *            SchemaContext containing already parsed yang models
+     * @return Set of Yang Modules
+     */
+    Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context);
+
+    /**
+     * Equivalent to {@link #parseYangModels(List)} that returns parsed modules
+     * mapped to Files from which they were parsed.
+     *
+     * @param yangFiles
+     *            yang files to parse
+     * @return Map of Yang Modules
+     */
+    Map<File, Module> parseYangModelsMapped(final List<File> yangFiles);
+
+    /**
+     * Parse one or more Yang model streams and return the definitions of Yang
+     * modules defined in *.yang files; <br>
+     * This method SHOULD be used if user need to parse multiple yang models
+     * that are referenced either through import or include statements.
+     *
+     * @param yangModelStreams
+     *            yang streams to parse
+     * @return Set of Yang Modules
+     */
+    Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams);
+
+    /**
+     * Parse one or more Yang model streams and return the definitions of Yang
+     * modules defined in *.yang files. <br>
+     * This method SHOULD be used if user has already parsed context and need to
+     * parse additinal yang models which can have dependencies on models in this
+     * context.
+     *
+     * @param yangModelStreams
+     *            yang streams to parse
+     * @param context
+     *            SchemaContext containing already parsed yang models
+     * @return Set of Yang Modules
+     */
+    Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, final SchemaContext context);
+
+    /**
+     * Equivalent to {@link #parseYangModels(List)} that returns parsed modules
+     * mapped to IputStreams from which they were parsed.
+     *
+     * @param yangModelStreams
+     *            yang streams to parse
+     * @return Map of Yang Modules
+     */
+    Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams);
+
+    /**
+     * Creates {@link SchemaContext} from specified Modules. The modules SHOULD
+     * not contain any unresolved Schema Nodes or Type Definitions. By
+     * unresolved Schema Nodes or Type Definitions we mean that the Module
+     * should not contain ANY Schema Nodes that contains
+     * {@link UnknownTypeDefinition} and all dependencies although via import or
+     * include definitions are resolved.
+     *
+     * @param modules
+     *            Set of Yang Modules
+     * @return Schema Context instance constructed from whole Set of Modules.
+     */
+    SchemaContext resolveSchemaContext(final Set<Module> modules);
+}
diff --git a/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/package-info.java b/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/package-info.java
new file mode 100644 (file)
index 0000000..2e8a029
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.model.parser.api;
\ No newline at end of file
diff --git a/yang-model-parser-impl/pom.xml b/yang-model-parser-impl/pom.xml
new file mode 100644 (file)
index 0000000..b40cd3c
--- /dev/null
@@ -0,0 +1,135 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+\r
+    <parent>\r
+        <groupId>org.opendaylight.controller</groupId>\r
+        <artifactId>yang</artifactId>\r
+        <version>0.5.4-SNAPSHOT</version>\r
+    </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
+    <artifactId>yang-model-parser-impl</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>YANG parser</description>\r
+\r
+    <dependencies>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>yang-common</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>yang-model-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>yang-model-parser-api</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>yang-model-util</artifactId>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.antlr</groupId>\r
+            <artifactId>antlr4</artifactId>\r
+            <version>4.0</version>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.slf4j</groupId>\r
+            <artifactId>slf4j-simple</artifactId>\r
+            <version>1.7.2</version>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>org.mockito</groupId>\r
+            <artifactId>mockito-all</artifactId>\r
+            <version>1.8.4</version>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>com.google.guava</groupId>\r
+            <artifactId>guava</artifactId>\r
+            <version>14.0.1</version>\r
+        </dependency>\r
+        <dependency>\r
+            <groupId>junit</groupId>\r
+            <artifactId>junit</artifactId>\r
+        </dependency>\r
+    </dependencies>\r
+\r
+    <build>\r
+        <plugins>\r
+            <plugin>\r
+                <groupId>org.antlr</groupId>\r
+                <artifactId>antlr4-maven-plugin</artifactId>\r
+                <version>4.0</version>\r
+                <executions>\r
+                    <execution>\r
+                        <goals>\r
+                            <goal>antlr4</goal>\r
+                        </goals>\r
+                    </execution>\r
+                </executions>\r
+                <configuration>\r
+                    <sourceDirectory>src/main/antlr</sourceDirectory>\r
+                    <outputDirectory>target/generated-sources/parser/org/opendaylight/controller/antlrv4/code/gen</outputDirectory>\r
+                    <visitor>true</visitor>\r
+                    <listener>true</listener>\r
+                </configuration>\r
+            </plugin>\r
+            <plugin>\r
+                <groupId>org.codehaus.mojo</groupId>\r
+                <artifactId>build-helper-maven-plugin</artifactId>\r
+                <version>1.7</version>\r
+                <executions>\r
+                    <execution>\r
+                        <phase>generate-sources</phase>\r
+                        <goals>\r
+                            <goal>add-source</goal>\r
+                        </goals>\r
+                        <configuration>\r
+                            <sources>\r
+                                <source>target/generated-sources/parser</source>\r
+                            </sources>\r
+                        </configuration>\r
+                    </execution>\r
+                </executions>\r
+            </plugin>\r
+            <plugin>\r
+                <groupId>org.apache.maven.plugins</groupId>\r
+                <artifactId>maven-javadoc-plugin</artifactId>\r
+                <configuration>\r
+                    <excludePackageNames>\r
+                        *.opendaylight.controller.antlrv4.code.gen\r
+                    </excludePackageNames>\r
+                </configuration>\r
+            </plugin>\r
+        </plugins>\r
+        <pluginManagement>\r
+            <plugins>\r
+                <plugin>\r
+                    <groupId>org.eclipse.m2e</groupId>\r
+                    <artifactId>lifecycle-mapping</artifactId>\r
+                    <version>1.0.0</version>\r
+                    <configuration>\r
+                        <lifecycleMappingMetadata>\r
+                            <pluginExecutions>\r
+                                <pluginExecution>\r
+                                    <pluginExecutionFilter>\r
+                                        <groupId>org.antlr</groupId>\r
+                                        <artifactId>antlr4-maven-plugin</artifactId>\r
+                                        <versionRange>[4.0,)</versionRange>\r
+                                        <goals>\r
+                                            <goal>antlr4</goal>\r
+                                        </goals>\r
+                                    </pluginExecutionFilter>\r
+                                    <action>\r
+                                        <execute></execute>\r
+                                    </action>\r
+                                </pluginExecution>\r
+                            </pluginExecutions>\r
+                        </lifecycleMappingMetadata>\r
+                    </configuration>\r
+                </plugin>\r
+            </plugins>\r
+        </pluginManagement>\r
+    </build>\r
+</project>\r
diff --git a/yang-model-parser-impl/src/main/antlr/YangLexer.g4 b/yang-model-parser-impl/src/main/antlr/YangLexer.g4
new file mode 100644 (file)
index 0000000..1c51135
--- /dev/null
@@ -0,0 +1,109 @@
+lexer grammar YangLexer;
+
+@header {
+package org.opendaylight.controller.antlrv4.code.gen;
+}
+
+tokens{
+    SEMICOLON,
+    LEFT_BRACE,
+    RIGHT_BRACE
+}
+
+
+PLUS : '+'-> pushMode(VALUE_MODE);
+WS : [ \n\r\t] -> skip;
+LINE_COMMENT :  ('//' (~( '\r' | '\n' )*)) -> skip;
+
+START_BLOCK_COMMENT : '/*' ->pushMode(BLOCK_COMMENT_MODE), skip ;
+
+
+SEMICOLON : ';' ->type(SEMICOLON);
+LEFT_BRACE : '{' ->type(LEFT_BRACE);
+RIGHT_BRACE : '}' ->type(RIGHT_BRACE);
+
+YIN_ELEMENT_KEYWORD : 'yin-element'-> pushMode(VALUE_MODE);
+YANG_VERSION_KEYWORD: 'yang-version'-> pushMode(VALUE_MODE);
+WHEN_KEYWORD : 'when'-> pushMode(VALUE_MODE);
+VALUE_KEYWORD : 'value'-> pushMode(VALUE_MODE);
+USES_KEYWORD : 'uses'-> pushMode(VALUE_MODE);
+UNITS_KEYWORD : 'units'-> pushMode(VALUE_MODE);
+UNIQUE_KEYWORD : 'unique'-> pushMode(VALUE_MODE);
+TYPEDEF_KEYWORD : 'typedef'-> pushMode(VALUE_MODE);
+TYPE_KEYWORD : 'type'-> pushMode(VALUE_MODE);
+SUBMODULE_KEYWORD : 'submodule'-> pushMode(VALUE_MODE);
+STATUS_KEYWORD : 'status'-> pushMode(VALUE_MODE);
+RPC_KEYWORD : 'rpc'-> pushMode(VALUE_MODE);
+REVISION_DATE_KEYWORD : 'revision-date'-> pushMode(VALUE_MODE);
+REVISION_KEYWORD : 'revision'-> pushMode(VALUE_MODE);
+REQUIRE_INSTANCE_KEYWORD : 'require-instance'-> pushMode(VALUE_MODE);
+REFINE_KEYWORD : 'refine'-> pushMode(VALUE_MODE);
+REFERENCE_KEYWORD : 'reference'-> pushMode(VALUE_MODE);
+RANGE_KEYWORD : 'range'-> pushMode(VALUE_MODE);
+PRESENCE_KEYWORD : 'presence'-> pushMode(VALUE_MODE);
+PREFIX_KEYWORD : 'prefix'-> pushMode(VALUE_MODE);
+POSITION_KEYWORD : 'position'-> pushMode(VALUE_MODE);
+PATTERN_KEYWORD : 'pattern'-> pushMode(VALUE_MODE);
+PATH_KEYWORD : 'path'-> pushMode(VALUE_MODE);
+OUTPUT_KEYWORD : 'output';
+ORGANIZATION_KEYWORD: 'organization'-> pushMode(VALUE_MODE);
+ORDERED_BY_KEYWORD : 'ordered-by'-> pushMode(VALUE_MODE);
+NOTIFICATION_KEYWORD: 'notification'-> pushMode(VALUE_MODE);
+NAMESPACE_KEYWORD : 'namespace'-> pushMode(VALUE_MODE);
+MUST_KEYWORD : 'must'-> pushMode(VALUE_MODE);
+MODULE_KEYWORD : 'module'-> pushMode(VALUE_MODE);
+MIN_ELEMENTS_KEYWORD : 'min-elements'-> pushMode(VALUE_MODE);
+MAX_ELEMENTS_KEYWORD : 'max-elements'-> pushMode(VALUE_MODE);
+MANDATORY_KEYWORD : 'mandatory'-> pushMode(VALUE_MODE);
+LIST_KEYWORD : 'list'-> pushMode(VALUE_MODE);
+LENGTH_KEYWORD : 'length'-> pushMode(VALUE_MODE);
+LEAF_LIST_KEYWORD : 'leaf-list'-> pushMode(VALUE_MODE);
+LEAF_KEYWORD : 'leaf'-> pushMode(VALUE_MODE);
+KEY_KEYWORD : 'key'-> pushMode(VALUE_MODE);
+INPUT_KEYWORD : 'input';
+INCLUDE_KEYWORD : 'include'-> pushMode(VALUE_MODE);
+IMPORT_KEYWORD : 'import'-> pushMode(VALUE_MODE);
+IF_FEATURE_KEYWORD : 'if-feature'-> pushMode(VALUE_MODE);
+IDENTITY_KEYWORD : 'identity'-> pushMode(VALUE_MODE);
+GROUPING_KEYWORD : 'grouping'-> pushMode(VALUE_MODE);
+FRACTION_DIGITS_KEYWORD : 'fraction-digits'-> pushMode(VALUE_MODE);
+FEATURE_KEYWORD : 'feature'-> pushMode(VALUE_MODE);
+DEVIATE_KEYWORD : 'deviate'-> pushMode(VALUE_MODE);
+DEVIATION_KEYWORD : 'deviation'-> pushMode(VALUE_MODE);
+EXTENSION_KEYWORD : 'extension'-> pushMode(VALUE_MODE);
+ERROR_MESSAGE_KEYWORD : 'error-message'-> pushMode(VALUE_MODE);
+ERROR_APP_TAG_KEYWORD : 'error-app-tag'-> pushMode(VALUE_MODE);
+ENUM_KEYWORD : 'enum'-> pushMode(VALUE_MODE);
+DESCRIPTION_KEYWORD : 'description'-> pushMode(VALUE_MODE);
+DEFAULT_KEYWORD : 'default'-> pushMode(VALUE_MODE);
+CONTAINER_KEYWORD : 'container'-> pushMode(VALUE_MODE);
+CONTACT_KEYWORD : 'contact'-> pushMode(VALUE_MODE);
+CONFIG_KEYWORD : 'config'-> pushMode(VALUE_MODE);
+CHOICE_KEYWORD: 'choice'-> pushMode(VALUE_MODE);
+CASE_KEYWORD : 'case'-> pushMode(VALUE_MODE);
+BIT_KEYWORD : 'bit'-> pushMode(VALUE_MODE);
+BELONGS_TO_KEYWORD : 'belongs-to'-> pushMode(VALUE_MODE);
+BASE_KEYWORD : 'base'-> pushMode(VALUE_MODE);
+AUGMENT_KEYWORD : 'augment'-> pushMode(VALUE_MODE);
+ARGUMENT_KEYWORD : 'argument'-> pushMode(VALUE_MODE);
+ANYXML_KEYWORD : 'anyxml'-> pushMode(VALUE_MODE);
+
+IDENTIFIER : [/.a-zA-Z_0-9\-][a-zA-Z0-9_\-.:]* -> pushMode(VALUE_MODE);
+
+mode VALUE_MODE;
+
+fragment ESC :  '\\' (["\\/bfnrt] | UNICODE) ;
+fragment UNICODE : 'u' HEX HEX HEX HEX ;
+fragment HEX : [0-9a-fA-F] ;
+          
+END_IDENTIFIER_SEMICOLON : ';' -> type(SEMICOLON),popMode;
+END_IDENTIFIER_LEFT_BRACE : '{' ->type(LEFT_BRACE), popMode;
+fragment SUB_STRING : ('"' (ESC | ~["])*'"') | ('\'' (ESC | ~['])*'\'') ;
+
+STRING: (SUB_STRING |  (~( '\r' | '\n' | ' ' | ';' | '{' )+)) ->popMode;// IDENTIFIER ;
+S : [ \n\r\t] -> skip;    
+
+mode BLOCK_COMMENT_MODE;
+END_BLOCK_COMMENT : '*/' -> popMode,skip;
+BLOCK_COMMENT :  . ->more,skip;
\ No newline at end of file
diff --git a/yang-model-parser-impl/src/main/antlr/YangParser.g4 b/yang-model-parser-impl/src/main/antlr/YangParser.g4
new file mode 100644 (file)
index 0000000..c814831
--- /dev/null
@@ -0,0 +1,123 @@
+parser grammar YangParser;
+
+@header {
+package org.opendaylight.controller.antlrv4.code.gen;
+}
+
+options{
+    tokenVocab=YangLexer;
+    
+}
+
+
+yang : module_stmt | submodule_stmt ;
+
+string : STRING (PLUS STRING)*;
+
+identifier_stmt : IDENTIFIER string? stmtend;
+                  
+stmtend : (SEMICOLON) | (LEFT_BRACE identifier_stmt? RIGHT_BRACE);
+deviate_replace_stmt : DEVIATE_KEYWORD string /* REPLACE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |type_stmt | units_stmt | default_stmt | config_stmt | mandatory_stmt | min_elements_stmt | max_elements_stmt )* RIGHT_BRACE));
+deviate_delete_stmt : DEVIATE_KEYWORD string /* DELETE_KEYWORD */ (SEMICOLON | (LEFT_BRACE (identifier_stmt |units_stmt | must_stmt | unique_stmt | default_stmt )* RIGHT_BRACE));
+deviate_add_stmt : DEVIATE_KEYWORD string /*ADD_KEYWORD*/ (SEMICOLON | (LEFT_BRACE (identifier_stmt |units_stmt | must_stmt | unique_stmt | default_stmt | config_stmt | mandatory_stmt  | min_elements_stmt  | max_elements_stmt )* RIGHT_BRACE));
+deviate_not_supported_stmt : DEVIATE_KEYWORD string /*NOT_SUPPORTED_KEYWORD*/ (SEMICOLON | (LEFT_BRACE identifier_stmt? RIGHT_BRACE));
+deviation_stmt : DEVIATION_KEYWORD string LEFT_BRACE (identifier_stmt |description_stmt | reference_stmt | deviate_not_supported_stmt | deviate_add_stmt | deviate_replace_stmt | deviate_delete_stmt)+ RIGHT_BRACE;
+notification_stmt : NOTIFICATION_KEYWORD string (SEMICOLON | (LEFT_BRACE (identifier_stmt |if_feature_stmt | status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | data_def_stmt )* RIGHT_BRACE));
+output_stmt : OUTPUT_KEYWORD LEFT_BRACE (identifier_stmt |typedef_stmt | grouping_stmt | data_def_stmt )+ RIGHT_BRACE;
+input_stmt : INPUT_KEYWORD LEFT_BRACE (identifier_stmt |typedef_stmt | grouping_stmt | data_def_stmt )+ RIGHT_BRACE;
+rpc_stmt : RPC_KEYWORD string (SEMICOLON | (LEFT_BRACE (identifier_stmt |if_feature_stmt  | status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | input_stmt | output_stmt )* RIGHT_BRACE));
+when_stmt : WHEN_KEYWORD string (SEMICOLON | (LEFT_BRACE (identifier_stmt |description_stmt | reference_stmt )* RIGHT_BRACE));
+
+augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)+ RIGHT_BRACE;
+uses_augment_stmt : AUGMENT_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt | case_stmt)+ RIGHT_BRACE;
+refine_anyxml_stmts : (identifier_stmt |must_stmt | config_stmt | mandatory_stmt | description_stmt | reference_stmt )*;
+refine_case_stmts : (identifier_stmt |description_stmt | reference_stmt )*;
+refine_choice_stmts : (identifier_stmt |default_stmt | config_stmt | mandatory_stmt | description_stmt | reference_stmt )*;
+refine_list_stmts : (identifier_stmt |must_stmt | config_stmt | min_elements_stmt | max_elements_stmt | description_stmt | reference_stmt )*;
+refine_leaf_list_stmts : (identifier_stmt |must_stmt | config_stmt | min_elements_stmt | max_elements_stmt | description_stmt | reference_stmt )*;
+refine_leaf_stmts : (identifier_stmt |must_stmt | default_stmt | config_stmt | mandatory_stmt | description_stmt | reference_stmt )*;
+refine_container_stmts : (identifier_stmt |must_stmt | presence_stmt | config_stmt | description_stmt | reference_stmt )*;
+refine_pom : (refine_container_stmts | refine_leaf_stmts | refine_leaf_list_stmts | refine_list_stmts | refine_choice_stmts | refine_case_stmts | refine_anyxml_stmts);
+refine_stmt : REFINE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (refine_pom) RIGHT_BRACE));
+uses_stmt : USES_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | refine_stmt | uses_augment_stmt )* RIGHT_BRACE));
+anyxml_stmt : ANYXML_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | must_stmt | config_stmt | mandatory_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+case_stmt : CASE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt | data_def_stmt )* RIGHT_BRACE));
+short_case_stmt : container_stmt | leaf_stmt | leaf_list_stmt | list_stmt | anyxml_stmt;
+choice_stmt : CHOICE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | default_stmt | config_stmt | mandatory_stmt | status_stmt | description_stmt | reference_stmt | short_case_stmt | case_stmt)* RIGHT_BRACE));
+unique_stmt : UNIQUE_KEYWORD string stmtend;
+key_stmt : KEY_KEYWORD string stmtend;
+list_stmt : LIST_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | must_stmt | key_stmt | unique_stmt | config_stmt | min_elements_stmt | max_elements_stmt | ordered_by_stmt | status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | data_def_stmt )+ RIGHT_BRACE;
+leaf_list_stmt : LEAF_LIST_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | type_stmt | units_stmt | must_stmt | config_stmt | min_elements_stmt | max_elements_stmt | ordered_by_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE;
+leaf_stmt : LEAF_KEYWORD string LEFT_BRACE  (identifier_stmt |when_stmt | if_feature_stmt | type_stmt | units_stmt | must_stmt | default_stmt | config_stmt | mandatory_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE;
+container_stmt : CONTAINER_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt | when_stmt | if_feature_stmt | must_stmt | presence_stmt | config_stmt | status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | data_def_stmt )* RIGHT_BRACE));
+grouping_stmt : GROUPING_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |status_stmt | description_stmt | reference_stmt | typedef_stmt | grouping_stmt | data_def_stmt )* RIGHT_BRACE));
+value_stmt : VALUE_KEYWORD string stmtend;
+max_value_arg : /*UNBOUNDED_KEYWORD |*/ string;
+min_value_arg : /*UNBOUNDED_KEYWORD |*/ string;
+max_elements_stmt : MAX_ELEMENTS_KEYWORD max_value_arg stmtend;
+min_elements_stmt : MIN_ELEMENTS_KEYWORD min_value_arg stmtend;
+error_app_tag_stmt : ERROR_APP_TAG_KEYWORD string stmtend;
+error_message_stmt : ERROR_MESSAGE_KEYWORD string stmtend;
+must_stmt : MUST_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+ordered_by_arg : string; /*USER_KEYWORD | SYSTEM_KEYWORD;*/
+ordered_by_stmt : ORDERED_BY_KEYWORD ordered_by_arg stmtend;
+presence_stmt : PRESENCE_KEYWORD string stmtend;
+mandatory_arg :string; // TRUE_KEYWORD | FALSE_KEYWORD;
+mandatory_stmt : MANDATORY_KEYWORD mandatory_arg stmtend;
+config_arg : string; //  TRUE_KEYWORD | FALSE_KEYWORD;
+config_stmt : CONFIG_KEYWORD config_arg stmtend;
+status_arg : string; /*CURRENT_KEYWORD | OBSOLETE_KEYWORD | DEPRECATED_KEYWORD; */
+status_stmt : STATUS_KEYWORD status_arg stmtend;
+position_stmt : POSITION_KEYWORD string stmtend;
+bit_stmt : BIT_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |position_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+bits_specification : bit_stmt (bit_stmt | identifier_stmt)*;
+union_specification : type_stmt (identifier_stmt | type_stmt )+;
+identityref_specification : base_stmt  ;
+instance_identifier_specification : (require_instance_stmt )?;
+require_instance_arg :string; // TRUE_KEYWORD | FALSE_KEYWORD;
+require_instance_stmt : REQUIRE_INSTANCE_KEYWORD require_instance_arg stmtend;
+path_stmt : PATH_KEYWORD string stmtend;
+leafref_specification : path_stmt;
+enum_stmt : ENUM_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |value_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+enum_specification : enum_stmt (identifier_stmt | enum_stmt )*;
+default_stmt : DEFAULT_KEYWORD string stmtend;
+pattern_stmt : PATTERN_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+length_stmt : LENGTH_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+string_restrictions : (length_stmt | pattern_stmt )*;
+fraction_digits_stmt : FRACTION_DIGITS_KEYWORD string stmtend;
+decimal64_specification : (numerical_restrictions? (identifier_stmt)* fraction_digits_stmt | fraction_digits_stmt (identifier_stmt)* numerical_restrictions?);
+range_stmt : RANGE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt |error_message_stmt | error_app_tag_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+numerical_restrictions : range_stmt ;
+type_body_stmts : (identifier_stmt)* (numerical_restrictions | decimal64_specification | string_restrictions | enum_specification | leafref_specification | identityref_specification | instance_identifier_specification | bits_specification | union_specification) (identifier_stmt)*;
+type_stmt : TYPE_KEYWORD string (SEMICOLON | (LEFT_BRACE  type_body_stmts RIGHT_BRACE));
+typedef_stmt : TYPEDEF_KEYWORD string LEFT_BRACE  (identifier_stmt | type_stmt | units_stmt | default_stmt | status_stmt | description_stmt | reference_stmt )+ RIGHT_BRACE;
+if_feature_stmt : IF_FEATURE_KEYWORD string stmtend;
+feature_stmt : FEATURE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt | if_feature_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+base_stmt : BASE_KEYWORD string stmtend;
+identity_stmt : IDENTITY_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt | base_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+yin_element_arg : string; // TRUE_KEYWORD | FALSE_KEYWORD;
+yin_element_stmt : YIN_ELEMENT_KEYWORD yin_element_arg stmtend;
+argument_stmt : ARGUMENT_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt)? (yin_element_stmt )? (identifier_stmt)* RIGHT_BRACE));
+extension_stmt : EXTENSION_KEYWORD string (SEMICOLON | (LEFT_BRACE  (identifier_stmt | argument_stmt | status_stmt | description_stmt | reference_stmt )* RIGHT_BRACE));
+revision_date_stmt : REVISION_DATE_KEYWORD string stmtend;
+revision_stmt : REVISION_KEYWORD string (SEMICOLON | (LEFT_BRACE  (description_stmt )? (reference_stmt )? RIGHT_BRACE));
+units_stmt : UNITS_KEYWORD string stmtend;
+reference_stmt : REFERENCE_KEYWORD string stmtend;
+description_stmt : DESCRIPTION_KEYWORD string stmtend;
+contact_stmt : CONTACT_KEYWORD string stmtend;
+organization_stmt : ORGANIZATION_KEYWORD string stmtend;
+belongs_to_stmt : BELONGS_TO_KEYWORD string LEFT_BRACE  prefix_stmt  RIGHT_BRACE;
+prefix_stmt : PREFIX_KEYWORD string stmtend;
+namespace_stmt : NAMESPACE_KEYWORD string stmtend;
+include_stmt : INCLUDE_KEYWORD string (SEMICOLON | (LEFT_BRACE  (revision_date_stmt )? RIGHT_BRACE));
+import_stmt : IMPORT_KEYWORD string LEFT_BRACE  prefix_stmt  (revision_date_stmt )? RIGHT_BRACE;
+yang_version_stmt : YANG_VERSION_KEYWORD string stmtend;
+data_def_stmt : container_stmt | leaf_stmt | leaf_list_stmt | list_stmt | choice_stmt | anyxml_stmt | uses_stmt;
+body_stmts : (( identifier_stmt| extension_stmt | feature_stmt | identity_stmt | typedef_stmt | grouping_stmt | data_def_stmt | augment_stmt | rpc_stmt | notification_stmt | deviation_stmt) )*;
+revision_stmts : (revision_stmt )*;
+linkage_stmts : (import_stmt | include_stmt )*;
+meta_stmts : (organization_stmt | contact_stmt | description_stmt | reference_stmt )*;
+submodule_header_stmts : (yang_version_stmt | belongs_to_stmt)+ ;
+module_header_stmts :   (yang_version_stmt | namespace_stmt | prefix_stmt)+ ;
+submodule_stmt : SUBMODULE_KEYWORD string LEFT_BRACE  submodule_header_stmts linkage_stmts meta_stmts revision_stmts body_stmts RIGHT_BRACE;
+module_stmt : MODULE_KEYWORD string LEFT_BRACE  module_header_stmts linkage_stmts meta_stmts revision_stmts body_stmts RIGHT_BRACE;
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractBuilder.java
new file mode 100644 (file)
index 0000000..786a7ec
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+
+/**
+ * Basic implementation of Builder.
+ */
+public abstract class AbstractBuilder implements Builder {
+    protected String moduleName;
+    protected final int line;
+    protected Builder parent;
+
+    protected List<UnknownSchemaNode> unknownNodes;
+    protected final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+
+    protected AbstractBuilder(final String moduleName, final int line) {
+        this.moduleName = moduleName;
+        this.line = line;
+    }
+
+    @Override
+    public String getModuleName() {
+        return moduleName;
+    }
+
+    @Override
+    public void setModuleName(final String moduleName) {
+        this.moduleName = moduleName;
+    }
+
+    @Override
+    public int getLine() {
+        return line;
+    }
+
+    @Override
+    public Builder getParent() {
+        return parent;
+    }
+
+    @Override
+    public void setParent(final Builder parent) {
+        this.parent = parent;
+    }
+
+    @Override
+    public List<UnknownSchemaNodeBuilder> getUnknownNodeBuilders() {
+        return addedUnknownNodes;
+    }
+
+    @Override
+    public void addUnknownNodeBuilder(UnknownSchemaNodeBuilder unknownNode) {
+        addedUnknownNodes.add(unknownNode);
+    }
+
+    public void setUnknownNodes(List<UnknownSchemaNode> unknownNodes) {
+        this.unknownNodes = unknownNodes;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java
new file mode 100644 (file)
index 0000000..e85305d
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+/**
+ * Basic implementation of DataNodeContainerBuilder.
+ */
+public abstract class AbstractDataNodeContainerBuilder extends AbstractBuilder implements DataNodeContainerBuilder {
+    protected final QName qname;
+
+    protected Set<DataSchemaNode> childNodes;
+    protected final Set<DataSchemaNodeBuilder> addedChildNodes = new HashSet<DataSchemaNodeBuilder>();
+
+    protected Set<GroupingDefinition> groupings;
+    protected final Set<GroupingBuilder> addedGroupings = new HashSet<GroupingBuilder>();
+
+    protected AbstractDataNodeContainerBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line);
+        this.qname = qname;
+    }
+
+    @Override
+    public QName getQName() {
+        return qname;
+    }
+
+    @Override
+    public Set<DataSchemaNode> getChildNodes() {
+        if (childNodes == null) {
+            return Collections.emptySet();
+        }
+        return childNodes;
+    }
+
+    public void setChildNodes(Set<DataSchemaNode> childNodes) {
+        this.childNodes = childNodes;
+    }
+
+    @Override
+    public Set<DataSchemaNodeBuilder> getChildNodeBuilders() {
+        return addedChildNodes;
+    }
+
+    @Override
+    public DataSchemaNodeBuilder getDataChildByName(final String name) {
+        for (DataSchemaNodeBuilder child : addedChildNodes) {
+            if (child.getQName().getLocalName().equals(name)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void addChildNode(DataSchemaNodeBuilder child) {
+        String childName = child.getQName().getLocalName();
+        for (DataSchemaNodeBuilder addedChildNode : addedChildNodes) {
+            if (addedChildNode.getQName().getLocalName().equals(childName)) {
+                throw new YangParseException(child.getModuleName(), child.getLine(), "Can not add '" + child + "' to '"
+                        + this + "' in module '" + moduleName + "': node with same name already declared at line "
+                        + addedChildNode.getLine());
+            }
+        }
+        addedChildNodes.add(child);
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        if (groupings == null) {
+            return Collections.emptySet();
+        }
+        return groupings;
+    }
+
+    public void setGroupings(final Set<GroupingDefinition> groupings) {
+        this.groupings = groupings;
+    }
+
+    public Set<GroupingBuilder> getGroupingBuilders() {
+        return addedGroupings;
+    }
+
+    @Override
+    public void addGrouping(GroupingBuilder grouping) {
+        String groupingName = grouping.getQName().getLocalName();
+        for (GroupingBuilder addedGrouping : addedGroupings) {
+            if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
+                throw new YangParseException(grouping.getModuleName(), grouping.getLine(), "Can not add '" + grouping
+                        + "': grouping with same name already declared in module '" + moduleName + "' at line "
+                        + addedGrouping.getLine());
+            }
+        }
+        addedGroupings.add(grouping);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..2727bc9
--- /dev/null
@@ -0,0 +1,83 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.parser.builder.api;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.model.api.SchemaPath;\r
+import org.opendaylight.controller.yang.model.api.Status;\r
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;\r
+\r
+/**\r
+ * Basic implementation of SchemaNodeBuilder.\r
+ */\r
+public abstract class AbstractSchemaNodeBuilder extends AbstractBuilder implements SchemaNodeBuilder {\r
+    protected final QName qname;\r
+    protected SchemaPath schemaPath;\r
+    protected String description;\r
+    protected String reference;\r
+    protected Status status = Status.CURRENT;\r
+    protected List<UnknownSchemaNode> unknownNodes;\r
+\r
+    protected AbstractSchemaNodeBuilder(final String moduleName, final int line, final QName qname) {\r
+        super(moduleName, line);\r
+        this.qname = qname;\r
+    }\r
+\r
+    public QName getQName() {\r
+        return qname;\r
+    }\r
+\r
+    @Override\r
+    public SchemaPath getPath() {\r
+        return schemaPath;\r
+    }\r
+\r
+    @Override\r
+    public void setPath(SchemaPath schemaPath) {\r
+        this.schemaPath = schemaPath;\r
+    }\r
+\r
+    @Override\r
+    public String getDescription() {\r
+        return description;\r
+    }\r
+\r
+    @Override\r
+    public void setDescription(String description) {\r
+        this.description = description;\r
+    }\r
+\r
+    @Override\r
+    public String getReference() {\r
+        return reference;\r
+    }\r
+\r
+    @Override\r
+    public void setReference(String reference) {\r
+        this.reference = reference;\r
+    }\r
+\r
+    @Override\r
+    public Status getStatus() {\r
+        return status;\r
+    }\r
+\r
+    @Override\r
+    public void setStatus(Status status) {\r
+        if (status != null) {\r
+            this.status = status;\r
+        }\r
+    }\r
+\r
+    public void setUnknownNodes(List<UnknownSchemaNode> unknownNodes) {\r
+        this.unknownNodes = unknownNodes;\r
+    }\r
+\r
+}\r
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractTypeAwareBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractTypeAwareBuilder.java
new file mode 100644 (file)
index 0000000..23ded94
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+
+/**
+ * Basic implementation for TypeAwareBuilder builders.
+ */
+public abstract class AbstractTypeAwareBuilder extends AbstractBuilder implements TypeAwareBuilder {
+    protected final QName qname;
+    protected TypeDefinition<?> type;
+    protected TypeDefinitionBuilder typedef;
+
+    public AbstractTypeAwareBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line);
+        this.qname = qname;
+    }
+
+    @Override
+    public QName getQName() {
+        return qname;
+    }
+
+    @Override
+    public TypeDefinition<?> getType() {
+        return type;
+    }
+
+    @Override
+    public TypeDefinitionBuilder getTypedef() {
+        return typedef;
+    }
+
+    @Override
+    public void setType(TypeDefinition<?> type) {
+        this.type = type;
+        this.typedef = null;
+    }
+
+    @Override
+    public void setTypedef(TypeDefinitionBuilder typedef) {
+        this.typedef = typedef;
+        this.type = null;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationSchemaBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationSchemaBuilder.java
new file mode 100644 (file)
index 0000000..98cdb67
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+
+/**
+ * Interface for builders of 'augment' statement.
+ */
+public interface AugmentationSchemaBuilder extends DataNodeContainerBuilder {
+
+    String getWhenCondition();
+
+    void addWhenCondition(String whenCondition);
+
+    void setDescription(String description);
+
+    void setReference(String reference);
+
+    void setStatus(Status status);
+
+    String getTargetPathAsString();
+
+    SchemaPath getTargetPath();
+
+    void setTargetPath(SchemaPath path);
+
+    AugmentationSchema build();
+
+    boolean isResolved();
+
+    void setResolved(boolean resolved);
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationTargetBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationTargetBuilder.java
new file mode 100644 (file)
index 0000000..639e18c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+/**
+ * Interface for builders of those nodes, which can be augmentation targets.
+ */
+public interface AugmentationTargetBuilder {
+
+    /**
+     * Add augment, which points to this node.
+     *
+     * @param augment
+     *            augment which points to this node
+     */
+    void addAugmentation(AugmentationSchemaBuilder augment);
+
+    /**
+     * Build again already built data node.
+     *
+     * In general, when Builder.build is called first time, it creates YANG data
+     * model node instance. With every other call it just return this instance
+     * without checking for properties change. This method causes that builder
+     * object process again all its properties and return an updated instance of
+     * YANG data node.
+     */
+    void rebuild();
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/Builder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/Builder.java
new file mode 100644 (file)
index 0000000..b849f20
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.List;
+
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+
+/**
+ * Parent interface for all builder interfaces.
+ */
+public interface Builder {
+
+    /**
+     * Get name of module in which this node is declared.
+     *
+     * @return module name
+     */
+    String getModuleName();
+
+    /**
+     * Set name of module in which this node is declared.
+     *
+     * @param moduleName
+     */
+    void setModuleName(String moduleName);
+
+    /**
+     * Get current line in yang file.
+     *
+     * @return current line in yang file
+     */
+    int getLine();
+
+    /**
+     * Get parent node of this node.
+     *
+     * @return parent node builder or null if this is top level node
+     */
+    Builder getParent();
+
+    /**
+     * Set parent of this node.
+     *
+     * @param parent
+     *            parent node builder
+     */
+    void setParent(Builder parent);
+
+    /**
+     * Add unknown node to this builder.
+     *
+     * @param unknownNode
+     */
+    void addUnknownNodeBuilder(UnknownSchemaNodeBuilder unknownNode);
+
+    /**
+     * Get builders of unknown nodes defined in this node.
+     *
+     * @return collection of UnknownSchemaNodeBuilder objects
+     */
+    List<UnknownSchemaNodeBuilder> getUnknownNodeBuilders();
+
+    /**
+     * Build YANG data model node.
+     *
+     * This method should create an instance of YANG data model node. After
+     * creating an instance, this instance should be returned for each call
+     * without repeating build process.
+     *
+     * @return YANG data model node
+     */
+    Object build();
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataNodeContainerBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataNodeContainerBuilder.java
new file mode 100644 (file)
index 0000000..7a5f80d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.Set;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+
+/**
+ * Interface for all yang data-node containers [augment, case, container,
+ * grouping, list, module, notification].
+ */
+public interface DataNodeContainerBuilder extends Builder {
+
+    /**
+     * Get qname of this node.
+     *
+     * @return QName of this node
+     */
+    QName getQName();
+
+    /**
+     * Get schema path of this node.
+     *
+     * @return SchemaPath of this node
+     */
+    SchemaPath getPath();
+
+    /**
+     * Get already built child nodes.
+     *
+     * @return collection of child nodes
+     */
+    Set<DataSchemaNode> getChildNodes();
+
+    /**
+     * Get builders of child nodes.
+     *
+     * @return collection child nodes builders
+     */
+    Set<DataSchemaNodeBuilder> getChildNodeBuilders();
+
+    /**
+     * Get child node by name.
+     *
+     * @param name
+     *            name of child to seek
+     * @return child node with given name if present, null otherwise
+     */
+    DataSchemaNodeBuilder getDataChildByName(String name);
+
+    /**
+     * Add builder of child node to this node.
+     *
+     * @param childNode
+     */
+    void addChildNode(DataSchemaNodeBuilder childNode);
+
+    /**
+     * Get already built groupings defined in this node.
+     *
+     * @return collection of GroupingDefinition objects
+     */
+    Set<GroupingDefinition> getGroupings();
+
+    /**
+     * Get builders of groupings defined in this node.
+     *
+     * @return collection of grouping builders
+     */
+    Set<GroupingBuilder> getGroupingBuilders();
+
+    /**
+     * Add builder of grouping statement to this node.
+     *
+     * @param groupingBuilder
+     */
+    void addGrouping(GroupingBuilder groupingBuilder);
+
+    /**
+     * Add builder of uses statement to this node.
+     *
+     * @param usesBuilder
+     */
+    void addUsesNode(UsesNodeBuilder usesBuilder);
+
+    /**
+     * Get builders of typedef statement defined in this node.
+     *
+     * @return
+     */
+    Set<TypeDefinitionBuilder> getTypeDefinitionBuilders();
+
+    /**
+     * Add typedef builder to this node.
+     *
+     * @param typedefBuilder
+     */
+    void addTypedef(TypeDefinitionBuilder typedefBuilder);
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..a217750
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.impl.ConstraintsBuilder;
+
+/**
+ * Interface for all yang data-schema nodes [anyxml, case, container, grouping,
+ * list, module, notification].
+ */
+public interface DataSchemaNodeBuilder extends SchemaNodeBuilder {
+
+    /**
+     * Build DataSchemaNode object from this builder.
+     */
+    DataSchemaNode build();
+
+    /**
+     *
+     * @return true, if this node is added by augmentation, false otherwise
+     */
+    boolean isAugmenting();
+
+    /**
+     * Set if this node is added by augmentation.
+     *
+     * @param augmenting
+     */
+    void setAugmenting(boolean augmenting);
+
+    /**
+     * Get value of config statement.
+     *
+     * @return value of config statement
+     */
+    Boolean isConfiguration();
+
+    /**
+     * Set config statement.
+     *
+     * @param config
+     */
+    void setConfiguration(Boolean config);
+
+    /**
+     * Get constraints of this builder.
+     *
+     * @return constraints of this builder
+     */
+    ConstraintsBuilder getConstraints();
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingBuilder.java
new file mode 100644 (file)
index 0000000..74ee330
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+
+/**
+ * Interface for builders of 'grouping' statement.
+ */
+public interface GroupingBuilder extends DataNodeContainerBuilder, SchemaNodeBuilder, GroupingMember {
+
+    /**
+     * Build GroupingDefinition object from this builder.
+     */
+    GroupingDefinition build();
+
+    /**
+     * Get uses statement defined in this builder
+     *
+     * @return collection of builders of uses statements
+     */
+    Set<UsesNodeBuilder> getUses();
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingMember.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingMember.java
new file mode 100644 (file)
index 0000000..c074f60
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+/**
+ * Marker interface for nodes which can be defined in grouping statement.
+ * [anyxml, choice, container, grouping, leaf, leaf-list, list, typedef, uses]
+ */
+public interface GroupingMember extends Builder {
+
+    /**
+     *
+     * @return true, if this node is added by uses statement, false otherwise
+     */
+    boolean isAddedByUses();
+
+    /**
+     * Set if this node is added by uses.
+     *
+     * @param addedByUses
+     */
+    void setAddedByUses(boolean addedByUses);
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/SchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/SchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..13c96d3
--- /dev/null
@@ -0,0 +1,88 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.parser.builder.api;\r
+\r
+import org.opendaylight.controller.yang.common.QName;\r
+import org.opendaylight.controller.yang.model.api.SchemaNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaPath;\r
+import org.opendaylight.controller.yang.model.api.Status;\r
+\r
+/**\r
+ * Interface for all builders of SchemaNode nodes.\r
+ */\r
+public interface SchemaNodeBuilder extends Builder {\r
+\r
+    /**\r
+     * Get qname of this node.\r
+     *\r
+     * @return QName of this node\r
+     */\r
+    QName getQName();\r
+\r
+    /**\r
+     * Get schema path of this node.\r
+     *\r
+     * @return SchemaPath of this node\r
+     */\r
+    SchemaPath getPath();\r
+\r
+    /**\r
+     * Set schema path to this node.\r
+     *\r
+     * @param schemaPath\r
+     */\r
+    void setPath(SchemaPath schemaPath);\r
+\r
+    /**\r
+     * Get description of this node.\r
+     *\r
+     * @return description statement\r
+     */\r
+    String getDescription();\r
+\r
+    /**\r
+     * Set description to this node.\r
+     *\r
+     * @param description\r
+     */\r
+    void setDescription(String description);\r
+\r
+    /**\r
+     * Get reference of this node.\r
+     *\r
+     * @return reference statement\r
+     */\r
+    String getReference();\r
+\r
+    /**\r
+     * Set reference to this node.\r
+     *\r
+     * @param reference\r
+     */\r
+    void setReference(String reference);\r
+\r
+    /**\r
+     * Get status of this node.\r
+     *\r
+     * @return status statement\r
+     */\r
+    Status getStatus();\r
+\r
+    /**\r
+     * Set status to this node.\r
+     *\r
+     * @param status\r
+     */\r
+    void setStatus(Status status);\r
+\r
+    /**\r
+     * Build SchemaNode object from this builder.\r
+     */\r
+    SchemaNode build();\r
+\r
+}\r
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeAwareBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeAwareBuilder.java
new file mode 100644 (file)
index 0000000..8b2e669
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+
+/**
+ * Builders of all nodes, which can have 'type' statement must implement this
+ * interface. [typedef, type, leaf, leaf-list, deviate]
+ */
+public interface TypeAwareBuilder extends Builder {
+
+    /**
+     * Get qname of this node.
+     *
+     * @return QName of this node
+     */
+    QName getQName();
+
+    /**
+     * Get schema path of this node.
+     *
+     * @return SchemaPath of this node
+     */
+    SchemaPath getPath();
+
+    /**
+     * Get resolved type of this node.
+     *
+     * @return type of this node if it is already resolved, null otherwise
+     */
+    TypeDefinition<?> getType();
+
+    /**
+     * Get builder of type of this node.
+     *
+     * @return builder of type of this node or null of this builder has already
+     *         resolved type
+     */
+    TypeDefinitionBuilder getTypedef();
+
+    /**
+     * Set resolved type to this node.
+     *
+     * @param type
+     *            type to set
+     */
+    void setType(TypeDefinition<?> type);
+
+    /**
+     * Set builder of type to this node.
+     *
+     * @param typedef
+     *            builder of type to set
+     */
+    void setTypedef(TypeDefinitionBuilder typedef);
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeDefinitionBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeDefinitionBuilder.java
new file mode 100644 (file)
index 0000000..87c7b3c
--- /dev/null
@@ -0,0 +1,51 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.parser.builder.api;\r
+\r
+import java.util.List;\r
+\r
+import org.opendaylight.controller.yang.model.api.TypeDefinition;\r
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;\r
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;\r
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;\r
+\r
+/**\r
+ * Interface for builders of 'typedef' statement.\r
+ */\r
+public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuilder, GroupingMember {\r
+\r
+    TypeDefinition<?> build();\r
+\r
+    List<RangeConstraint> getRanges();\r
+\r
+    void setRanges(List<RangeConstraint> ranges);\r
+\r
+    List<LengthConstraint> getLengths();\r
+\r
+    void setLengths(List<LengthConstraint> lengths);\r
+\r
+    List<PatternConstraint> getPatterns();\r
+\r
+    void setPatterns(List<PatternConstraint> patterns);\r
+\r
+    Integer getFractionDigits();\r
+\r
+    void setFractionDigits(Integer fractionDigits);\r
+\r
+    List<UnknownSchemaNode> getUnknownNodes();\r
+\r
+    Object getDefaultValue();\r
+\r
+    void setDefaultValue(Object defaultValue);\r
+\r
+    String getUnits();\r
+\r
+    void setUnits(String units);\r
+\r
+}\r
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/UsesNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/UsesNodeBuilder.java
new file mode 100644 (file)
index 0000000..626f0f4
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.api;
+
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.util.RefineHolder;
+
+/**
+ * Interface for builders of 'uses' statement.
+ */
+public interface UsesNodeBuilder extends GroupingMember, Builder {
+
+    DataNodeContainerBuilder getParent();
+
+    String getGroupingName();
+
+    SchemaPath getGroupingPath();
+
+    void setGroupingPath(SchemaPath groupingPath);
+
+    Set<AugmentationSchemaBuilder> getAugmentations();
+
+    void addAugment(AugmentationSchemaBuilder builder);
+
+    boolean isAugmenting();
+
+    void setAugmenting(boolean augmenting);
+
+    List<RefineHolder> getRefines();
+
+    List<SchemaNodeBuilder> getRefineNodes();
+
+    void addRefine(RefineHolder refine);
+
+    void addRefineNode(SchemaNodeBuilder refineNode);
+
+    UsesNode build();
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AnyXmlBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AnyXmlBuilder.java
new file mode 100644 (file)
index 0000000..6b6063c
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class AnyXmlBuilder extends AbstractSchemaNodeBuilder implements DataSchemaNodeBuilder, GroupingMember {
+    private boolean built;
+    private final AnyXmlSchemaNodeImpl instance;
+    private final ConstraintsBuilder constraints;
+
+    private Boolean configuration;
+    private boolean augmenting;
+    private boolean addedByUses;
+
+    public AnyXmlBuilder(final String moduleName, final int line, final QName qname, final SchemaPath schemaPath) {
+        super(moduleName, line, qname);
+        this.schemaPath = schemaPath;
+        instance = new AnyXmlSchemaNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public AnyXmlBuilder(final AnyXmlBuilder builder) {
+        super(builder.getModuleName(), builder.getLine(), builder.getQName());
+        parent = builder.getParent();
+        instance = new AnyXmlSchemaNodeImpl(qname);
+        constraints = builder.getConstraints();
+        schemaPath = builder.getPath();
+        unknownNodes = builder.unknownNodes;
+        addedUnknownNodes.addAll(builder.getUnknownNodes());
+        description = builder.getDescription();
+        reference = builder.getReference();
+        status = builder.getStatus();
+        configuration = builder.isConfiguration();
+        augmenting = builder.isAugmenting();
+        addedByUses = builder.isAddedByUses();
+    }
+
+    @Override
+    public AnyXmlSchemaNode build() {
+        if (!built) {
+            instance.setPath(schemaPath);
+            instance.setConstraints(constraints.build());
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setConfiguration(configuration);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            built = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public List<UnknownSchemaNodeBuilder> getUnknownNodes() {
+        return addedUnknownNodes;
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(final boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    @Override
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(final Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AnyXmlBuilder other = (AnyXmlBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "anyxml " + qname.getLocalName();
+    }
+
+    private final class AnyXmlSchemaNodeImpl implements AnyXmlSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean configuration;
+        private ConstraintDefinition constraintsDef;
+        private boolean augmenting;
+        private boolean addedByUses;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private AnyXmlSchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraintsDef;
+        }
+
+        private void setConstraints(ConstraintDefinition constraintsDef) {
+            this.constraintsDef = constraintsDef;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            AnyXmlSchemaNodeImpl other = (AnyXmlSchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(AnyXmlSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append(", path=" + path);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AugmentationSchemaBuilderImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AugmentationSchemaBuilderImpl.java
new file mode 100644 (file)
index 0000000..cdb751f
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.ParserListenerUtils;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class AugmentationSchemaBuilderImpl extends AbstractDataNodeContainerBuilder implements
+        AugmentationSchemaBuilder {
+    private boolean built;
+    private final AugmentationSchemaImpl instance;
+
+    private String whenCondition;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+
+    private final String augmentTargetStr;
+    private SchemaPath dirtyAugmentTarget;
+    private SchemaPath finalAugmentTarget;
+
+    private final Set<UsesNodeBuilder> usesNodes = new HashSet<UsesNodeBuilder>();
+    private boolean resolved;
+
+    AugmentationSchemaBuilderImpl(final String moduleName, final int line, final String augmentTargetStr) {
+        super(moduleName, line, null);
+        this.augmentTargetStr = augmentTargetStr;
+        final SchemaPath targetPath = ParserListenerUtils.parseAugmentPath(augmentTargetStr);
+        dirtyAugmentTarget = targetPath;
+        instance = new AugmentationSchemaImpl(targetPath);
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<GroupingBuilder> getGroupingBuilders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public void addGrouping(GroupingBuilder grouping) {
+        throw new YangParseException(moduleName, line, "augment can not contains grouping statement");
+    }
+
+    @Override
+    public void addUsesNode(UsesNodeBuilder usesBuilder) {
+        usesNodes.add(usesBuilder);
+    }
+
+    /**
+     * Always returns null.
+     */
+    @Override
+    public SchemaPath getPath() {
+        return null;
+    }
+
+    @Override
+    public AugmentationSchema build() {
+        if (!built) {
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setTargetPath(finalAugmentTarget);
+
+            RevisionAwareXPath whenStmt;
+            if (whenCondition == null) {
+                whenStmt = null;
+            } else {
+                whenStmt = new RevisionAwareXPathImpl(whenCondition, false);
+            }
+            instance.setWhenCondition(whenStmt);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            for (DataSchemaNodeBuilder node : addedChildNodes) {
+                childs.put(node.getQName(), node.build());
+            }
+            instance.setChildNodes(childs);
+
+            // USES
+            final Set<UsesNode> usesNodeDefinitions = new HashSet<UsesNode>();
+            for (UsesNodeBuilder builder : usesNodes) {
+                usesNodeDefinitions.add(builder.build());
+            }
+            instance.setUses(usesNodeDefinitions);
+
+            // UNKNOWN NODES
+            List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                unknownNodes.add(b.build());
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            built = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public boolean isResolved() {
+        return resolved;
+    }
+
+    @Override
+    public void setResolved(boolean resolved) {
+        this.resolved = resolved;
+    }
+
+    public String getWhenCondition() {
+        return whenCondition;
+    }
+
+    public void addWhenCondition(String whenCondition) {
+        this.whenCondition = whenCondition;
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public void addTypedef(TypeDefinitionBuilder type) {
+        throw new YangParseException(moduleName, line, "Augmentation can not contains typedef statement.");
+    }
+
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public void setStatus(Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    @Override
+    public SchemaPath getTargetPath() {
+        return dirtyAugmentTarget;
+    }
+
+    @Override
+    public void setTargetPath(SchemaPath path) {
+        this.finalAugmentTarget = path;
+    }
+
+    @Override
+    public String getTargetPathAsString() {
+        return augmentTargetStr;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 17;
+        int result = 1;
+        result = prime * result + ((augmentTargetStr == null) ? 0 : augmentTargetStr.hashCode());
+        result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode());
+        result = prime * result + ((childNodes == null) ? 0 : childNodes.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        AugmentationSchemaBuilderImpl other = (AugmentationSchemaBuilderImpl) obj;
+        if (augmentTargetStr == null) {
+            if (other.augmentTargetStr != null) {
+                return false;
+            }
+        } else if (!augmentTargetStr.equals(other.augmentTargetStr)) {
+            return false;
+        }
+        if (whenCondition == null) {
+            if (other.whenCondition != null) {
+                return false;
+            }
+        } else if (!whenCondition.equals(other.whenCondition)) {
+            return false;
+        }
+        if (childNodes == null) {
+            if (other.childNodes != null) {
+                return false;
+            }
+        } else if (!childNodes.equals(other.childNodes)) {
+            return false;
+        }
+        return true;
+    }
+
+    public String toString() {
+        return "augment " + augmentTargetStr;
+    }
+
+    private final class AugmentationSchemaImpl implements AugmentationSchema {
+        private SchemaPath targetPath;
+        private RevisionAwareXPath whenCondition;
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private String description;
+        private String reference;
+        private Status status;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private AugmentationSchemaImpl(SchemaPath targetPath) {
+            this.targetPath = targetPath;
+        }
+
+        @Override
+        public SchemaPath getTargetPath() {
+            return targetPath;
+        }
+
+        private void setTargetPath(SchemaPath path) {
+            this.targetPath = path;
+        }
+
+        @Override
+        public RevisionAwareXPath getWhenCondition() {
+            return whenCondition;
+        }
+
+        private void setWhenCondition(RevisionAwareXPath whenCondition) {
+            this.whenCondition = whenCondition;
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            final Set<DataSchemaNode> result = new TreeSet<DataSchemaNode>(Comparators.SCHEMA_NODE_COMP);
+            result.addAll(childNodes.values());
+            return result;
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        /**
+         * Always returns an empty set, because augment can not contains
+         * grouping statement.
+         */
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        /**
+         * Always returns an empty set, because augment can not contains type
+         * definitions.
+         */
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            this.status = status;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 17;
+            int result = 1;
+            result = prime * result + ((targetPath == null) ? 0 : targetPath.hashCode());
+            result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode());
+            result = prime * result + ((childNodes == null) ? 0 : childNodes.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            AugmentationSchemaImpl other = (AugmentationSchemaImpl) obj;
+            if (targetPath == null) {
+                if (other.targetPath != null) {
+                    return false;
+                }
+            } else if (!targetPath.equals(other.targetPath)) {
+                return false;
+            }
+            if (whenCondition == null) {
+                if (other.whenCondition != null) {
+                    return false;
+                }
+            } else if (!whenCondition.equals(other.whenCondition)) {
+                return false;
+            }
+            if (childNodes == null) {
+                if (other.childNodes != null) {
+                    return false;
+                }
+            } else if (!childNodes.equals(other.childNodes)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(AugmentationSchemaImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("targetPath=" + targetPath);
+            sb.append(", when=" + whenCondition);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceBuilder.java
new file mode 100644 (file)
index 0000000..291554c
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.ParserUtils;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class ChoiceBuilder extends AbstractSchemaNodeBuilder implements DataSchemaNodeBuilder,
+        AugmentationTargetBuilder, GroupingMember {
+    private boolean isBuilt;
+    private final ChoiceNodeImpl instance;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private boolean addedByUses;
+    private Boolean configuration;
+    private final ConstraintsBuilder constraints;
+    // AugmentationTarget args
+    private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
+    // ChoiceNode args
+    private Set<ChoiceCaseNode> cases;
+    private final Set<ChoiceCaseBuilder> addedCases = new HashSet<ChoiceCaseBuilder>();
+    private String defaultCase;
+
+    public ChoiceBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new ChoiceNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public ChoiceBuilder(ChoiceBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        parent = b.getParent();
+        instance = new ChoiceNodeImpl(qname);
+        constraints = b.getConstraints();
+        schemaPath = b.getPath();
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.getUnknownNodes());
+        augmenting = b.isAugmenting();
+        addedByUses = b.isAddedByUses();
+        configuration = b.isConfiguration();
+        addedAugmentations.addAll(b.getAugmentations());
+        cases = b.cases;
+        addedCases.addAll(b.getCases());
+        defaultCase = b.getDefaultCase();
+    }
+
+    @Override
+    public ChoiceNode build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+            instance.setConfiguration(configuration);
+            instance.setConstraints(constraints.build());
+            instance.setDefaultCase(defaultCase);
+
+            // CASES
+            if (cases == null) {
+                cases = new TreeSet<ChoiceCaseNode>(Comparators.SCHEMA_NODE_COMP);
+                for (ChoiceCaseBuilder caseBuilder : addedCases) {
+                    cases.add(caseBuilder.build());
+                }
+            }
+            instance.setCases(cases);
+
+            // AUGMENTATIONS
+            final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
+            for (AugmentationSchemaBuilder builder : addedAugmentations) {
+                augmentations.add(builder.build());
+            }
+            instance.setAvailableAugmentations(augmentations);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public void rebuild() {
+        isBuilt = false;
+        build();
+    }
+
+    public Set<ChoiceCaseBuilder> getCases() {
+        return addedCases;
+    }
+
+    /**
+     * Add case node to this choice.
+     *
+     * If node is not declared with 'case' keyword, create new case builder and
+     * make this node child of newly created case.
+     *
+     * @param caseNode
+     *            case node
+     */
+    public void addCase(DataSchemaNodeBuilder caseNode) {
+        QName caseQName = caseNode.getQName();
+        String caseName = caseQName.getLocalName();
+        for (ChoiceCaseBuilder addedCase : addedCases) {
+            if (addedCase.getQName().getLocalName().equals(caseName)) {
+                throw new YangParseException(caseNode.getModuleName(), caseNode.getLine(), "Can not add '" + caseNode
+                        + "' to node '" + qname.getLocalName() + "' in module '" + moduleName
+                        + "': case with same name already declared at line " + addedCase.getLine());
+            }
+        }
+
+        if (caseNode instanceof ChoiceCaseBuilder) {
+            addedCases.add((ChoiceCaseBuilder) caseNode);
+        } else {
+            ChoiceCaseBuilder caseBuilder = new ChoiceCaseBuilder(caseNode.getModuleName(), caseNode.getLine(),
+                    caseQName);
+            if (caseNode.isAugmenting()) {
+                // if node is added by augmentation, set case builder augmenting
+                // as true and node augmenting as false
+                caseBuilder.setAugmenting(true);
+                caseNode.setAugmenting(false);
+            }
+            caseBuilder.setPath(caseNode.getPath());
+            SchemaPath newPath = ParserUtils.createSchemaPath(caseNode.getPath(), caseQName.getLocalName(),
+                    caseQName.getNamespace(), caseQName.getRevision(), caseQName.getPrefix());
+            caseNode.setPath(newPath);
+            caseBuilder.addChildNode(caseNode);
+            addedCases.add(caseBuilder);
+        }
+    }
+
+    public void setCases(Set<ChoiceCaseNode> cases) {
+        this.cases = cases;
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public Set<AugmentationSchemaBuilder> getAugmentations() {
+        return addedAugmentations;
+    }
+
+    @Override
+    public void addAugmentation(AugmentationSchemaBuilder augment) {
+        addedAugmentations.add(augment);
+    }
+
+    public List<UnknownSchemaNodeBuilder> getUnknownNodes() {
+        return addedUnknownNodes;
+    }
+
+    public String getDefaultCase() {
+        return defaultCase;
+    }
+
+    public void setDefaultCase(String defaultCase) {
+        this.defaultCase = defaultCase;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ChoiceBuilder other = (ChoiceBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "choice " + qname.getLocalName();
+    }
+
+    public final class ChoiceNodeImpl implements ChoiceNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean augmenting;
+        private boolean addedByUses;
+        private boolean configuration;
+        private ConstraintDefinition constraints;
+        private Set<ChoiceCaseNode> cases = Collections.emptySet();
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private String defaultCase;
+
+        private ChoiceNodeImpl(QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraints;
+        }
+
+        private void setConstraints(ConstraintDefinition constraints) {
+            this.constraints = constraints;
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAvailableAugmentations() {
+            return augmentations;
+        }
+
+        private void setAvailableAugmentations(Set<AugmentationSchema> availableAugmentations) {
+            if (availableAugmentations != null) {
+                this.augmentations = availableAugmentations;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
+        }
+
+        @Override
+        public Set<ChoiceCaseNode> getCases() {
+            return cases;
+        }
+
+        @Override
+        public ChoiceCaseNode getCaseNodeByName(final QName name) {
+            if (name == null) {
+                throw new IllegalArgumentException("Choice Case QName cannot be NULL!");
+            }
+            for (final ChoiceCaseNode caseNode : cases) {
+                if (caseNode != null) {
+                    if (name.equals(caseNode.getQName())) {
+                        return caseNode;
+                    }
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public ChoiceCaseNode getCaseNodeByName(final String name) {
+            if (name == null) {
+                throw new IllegalArgumentException("Choice Case string Name cannot be NULL!");
+            }
+            for (final ChoiceCaseNode caseNode : cases) {
+                if (caseNode != null && (caseNode.getQName() != null)) {
+                    if (name.equals(caseNode.getQName().getLocalName())) {
+                        return caseNode;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private void setCases(Set<ChoiceCaseNode> cases) {
+            if (cases != null) {
+                this.cases = cases;
+            }
+        }
+
+        @Override
+        public String getDefaultCase() {
+            return defaultCase;
+        }
+
+        private void setDefaultCase(String defaultCase) {
+            this.defaultCase = defaultCase;
+        }
+
+        public ChoiceBuilder toBuilder() {
+            return ChoiceBuilder.this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ChoiceNodeImpl other = (ChoiceNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ChoiceNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceCaseBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceCaseBuilder.java
new file mode 100644 (file)
index 0000000..c5282bc
--- /dev/null
@@ -0,0 +1,448 @@
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class ChoiceCaseBuilder extends AbstractDataNodeContainerBuilder implements DataSchemaNodeBuilder,
+        AugmentationTargetBuilder {
+    private boolean isBuilt;
+    private final ChoiceCaseNodeImpl instance;
+    // SchemaNode args
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private final ConstraintsBuilder constraints;
+    // DataNodeContainer args
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    // AugmentationTarget args
+    private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
+
+    ChoiceCaseBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new ChoiceCaseNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    @Override
+    public ChoiceCaseNode build() {
+        if (!isBuilt) {
+            instance.setConstraints(constraints.build());
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAugmenting(augmenting);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            for (DataSchemaNodeBuilder node : addedChildNodes) {
+                childs.put(node.getQName(), node.build());
+            }
+            instance.setChildNodes(childs);
+
+            // USES
+            final Set<UsesNode> uses = new HashSet<UsesNode>();
+            for (UsesNodeBuilder builder : addedUsesNodes) {
+                uses.add(builder.build());
+            }
+            instance.setUses(uses);
+
+            // UNKNOWN NODES
+            final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                unknownNodes.add(b.build());
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            // AUGMENTATIONS
+            final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
+            for (AugmentationSchemaBuilder builder : addedAugmentations) {
+                augmentations.add(builder.build());
+            }
+            instance.setAvailableAugmentations(augmentations);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    @Override
+    public void rebuild() {
+        isBuilt = false;
+        build();
+    }
+
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    public Set<UsesNodeBuilder> getUsesNodes() {
+        return addedUsesNodes;
+    }
+
+    @Override
+    public void addUsesNode(UsesNodeBuilder usesNodeBuilder) {
+        addedUsesNodes.add(usesNodeBuilder);
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
+        throw new YangParseException(moduleName, line, "Can not add type definition to choice case.");
+    }
+
+    @Override
+    public Boolean isConfiguration() {
+        return false;
+    }
+
+    @Override
+    public void setConfiguration(final Boolean configuration) {
+        throw new YangParseException(moduleName, line, "Can not add config statement to choice case.");
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    @Override
+    public void addAugmentation(AugmentationSchemaBuilder augment) {
+        addedAugmentations.add(augment);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ChoiceCaseBuilder other = (ChoiceCaseBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "case " + getQName().getLocalName();
+    }
+
+    public final class ChoiceCaseNodeImpl implements ChoiceCaseNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean augmenting;
+        private ConstraintDefinition constraints;
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private ChoiceCaseNodeImpl(QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return false;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraints;
+        }
+
+        private void setConstraints(ConstraintDefinition constraints) {
+            this.constraints = constraints;
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return false;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        /**
+         * Always returns an empty set, because case node can not contains type
+         * definitions.
+         */
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            return new HashSet<DataSchemaNode>(childNodes.values());
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAvailableAugmentations() {
+            return augmentations;
+        }
+
+        private void setAvailableAugmentations(Set<AugmentationSchema> augmentations) {
+            if (augmentations != null) {
+                this.augmentations = augmentations;
+            }
+        }
+
+        public ChoiceCaseBuilder toBuilder() {
+            return ChoiceCaseBuilder.this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ChoiceCaseNodeImpl other = (ChoiceCaseNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ChoiceCaseNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ConstraintsBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ConstraintsBuilder.java
new file mode 100644 (file)
index 0000000..b2f1dff
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractBuilder;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class ConstraintsBuilder extends AbstractBuilder {
+    private final ConstraintDefinitionImpl instance;
+    private final Set<MustDefinition> mustDefinitions;
+    private String whenCondition;
+    private boolean mandatory;
+    private Integer min;
+    private Integer max;
+
+    ConstraintsBuilder(final String moduleName, final int line) {
+        super(moduleName, line);
+        instance = new ConstraintDefinitionImpl();
+        mustDefinitions = new HashSet<MustDefinition>();
+    }
+
+    @Override
+    public ConstraintDefinition build() {
+        RevisionAwareXPath whenStmt;
+        if (whenCondition == null) {
+            whenStmt = null;
+        } else {
+            whenStmt = new RevisionAwareXPathImpl(whenCondition, false);
+        }
+        instance.setWhenCondition(whenStmt);
+        instance.setMustConstraints(mustDefinitions);
+        instance.setMandatory(mandatory);
+        instance.setMinElements(min);
+        instance.setMaxElements(max);
+        return instance;
+    }
+
+    @Override
+    public void addUnknownNodeBuilder(UnknownSchemaNodeBuilder unknownNode) {
+        throw new YangParseException(moduleName, line, "Can not add unknown node to constraints.");
+    }
+
+    @Override
+    public List<UnknownSchemaNodeBuilder> getUnknownNodeBuilders() {
+        return Collections.emptyList();
+    }
+
+    public Integer getMinElements() {
+        return min;
+    }
+
+    public void setMinElements(Integer minElements) {
+        this.min = minElements;
+    }
+
+    public Integer getMaxElements() {
+        return max;
+    }
+
+    public void setMaxElements(Integer maxElements) {
+        this.max = maxElements;
+    }
+
+    public Set<MustDefinition> getMustDefinitions() {
+        return mustDefinitions;
+    }
+
+    public void addMustDefinition(MustDefinition must) {
+        mustDefinitions.add(must);
+    }
+
+    public String getWhenCondition() {
+        return whenCondition;
+    }
+
+    public void addWhenCondition(String whenCondition) {
+        this.whenCondition = whenCondition;
+    }
+
+    public boolean isMandatory() {
+        return mandatory;
+    }
+
+    public void setMandatory(boolean mandatory) {
+        this.mandatory = mandatory;
+    }
+
+    private final class ConstraintDefinitionImpl implements ConstraintDefinition {
+        private RevisionAwareXPath whenCondition;
+        private Set<MustDefinition> mustConstraints;
+        private boolean mandatory;
+        private Integer minElements;
+        private Integer maxElements;
+
+        @Override
+        public RevisionAwareXPath getWhenCondition() {
+            return whenCondition;
+        }
+
+        private void setWhenCondition(RevisionAwareXPath whenCondition) {
+            this.whenCondition = whenCondition;
+        }
+
+        @Override
+        public Set<MustDefinition> getMustConstraints() {
+            if (mustConstraints == null) {
+                return Collections.emptySet();
+            } else {
+                return mustConstraints;
+            }
+        }
+
+        private void setMustConstraints(Set<MustDefinition> mustConstraints) {
+            if (mustConstraints != null) {
+                this.mustConstraints = mustConstraints;
+            }
+        }
+
+        @Override
+        public boolean isMandatory() {
+            return mandatory;
+        }
+
+        private void setMandatory(boolean mandatory) {
+            this.mandatory = mandatory;
+        }
+
+        @Override
+        public Integer getMinElements() {
+            return minElements;
+        }
+
+        private void setMinElements(Integer minElements) {
+            this.minElements = minElements;
+        }
+
+        @Override
+        public Integer getMaxElements() {
+            return maxElements;
+        }
+
+        private void setMaxElements(Integer maxElements) {
+            this.maxElements = maxElements;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode());
+            result = prime * result + ((mustConstraints == null) ? 0 : mustConstraints.hashCode());
+            result = prime * result + ((minElements == null) ? 0 : minElements.hashCode());
+            result = prime * result + ((maxElements == null) ? 0 : maxElements.hashCode());
+            result = prime * result + (mandatory ? 1231 : 1237);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ConstraintDefinitionImpl other = (ConstraintDefinitionImpl) obj;
+            if (whenCondition == null) {
+                if (other.whenCondition != null) {
+                    return false;
+                }
+            } else if (!whenCondition.equals(other.whenCondition)) {
+                return false;
+            }
+            if (mustConstraints == null) {
+                if (other.mustConstraints != null) {
+                    return false;
+                }
+            } else if (!mustConstraints.equals(other.mustConstraints)) {
+                return false;
+            }
+            if (mandatory != other.mandatory) {
+                return false;
+            }
+            if (minElements == null) {
+                if (other.minElements != null) {
+                    return false;
+                }
+            } else if (!minElements.equals(other.minElements)) {
+                return false;
+            }
+            if (maxElements == null) {
+                if (other.maxElements != null) {
+                    return false;
+                }
+            } else if (!maxElements.equals(other.maxElements)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ConstraintDefinitionImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("whenCondition=" + whenCondition);
+            sb.append(", mustConstraints=" + mustConstraints);
+            sb.append(", mandatory=" + mandatory);
+            sb.append(", minElements=" + minElements);
+            sb.append(", maxElements=" + maxElements);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ContainerSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ContainerSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..0bc56d4
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class ContainerSchemaNodeBuilder extends AbstractDataNodeContainerBuilder implements
+        AugmentationTargetBuilder, DataSchemaNodeBuilder, GroupingMember {
+    private boolean isBuilt;
+    private final ContainerSchemaNodeImpl instance;
+
+    // SchemaNode args
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private boolean addedByUses;
+    private Boolean configuration;
+    private final ConstraintsBuilder constraints;
+    // DataNodeContainer args
+    private Set<TypeDefinition<?>> typedefs;
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+    private Set<UsesNode> usesNodes;
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    // AugmentationTarget args
+    private Set<AugmentationSchema> augmentations;
+    private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
+    // ContainerSchemaNode args
+    private boolean presence;
+
+    public ContainerSchemaNodeBuilder(final String moduleName, final int line, final QName qname,
+            final SchemaPath schemaPath) {
+        super(moduleName, line, qname);
+        this.schemaPath = schemaPath;
+        instance = new ContainerSchemaNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public ContainerSchemaNodeBuilder(final ContainerSchemaNodeBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        instance = new ContainerSchemaNodeImpl(b.getQName());
+        constraints = b.getConstraints();
+        schemaPath = b.getPath();
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        presence = b.isPresence();
+        augmenting = b.isAugmenting();
+        addedByUses = b.isAddedByUses();
+        configuration = b.isConfiguration();
+        childNodes = b.getChildNodes();
+        addedChildNodes.addAll(b.getChildNodeBuilders());
+        groupings = b.getGroupings();
+        addedGroupings.addAll(b.getGroupingBuilders());
+        typedefs = b.typedefs;
+        addedTypedefs.addAll(b.getTypeDefinitionBuilders());
+        usesNodes = b.usesNodes;
+        addedUsesNodes.addAll(b.getUsesNodes());
+        augmentations = b.augmentations;
+        addedAugmentations.addAll(b.getAugmentations());
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.getUnknownNodeBuilders());
+    }
+
+    @Override
+    public ContainerSchemaNode build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setPresenceContainer(presence);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+
+            // if this builder represents rpc input or output, it can has
+            // configuration value set to null
+            if (configuration == null) {
+                configuration = false;
+            }
+            instance.setConfiguration(configuration);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            if (childNodes == null || childNodes.isEmpty()) {
+                for (DataSchemaNodeBuilder node : addedChildNodes) {
+                    childs.put(node.getQName(), node.build());
+                }
+            } else {
+                for (DataSchemaNode node : childNodes) {
+                    childs.put(node.getQName(), node);
+                }
+            }
+            instance.setChildNodes(childs);
+
+            // GROUPINGS
+            if (groupings == null) {
+                groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+                for (GroupingBuilder builder : addedGroupings) {
+                    groupings.add(builder.build());
+                }
+            }
+            instance.setGroupings(groupings);
+
+            // TYPEDEFS
+            if (typedefs == null) {
+                typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+                for (TypeDefinitionBuilder entry : addedTypedefs) {
+                    typedefs.add(entry.build());
+                }
+            }
+            instance.setTypeDefinitions(typedefs);
+
+            // USES
+            if (usesNodes == null) {
+                usesNodes = new HashSet<UsesNode>();
+                for (UsesNodeBuilder builder : addedUsesNodes) {
+                    usesNodes.add(builder.build());
+                }
+            }
+            instance.setUses(usesNodes);
+
+            // AUGMENTATIONS
+            if (augmentations == null) {
+                augmentations = new HashSet<AugmentationSchema>();
+                for (AugmentationSchemaBuilder builder : addedAugmentations) {
+                    augmentations.add(builder.build());
+                }
+            }
+            instance.setAvailableAugmentations(augmentations);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            instance.setConstraints(constraints.build());
+            instance.setAvailableAugmentations(augmentations);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public void rebuild() {
+        isBuilt = false;
+        build();
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return addedTypedefs;
+    }
+
+    @Override
+    public void addTypedef(final TypeDefinitionBuilder type) {
+        String typeName = type.getQName().getLocalName();
+        for (TypeDefinitionBuilder addedTypedef : addedTypedefs) {
+            throw new YangParseException(moduleName, type.getLine(), "Can not add typedef '" + typeName
+                    + "': typedef with same name already declared at line " + addedTypedef.getLine());
+        }
+        addedTypedefs.add(type);
+    }
+
+    public void setTypedefs(final Set<TypeDefinition<?>> typedefs) {
+        this.typedefs = typedefs;
+    }
+
+    public Set<AugmentationSchemaBuilder> getAugmentations() {
+        return addedAugmentations;
+    }
+
+    @Override
+    public void addAugmentation(AugmentationSchemaBuilder augment) {
+        addedAugmentations.add(augment);
+    }
+
+    public void setAugmentations(final Set<AugmentationSchema> augmentations) {
+        this.augmentations = augmentations;
+    }
+
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    @Override
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public Set<UsesNodeBuilder> getUsesNodes() {
+        return addedUsesNodes;
+    }
+
+    @Override
+    public void addUsesNode(UsesNodeBuilder usesNodeBuilder) {
+        addedUsesNodes.add(usesNodeBuilder);
+    }
+
+    public void setUsesnodes(final Set<UsesNode> usesNodes) {
+        this.usesNodes = usesNodes;
+    }
+
+    public boolean isPresence() {
+        return presence;
+    }
+
+    public void setPresence(boolean presence) {
+        this.presence = presence;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ContainerSchemaNodeBuilder other = (ContainerSchemaNodeBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "container " + qname.getLocalName();
+    }
+
+    public final class ContainerSchemaNodeImpl implements ContainerSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean augmenting;
+        private boolean addedByUses;
+        private boolean configuration;
+        private ConstraintDefinition constraints;
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<GroupingDefinition> groupings = Collections.emptySet();
+        private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private boolean presence;
+
+        private ContainerSchemaNodeImpl(QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraints;
+        }
+
+        private void setConstraints(ConstraintDefinition constraints) {
+            this.constraints = constraints;
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAvailableAugmentations() {
+            return augmentations;
+        }
+
+        private void setAvailableAugmentations(Set<AugmentationSchema> augmentations) {
+            if (augmentations != null) {
+                this.augmentations = augmentations;
+            }
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            return new HashSet<DataSchemaNode>(childNodes.values());
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            if (groupings != null) {
+                this.groupings = groupings;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        @Override
+        public boolean isPresenceContainer() {
+            return presence;
+        }
+
+        private void setPresenceContainer(boolean presence) {
+            this.presence = presence;
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+            if (typeDefinitions != null) {
+                this.typeDefinitions = typeDefinitions;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
+        }
+
+        public ContainerSchemaNodeBuilder toBuilder() {
+            return ContainerSchemaNodeBuilder.this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ContainerSchemaNodeImpl other = (ContainerSchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ContainerSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/DeviationBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/DeviationBuilder.java
new file mode 100644 (file)
index 0000000..3bc9879
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.model.api.Deviation;
+import org.opendaylight.controller.yang.model.api.Deviation.Deviate;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.ParserListenerUtils;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class DeviationBuilder extends AbstractBuilder {
+    private final String targetPathStr;
+    private boolean isBuilt;
+    private final DeviationImpl instance;
+
+    private SchemaPath targetPath;
+    private String reference;
+    private final List<UnknownSchemaNodeBuilder> addedUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+
+    DeviationBuilder(final String moduleName, final int line, final String targetPathStr) {
+        super(moduleName, line);
+        if (!targetPathStr.startsWith("/")) {
+            throw new YangParseException(moduleName, line,
+                    "Deviation argument string must be an absolute schema node identifier.");
+        }
+        this.targetPathStr = targetPathStr;
+        this.targetPath = ParserListenerUtils.parseAugmentPath(targetPathStr);
+        instance = new DeviationImpl();
+    }
+
+    @Override
+    public Deviation build() {
+        if (targetPath == null) {
+            throw new YangParseException(moduleName, line, "Unresolved deviation target");
+        }
+
+        if (!isBuilt) {
+            instance.setTargetPath(targetPath);
+            instance.setReference(reference);
+
+            // UNKNOWN NODES
+            List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                unknownNodes.add(b.build());
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    public SchemaPath getTargetPath() {
+        return targetPath;
+    }
+
+    public void setTargetPath(final SchemaPath targetPath) {
+        this.targetPath = targetPath;
+    }
+
+    public void setDeviate(final String deviate) {
+        if ("not-supported".equals(deviate)) {
+            instance.setDeviate(Deviate.NOT_SUPPORTED);
+        } else if ("add".equals(deviate)) {
+            instance.setDeviate(Deviate.ADD);
+        } else if ("replace".equals(deviate)) {
+            instance.setDeviate(Deviate.REPLACE);
+        } else if ("delete".equals(deviate)) {
+            instance.setDeviate(Deviate.DELETE);
+        } else {
+            throw new YangParseException(moduleName, line, "Unsupported type of 'deviate' statement: " + deviate);
+        }
+    }
+
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public String toString() {
+        return "deviation " + targetPathStr;
+    }
+
+    private final class DeviationImpl implements Deviation {
+        private SchemaPath targetPath;
+        private Deviate deviate;
+        private String reference;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private DeviationImpl() {
+        }
+
+        @Override
+        public SchemaPath getTargetPath() {
+            return targetPath;
+        }
+
+        private void setTargetPath(final SchemaPath targetPath) {
+            this.targetPath = targetPath;
+        }
+
+        @Override
+        public Deviate getDeviate() {
+            return deviate;
+        }
+
+        private void setDeviate(final Deviate deviate) {
+            this.deviate = deviate;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(final String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((targetPath == null) ? 0 : targetPath.hashCode());
+            result = prime * result + ((deviate == null) ? 0 : deviate.hashCode());
+            result = prime * result + ((reference == null) ? 0 : reference.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            DeviationImpl other = (DeviationImpl) obj;
+            if (targetPath == null) {
+                if (other.targetPath != null) {
+                    return false;
+                }
+            } else if (!targetPath.equals(other.targetPath)) {
+                return false;
+            }
+            if (deviate == null) {
+                if (other.deviate != null) {
+                    return false;
+                }
+            } else if (!deviate.equals(other.deviate)) {
+                return false;
+            }
+            if (reference == null) {
+                if (other.reference != null) {
+                    return false;
+                }
+            } else if (!reference.equals(other.reference)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(DeviationImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("targetPath=" + targetPath);
+            sb.append(", deviate=" + deviate);
+            sb.append(", reference=" + reference);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ExtensionBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ExtensionBuilder.java
new file mode 100644 (file)
index 0000000..93a34e1
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class ExtensionBuilder extends AbstractSchemaNodeBuilder {
+    private boolean isBuilt;
+    private final ExtensionDefinitionImpl instance;
+
+    ExtensionBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new ExtensionDefinitionImpl(qname);
+    }
+
+    @Override
+    public ExtensionDefinition build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder un : addedUnknownNodes) {
+                    unknownNodes.add(un.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    public void setYinElement(boolean yin) {
+        instance.setYinElement(yin);
+    }
+
+    public void setArgument(String argument) {
+        instance.setArgument(argument);
+    }
+
+    @Override
+    public String toString() {
+        return "extension " + qname.getLocalName();
+    }
+
+    private final class ExtensionDefinitionImpl implements ExtensionDefinition {
+        private final QName qname;
+        private String argument;
+        private SchemaPath schemaPath;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private boolean yin;
+
+        private ExtensionDefinitionImpl(QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return schemaPath;
+        }
+
+        private void setPath(SchemaPath schemaPath) {
+            this.schemaPath = schemaPath;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public String getArgument() {
+            return argument;
+        }
+
+        private void setArgument(String argument) {
+            this.argument = argument;
+        }
+
+        @Override
+        public boolean isYinElement() {
+            return yin;
+        }
+
+        private void setYinElement(boolean yin) {
+            this.yin = yin;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ExtensionDefinitionImpl other = (ExtensionDefinitionImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (schemaPath == null) {
+                if (other.schemaPath != null) {
+                    return false;
+                }
+            } else if (!schemaPath.equals(other.schemaPath)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ExtensionDefinitionImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("argument=" + argument);
+            sb.append(", qname=" + qname);
+            sb.append(", schemaPath=" + schemaPath);
+            sb.append(", extensionSchemaNodes=" + unknownNodes);
+            sb.append(", yin=" + yin);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/FeatureBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/FeatureBuilder.java
new file mode 100644 (file)
index 0000000..dd3fd11
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.FeatureDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class FeatureBuilder extends AbstractSchemaNodeBuilder {
+    private boolean isBuilt;
+    private final FeatureDefinitionImpl instance;
+
+    FeatureBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new FeatureDefinitionImpl(qname);
+    }
+
+    @Override
+    public FeatureDefinitionImpl build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public String toString() {
+        return "feature " + qname.getLocalName();
+    }
+
+    private final class FeatureDefinitionImpl implements FeatureDefinition {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private FeatureDefinitionImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(final String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(final String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            FeatureDefinitionImpl other = (FeatureDefinitionImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(FeatureDefinitionImpl.class.getSimpleName());
+            sb.append("[name=" + qname + "]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/GroupingBuilderImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/GroupingBuilderImpl.java
new file mode 100644 (file)
index 0000000..8a8f121
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class GroupingBuilderImpl extends AbstractDataNodeContainerBuilder implements GroupingBuilder {
+    private boolean isBuilt;
+    private final GroupingDefinitionImpl instance;
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    private boolean addedByUses;
+
+    private Set<TypeDefinition<?>> typedefs;
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+
+    private Set<UsesNode> usesNodes;
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+
+    public GroupingBuilderImpl(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new GroupingDefinitionImpl(qname);
+    }
+
+    public GroupingBuilderImpl(GroupingBuilder builder) {
+        super(builder.getModuleName(), builder.getLine(), builder.getQName());
+        parent = builder.getParent();
+        instance = new GroupingDefinitionImpl(qname);
+        schemaPath = builder.getPath();
+        description = builder.getDescription();
+        reference = builder.getReference();
+        status = builder.getStatus();
+        addedByUses = builder.isAddedByUses();
+        childNodes = builder.getChildNodes();
+        addedChildNodes.addAll(builder.getChildNodeBuilders());
+        groupings = builder.getGroupings();
+        addedGroupings.addAll(builder.getGroupingBuilders());
+        addedUsesNodes.addAll(builder.getUses());
+        addedUnknownNodes.addAll(builder.getUnknownNodeBuilders());
+    }
+
+    @Override
+    public GroupingDefinition build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAddedByUses(addedByUses);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            if (childNodes == null || childNodes.isEmpty()) {
+                for (DataSchemaNodeBuilder node : addedChildNodes) {
+                    childs.put(node.getQName(), node.build());
+                }
+            } else {
+                for (DataSchemaNode node : childNodes) {
+                    childs.put(node.getQName(), node);
+                }
+            }
+            instance.setChildNodes(childs);
+
+            // GROUPINGS
+            if (groupings == null) {
+                groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+                for (GroupingBuilder builder : addedGroupings) {
+                    groupings.add(builder.build());
+                }
+            }
+            instance.setGroupings(groupings);
+
+            // TYPEDEFS
+            if (typedefs == null) {
+                typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+                for (TypeDefinitionBuilder entry : addedTypedefs) {
+                    typedefs.add(entry.build());
+                }
+            }
+            instance.setTypeDefinitions(typedefs);
+
+            // USES
+            if (usesNodes == null) {
+                usesNodes = new HashSet<UsesNode>();
+                for (UsesNodeBuilder builder : addedUsesNodes) {
+                    usesNodes.add(builder.build());
+                }
+            }
+            instance.setUses(usesNodes);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return addedTypedefs;
+    }
+
+    @Override
+    public void addTypedef(final TypeDefinitionBuilder type) {
+        String typeName = type.getQName().getLocalName();
+        for (TypeDefinitionBuilder addedTypedef : addedTypedefs) {
+            throw new YangParseException(moduleName, type.getLine(), "Can not add typedef '" + typeName
+                    + "': typedef with same name already declared at line " + addedTypedef.getLine());
+        }
+        addedTypedefs.add(type);
+    }
+
+    public void setTypedefs(final Set<TypeDefinition<?>> typedefs) {
+        this.typedefs = typedefs;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        this.status = status;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    @Override
+    public Set<UsesNodeBuilder> getUses() {
+        return addedUsesNodes;
+    }
+
+    @Override
+    public void addUsesNode(final UsesNodeBuilder usesBuilder) {
+        addedUsesNodes.add(usesBuilder);
+    }
+
+    public void setUsesnodes(final Set<UsesNode> usesNodes) {
+        this.usesNodes = usesNodes;
+    }
+
+    @Override
+    public String toString() {
+        return "grouping " + qname.getLocalName();
+    }
+
+    private final class GroupingDefinitionImpl implements GroupingDefinition {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status;
+        private boolean addedByUses;
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<GroupingDefinition> groupings = Collections.emptySet();
+        private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private GroupingDefinitionImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            this.status = status;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(final boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            final Set<DataSchemaNode> result = new TreeSet<DataSchemaNode>(Comparators.SCHEMA_NODE_COMP);
+            result.addAll(childNodes.values());
+            return result;
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            this.childNodes = childNodes;
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            this.groupings = groupings;
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            this.uses = uses;
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+            this.typeDefinitions = typeDefinitions;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final GroupingDefinitionImpl other = (GroupingDefinitionImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(GroupingDefinitionImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentitySchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentitySchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..2e7c495
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class IdentitySchemaNodeBuilder extends AbstractSchemaNodeBuilder {
+    private boolean isBuilt;
+    private final IdentitySchemaNodeImpl instance;
+    private IdentitySchemaNodeBuilder baseIdentityBuilder;
+    private IdentitySchemaNode baseIdentity;
+    private String baseIdentityName;
+
+    IdentitySchemaNodeBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new IdentitySchemaNodeImpl(qname);
+    }
+
+    @Override
+    public IdentitySchemaNode build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+
+            if (baseIdentity == null) {
+                if (baseIdentityBuilder != null) {
+                    instance.setBaseIdentity(baseIdentityBuilder.build());
+                }
+            } else {
+                instance.setBaseIdentity(baseIdentity);
+            }
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    public String getBaseIdentityName() {
+        return baseIdentityName;
+    }
+
+    public void setBaseIdentityName(final String baseIdentityName) {
+        this.baseIdentityName = baseIdentityName;
+    }
+
+    public void setBaseIdentity(final IdentitySchemaNodeBuilder baseType) {
+        this.baseIdentityBuilder = baseType;
+    }
+
+    public void setBaseIdentity(final IdentitySchemaNode baseType) {
+        this.baseIdentity = baseType;
+    }
+
+    @Override
+    public String toString() {
+        return "identity " + qname.getLocalName();
+    }
+
+    private final class IdentitySchemaNodeImpl implements IdentitySchemaNode {
+        private final QName qname;
+        private IdentitySchemaNode baseIdentity;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private SchemaPath path;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private IdentitySchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public IdentitySchemaNode getBaseIdentity() {
+            return baseIdentity;
+        }
+
+        private void setBaseIdentity(final IdentitySchemaNode baseIdentity) {
+            this.baseIdentity = baseIdentity;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(final String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(final String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(final Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {
+            if (unknownSchemaNodes != null) {
+                this.unknownNodes = unknownSchemaNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            IdentitySchemaNodeImpl other = (IdentitySchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(IdentitySchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("base=" + baseIdentity);
+            sb.append(", qname=" + qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentityrefTypeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentityrefTypeBuilder.java
new file mode 100644 (file)
index 0000000..ca60029
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.IdentityrefType;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractTypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+/**
+ * Builder for YANG union type. User can add type to this union as
+ * TypeDefinition object (resolved type) or in form of TypeDefinitionBuilder.
+ * When build is called, types in builder form will be built and add to resolved
+ * types.
+ */
+public final class IdentityrefTypeBuilder extends AbstractTypeAwareBuilder implements TypeDefinitionBuilder {
+    private static final String NAME = "identityref";
+
+    private final String baseString;
+    private final SchemaPath schemaPath;
+    private QName baseQName;
+
+    IdentityrefTypeBuilder(final String moduleName, final int line, final String baseString, final SchemaPath schemaPath) {
+        super(moduleName, line, null);
+        this.baseString = baseString;
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public IdentityrefType build() {
+        return new IdentityrefType(baseQName, schemaPath);
+    }
+
+    public String getBaseString() {
+        return baseString;
+    }
+
+    public void setBaseQName(QName baseQName) {
+        this.baseQName = baseQName;
+    }
+
+    @Override
+    public TypeDefinition<?> getType() {
+        return null;
+    }
+
+    @Override
+    public TypeDefinitionBuilder getTypedef() {
+        return null;
+    }
+
+    @Override
+    public void setType(final TypeDefinition<?> type) {
+        throw new YangParseException(moduleName, line, "Can not set type to " + NAME);
+    }
+
+    @Override
+    public void setTypedef(final TypeDefinitionBuilder tdb) {
+        throw new YangParseException(moduleName, line, "Can not set type to " + NAME);
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        throw new YangParseException(moduleName, line, "Can not set path to " + NAME);
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        throw new YangParseException(moduleName, line, "Can not set description to " + NAME);
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        throw new YangParseException(moduleName, line, "Can not set reference to " + NAME);
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        throw new YangParseException(moduleName, line, "Can not set status to " + NAME);
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return false;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        throw new YangParseException(moduleName, line, "Identityref type can not be added by uses.");
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownNodes() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void addUnknownNodeBuilder(final UnknownSchemaNodeBuilder unknownNode) {
+        throw new YangParseException(moduleName, line, "Can not add unknown node to " + NAME);
+    }
+
+    @Override
+    public QName getQName() {
+        return null;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return null;
+    }
+
+    @Override
+    public String getDescription() {
+        return null;
+    }
+
+    @Override
+    public String getReference() {
+        return null;
+    }
+
+    @Override
+    public Status getStatus() {
+        return null;
+    }
+
+    @Override
+    public List<RangeConstraint> getRanges() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setRanges(List<RangeConstraint> ranges) {
+        throw new YangParseException(moduleName, line, "Can not set ranges to " + NAME);
+    }
+
+    @Override
+    public List<LengthConstraint> getLengths() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setLengths(List<LengthConstraint> lengths) {
+        throw new YangParseException(moduleName, line, "Can not set lengths to " + NAME);
+    }
+
+    @Override
+    public List<PatternConstraint> getPatterns() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setPatterns(List<PatternConstraint> patterns) {
+        throw new YangParseException(moduleName, line, "Can not set patterns to " + NAME);
+    }
+
+    @Override
+    public Integer getFractionDigits() {
+        return null;
+    }
+
+    @Override
+    public void setFractionDigits(Integer fractionDigits) {
+        throw new YangParseException(moduleName, line, "Can not set fraction digits to " + NAME);
+    }
+
+    @Override
+    public List<UnknownSchemaNodeBuilder> getUnknownNodeBuilders() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return null;
+    }
+
+    @Override
+    public void setDefaultValue(Object defaultValue) {
+        throw new YangParseException(moduleName, line, "Can not set default value to " + NAME);
+    }
+
+    @Override
+    public String getUnits() {
+        return null;
+    }
+
+    @Override
+    public void setUnits(String units) {
+        throw new YangParseException(moduleName, line, "Can not set units to " + NAME);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder result = new StringBuilder(IdentityrefTypeBuilder.class.getSimpleName() + "[");
+        result.append(", base=" + baseQName);
+        result.append("]");
+        return result.toString();
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..8e11ad2
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractTypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder implements DataSchemaNodeBuilder,
+        GroupingMember {
+    private boolean isBuilt;
+    private final LeafListSchemaNodeImpl instance;
+    // SchemaNode args
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private boolean addedByUses;
+    private Boolean configuration;
+    private final ConstraintsBuilder constraints;
+    // LeafListSchemaNode args
+    private boolean userOrdered;
+
+    public LeafListSchemaNodeBuilder(final String moduleName, final int line, final QName qname,
+            final SchemaPath schemaPath) {
+        super(moduleName, line, qname);
+        this.schemaPath = schemaPath;
+        instance = new LeafListSchemaNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public LeafListSchemaNodeBuilder(final LeafListSchemaNodeBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        instance = new LeafListSchemaNodeImpl(qname);
+
+        type = b.getType();
+        typedef = b.getTypedef();
+
+        constraints = b.getConstraints();
+        schemaPath = b.getPath();
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        augmenting = b.isAugmenting();
+        addedByUses = b.isAddedByUses();
+        configuration = b.isConfiguration();
+        userOrdered = b.isUserOrdered();
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.getUnknownNodeBuilders());
+    }
+
+    @Override
+    public LeafListSchemaNode build() {
+        if (!isBuilt) {
+            instance.setConstraints(constraints.build());
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+            instance.setConfiguration(configuration);
+            instance.setUserOrdered(userOrdered);
+
+            if (type == null) {
+                instance.setType(typedef.build());
+            } else {
+                instance.setType(type);
+            }
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public boolean isUserOrdered() {
+        return userOrdered;
+    }
+
+    public void setUserOrdered(final boolean userOrdered) {
+        this.userOrdered = userOrdered;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        LeafListSchemaNodeBuilder other = (LeafListSchemaNodeBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "leaf-list " + qname.getLocalName();
+    }
+
+    private final class LeafListSchemaNodeImpl implements LeafListSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean augmenting;
+        private boolean addedByUses;
+        private boolean configuration;
+        private ConstraintDefinition constraintsDef;
+        private TypeDefinition<?> type;
+        private boolean userOrdered;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private LeafListSchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            this.status = status;
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(final boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraintsDef;
+        }
+
+        private void setConstraints(ConstraintDefinition constraintsDef) {
+            this.constraintsDef = constraintsDef;
+        }
+
+        @Override
+        public TypeDefinition<?> getType() {
+            return type;
+        }
+
+        public void setType(TypeDefinition<? extends TypeDefinition<?>> type) {
+            this.type = type;
+        }
+
+        @Override
+        public boolean isUserOrdered() {
+            return userOrdered;
+        }
+
+        private void setUserOrdered(boolean userOrdered) {
+            this.userOrdered = userOrdered;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            LeafListSchemaNodeImpl other = (LeafListSchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(LeafListSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append(qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..5c1da11
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractTypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implements DataSchemaNodeBuilder,
+        GroupingMember {
+    private boolean isBuilt;
+    private final LeafSchemaNodeImpl instance;
+    // SchemaNode args
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private boolean addedByUses;
+    private Boolean configuration;
+    private final ConstraintsBuilder constraints;
+    // leaf args
+    private String defaultStr;
+    private String unitsStr;
+
+    public LeafSchemaNodeBuilder(final String moduleName, final int line, final QName qname, final SchemaPath schemaPath) {
+        super(moduleName, line, qname);
+        this.schemaPath = schemaPath;
+        instance = new LeafSchemaNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public LeafSchemaNodeBuilder(final LeafSchemaNodeBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        instance = new LeafSchemaNodeImpl(qname);
+        constraints = b.getConstraints();
+        schemaPath = b.getPath();
+
+        type = b.getType();
+        typedef = b.getTypedef();
+
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        augmenting = b.isAugmenting();
+        addedByUses = b.isAddedByUses();
+        configuration = b.isConfiguration();
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.getUnknownNodeBuilders());
+
+        defaultStr = b.getDefaultStr();
+        unitsStr = b.getUnits();
+    }
+
+    @Override
+    public LeafSchemaNode build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setConstraints(constraints.build());
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+            instance.setConfiguration(configuration);
+            instance.setDefault(defaultStr);
+            instance.setUnits(unitsStr);
+
+            // TYPE
+            if (type == null) {
+                instance.setType(typedef.build());
+            } else {
+                instance.setType(type);
+            }
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath path) {
+        this.schemaPath = path;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(final boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(final Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    public String getDefaultStr() {
+        return defaultStr;
+    }
+
+    public void setDefaultStr(String defaultStr) {
+        this.defaultStr = defaultStr;
+    }
+
+    public String getUnits() {
+        return unitsStr;
+    }
+
+    public void setUnits(String unitsStr) {
+        this.unitsStr = unitsStr;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        LeafSchemaNodeBuilder other = (LeafSchemaNodeBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "leaf " + qname.getLocalName();
+    }
+
+    private final class LeafSchemaNodeImpl implements LeafSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private boolean augmenting;
+        private boolean addedByUses;
+        private boolean configuration;
+        private ConstraintDefinition constraintsDef;
+        private TypeDefinition<?> type;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private String defaultStr;
+        private String unitsStr;
+
+        private LeafSchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(final boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraintsDef;
+        }
+
+        private void setConstraints(ConstraintDefinition constraintsDef) {
+            this.constraintsDef = constraintsDef;
+        }
+
+        @Override
+        public TypeDefinition<?> getType() {
+            return type;
+        }
+
+        private void setType(TypeDefinition<? extends TypeDefinition<?>> type) {
+            this.type = type;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public String getDefault() {
+            return defaultStr;
+        }
+
+        private void setDefault(String defaultStr) {
+            this.defaultStr = defaultStr;
+        }
+
+        @Override
+        public String getUnits() {
+            return unitsStr;
+        }
+
+        public void setUnits(String unitsStr) {
+            this.unitsStr = unitsStr;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            LeafSchemaNodeImpl other = (LeafSchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(LeafSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append(", path=" + path);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ListSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ListSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..5e369d0
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class ListSchemaNodeBuilder extends AbstractDataNodeContainerBuilder implements DataSchemaNodeBuilder,
+        AugmentationTargetBuilder, GroupingMember {
+    private boolean isBuilt;
+    private final ListSchemaNodeImpl instance;
+    // SchemaNode args
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    // DataSchemaNode args
+    private boolean augmenting;
+    private boolean addedByUses;
+    private Boolean configuration;
+    private final ConstraintsBuilder constraints;
+    // DataNodeContainer args
+    private Set<TypeDefinition<?>> typedefs;
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+    private Set<UsesNode> usesNodes;
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    // AugmentationTarget args
+    private Set<AugmentationSchema> augmentations;
+    private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
+    // ListSchemaNode args
+    private List<QName> keyDefinition = Collections.emptyList();
+    private boolean userOrdered;
+
+    public ListSchemaNodeBuilder(final String moduleName, final int line, final QName qname, final SchemaPath schemaPath) {
+        super(moduleName, line, qname);
+        this.schemaPath = schemaPath;
+        instance = new ListSchemaNodeImpl(qname);
+        constraints = new ConstraintsBuilder(moduleName, line);
+    }
+
+    public ListSchemaNodeBuilder(final ListSchemaNodeBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        instance = new ListSchemaNodeImpl(b.getQName());
+        constraints = b.getConstraints();
+        schemaPath = b.getPath();
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        augmenting = b.isAugmenting();
+        addedByUses = b.isAddedByUses();
+        configuration = b.isConfiguration();
+        keyDefinition = b.getKeyDefinition();
+        userOrdered = b.isUserOrdered();
+        childNodes = b.getChildNodes();
+        addedChildNodes.addAll(b.getChildNodeBuilders());
+        groupings = b.getGroupings();
+        addedGroupings.addAll(b.getGroupingBuilders());
+        typedefs = b.typedefs;
+        addedTypedefs.addAll(b.getTypeDefinitionBuilders());
+        usesNodes = b.usesNodes;
+        addedUsesNodes.addAll(b.getUsesNodes());
+        augmentations = b.augmentations;
+        addedAugmentations.addAll(b.getAugmentations());
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.getUnknownNodeBuilders());
+    }
+
+    @Override
+    public ListSchemaNode build() {
+        if (!isBuilt) {
+            instance.setKeyDefinition(keyDefinition);
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAugmenting(augmenting);
+            instance.setAddedByUses(addedByUses);
+            instance.setConfiguration(configuration);
+            instance.setUserOrdered(userOrdered);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            if (childNodes == null || childNodes.isEmpty()) {
+                for (DataSchemaNodeBuilder node : addedChildNodes) {
+                    childs.put(node.getQName(), node.build());
+                }
+            } else {
+                for (DataSchemaNode node : childNodes) {
+                    childs.put(node.getQName(), node);
+                }
+            }
+            instance.setChildNodes(childs);
+
+            // TYPEDEFS
+            if (typedefs == null) {
+                typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+                for (TypeDefinitionBuilder entry : addedTypedefs) {
+                    typedefs.add(entry.build());
+                }
+            }
+            instance.setTypeDefinitions(typedefs);
+
+            // USES
+            if (usesNodes == null) {
+                usesNodes = new HashSet<UsesNode>();
+                for (UsesNodeBuilder builder : addedUsesNodes) {
+                    usesNodes.add(builder.build());
+                }
+            }
+            instance.setUses(usesNodes);
+
+            // GROUPINGS
+            if (groupings == null) {
+                groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+                for (GroupingBuilder builder : addedGroupings) {
+                    groupings.add(builder.build());
+                }
+            }
+            instance.setGroupings(groupings);
+
+            // AUGMENTATIONS
+            if (augmentations == null) {
+                augmentations = new HashSet<AugmentationSchema>();
+                for (AugmentationSchemaBuilder builder : addedAugmentations) {
+                    augmentations.add(builder.build());
+                }
+            }
+            instance.setAvailableAugmentations(augmentations);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            instance.setConstraints(constraints.build());
+            instance.setAvailableAugmentations(augmentations);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public void rebuild() {
+        isBuilt = false;
+        build();
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return addedTypedefs;
+    }
+
+    @Override
+    public void addTypedef(final TypeDefinitionBuilder type) {
+        String typeName = type.getQName().getLocalName();
+        for (TypeDefinitionBuilder addedTypedef : addedTypedefs) {
+            throw new YangParseException(moduleName, type.getLine(), "Can not add typedef '" + typeName
+                    + "': typedef with same name already declared at line " + addedTypedef.getLine());
+        }
+        addedTypedefs.add(type);
+    }
+
+    public void setTypedefs(final Set<TypeDefinition<?>> typedefs) {
+        this.typedefs = typedefs;
+    }
+
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(String reference) {
+        this.reference = reference;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    public Set<UsesNodeBuilder> getUsesNodes() {
+        return addedUsesNodes;
+    }
+
+    @Override
+    public void addUsesNode(final UsesNodeBuilder usesBuilder) {
+        addedUsesNodes.add(usesBuilder);
+    }
+
+    public void setUsesnodes(final Set<UsesNode> usesNodes) {
+        this.usesNodes = usesNodes;
+    }
+
+    public Set<AugmentationSchemaBuilder> getAugmentations() {
+        return addedAugmentations;
+    }
+
+    @Override
+    public void addAugmentation(AugmentationSchemaBuilder augment) {
+        addedAugmentations.add(augment);
+    }
+
+    public void setAugmentations(final Set<AugmentationSchema> augmentations) {
+        this.augmentations = augmentations;
+    }
+
+    public List<QName> getKeyDefinition() {
+        return keyDefinition;
+    }
+
+    public void setKeyDefinition(final List<QName> keyDefinition) {
+        if (keyDefinition != null) {
+            this.keyDefinition = keyDefinition;
+        }
+    }
+
+    public boolean isAugmenting() {
+        return augmenting;
+    }
+
+    @Override
+    public void setAugmenting(boolean augmenting) {
+        this.augmenting = augmenting;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    public Boolean isConfiguration() {
+        return configuration;
+    }
+
+    @Override
+    public void setConfiguration(Boolean configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public ConstraintsBuilder getConstraints() {
+        return constraints;
+    }
+
+    public boolean isUserOrdered() {
+        return userOrdered;
+    }
+
+    public void setUserOrdered(final boolean userOrdered) {
+        this.userOrdered = userOrdered;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        ListSchemaNodeBuilder other = (ListSchemaNodeBuilder) obj;
+        if (schemaPath == null) {
+            if (other.schemaPath != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.schemaPath)) {
+            return false;
+        }
+        if (parent == null) {
+            if (other.parent != null) {
+                return false;
+            }
+        } else if (!parent.equals(other.parent)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "list " + qname.getLocalName();
+    }
+
+    public final class ListSchemaNodeImpl implements ListSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private List<QName> keyDefinition = Collections.emptyList();
+        private boolean augmenting;
+        private boolean addedByUses;
+        private boolean configuration;
+        private ConstraintDefinition constraints;
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
+        private Set<GroupingDefinition> groupings = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private boolean userOrdered;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private ListSchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(final String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(final String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            this.status = status;
+        }
+
+        @Override
+        public List<QName> getKeyDefinition() {
+            return keyDefinition;
+        }
+
+        private void setKeyDefinition(List<QName> keyDefinition) {
+            if (keyDefinition != null) {
+                this.keyDefinition = keyDefinition;
+            }
+        }
+
+        @Override
+        public boolean isAugmenting() {
+            return augmenting;
+        }
+
+        private void setAugmenting(boolean augmenting) {
+            this.augmenting = augmenting;
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(final boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public boolean isConfiguration() {
+            return configuration;
+        }
+
+        private void setConfiguration(boolean configuration) {
+            this.configuration = configuration;
+        }
+
+        @Override
+        public ConstraintDefinition getConstraints() {
+            return constraints;
+        }
+
+        private void setConstraints(ConstraintDefinition constraints) {
+            this.constraints = constraints;
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAvailableAugmentations() {
+            return augmentations;
+        }
+
+        private void setAvailableAugmentations(Set<AugmentationSchema> augmentations) {
+            if (augmentations != null) {
+                this.augmentations = augmentations;
+            }
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            return new HashSet<DataSchemaNode>(childNodes.values());
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            if (groupings != null) {
+                this.groupings = groupings;
+            }
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+            if (typeDefinitions != null) {
+                this.typeDefinitions = typeDefinitions;
+            }
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public boolean isUserOrdered() {
+            return userOrdered;
+        }
+
+        private void setUserOrdered(boolean userOrdered) {
+            this.userOrdered = userOrdered;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        public ListSchemaNodeBuilder toBuilder() {
+            return ListSchemaNodeBuilder.this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final ListSchemaNodeImpl other = (ListSchemaNodeImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ListSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("qname=" + qname);
+            sb.append(", path=" + path);
+            sb.append(", keyDefinition=" + keyDefinition);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ModuleBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ModuleBuilder.java
new file mode 100644 (file)
index 0000000..80fe524
--- /dev/null
@@ -0,0 +1,1260 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.Deviation;
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
+import org.opendaylight.controller.yang.model.api.FeatureDefinition;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+import org.opendaylight.controller.yang.model.api.RpcDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.RefineHolder;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+/**
+ * Builder of Module object. If this module is dependent on external
+ * module/modules, these dependencies must be resolved before module is built,
+ * otherwise result may not be valid.
+ */
+public class ModuleBuilder extends AbstractDataNodeContainerBuilder {
+    private final ModuleImpl instance;
+    private final String name;
+    private URI namespace;
+    private String prefix;
+    private Date revision;
+
+    private int augmentsResolved;
+
+    private final LinkedList<Builder> actualPath = new LinkedList<Builder>();
+    private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<TypeAwareBuilder>();
+
+    private final Set<ModuleImport> imports = new HashSet<ModuleImport>();
+    private final List<AugmentationSchemaBuilder> addedAugments = new ArrayList<AugmentationSchemaBuilder>();
+    private final List<AugmentationSchemaBuilder> allAugments = new ArrayList<AugmentationSchemaBuilder>();
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    private final List<UsesNodeBuilder> allUsesNodes = new ArrayList<UsesNodeBuilder>();
+    private final Set<RpcDefinitionBuilder> addedRpcs = new HashSet<RpcDefinitionBuilder>();
+    private final Set<NotificationBuilder> addedNotifications = new HashSet<NotificationBuilder>();
+    private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<IdentitySchemaNodeBuilder>();
+    private final Set<FeatureBuilder> addedFeatures = new HashSet<FeatureBuilder>();
+    private final Set<DeviationBuilder> addedDeviations = new HashSet<DeviationBuilder>();
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+    private final List<ExtensionBuilder> addedExtensions = new ArrayList<ExtensionBuilder>();
+    private final List<UnknownSchemaNodeBuilder> allUnknownNodes = new ArrayList<UnknownSchemaNodeBuilder>();
+
+    public ModuleBuilder(final String name) {
+        super(name, 0, null);
+        this.name = name;
+        instance = new ModuleImpl(name);
+        actualPath.push(this);
+    }
+
+    /**
+     * Build new Module object based on this builder.
+     */
+    @Override
+    public Module build() {
+        instance.setPrefix(prefix);
+        instance.setRevision(revision);
+        instance.setImports(imports);
+        instance.setNamespace(namespace);
+
+        // TYPEDEFS
+        final Set<TypeDefinition<?>> typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+        for (TypeDefinitionBuilder tdb : addedTypedefs) {
+            typedefs.add(tdb.build());
+        }
+        instance.setTypeDefinitions(typedefs);
+
+        // CHILD NODES
+        final Map<QName, DataSchemaNode> children = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+        for (DataSchemaNodeBuilder child : addedChildNodes) {
+            children.put(child.getQName(), child.build());
+        }
+        instance.setChildNodes(children);
+
+        // GROUPINGS
+        final Set<GroupingDefinition> groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+        for (GroupingBuilder gb : addedGroupings) {
+            groupings.add(gb.build());
+        }
+        instance.setGroupings(groupings);
+
+        // USES
+        final Set<UsesNode> usesDefinitions = new HashSet<UsesNode>();
+        for (UsesNodeBuilder unb : addedUsesNodes) {
+            usesDefinitions.add(unb.build());
+        }
+        instance.setUses(usesDefinitions);
+
+        // FEATURES
+        final Set<FeatureDefinition> features = new TreeSet<FeatureDefinition>(Comparators.SCHEMA_NODE_COMP);
+        for (FeatureBuilder fb : addedFeatures) {
+            features.add(fb.build());
+        }
+        instance.setFeatures(features);
+
+        // NOTIFICATIONS
+        final Set<NotificationDefinition> notifications = new TreeSet<NotificationDefinition>(
+                Comparators.SCHEMA_NODE_COMP);
+        for (NotificationBuilder entry : addedNotifications) {
+            notifications.add(entry.build());
+        }
+        instance.setNotifications(notifications);
+
+        // AUGMENTATIONS
+        final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
+        for (AugmentationSchemaBuilder builder : addedAugments) {
+            augmentations.add(builder.build());
+        }
+        instance.setAugmentations(augmentations);
+
+        // RPCs
+        final Set<RpcDefinition> rpcs = new TreeSet<RpcDefinition>(Comparators.SCHEMA_NODE_COMP);
+        for (RpcDefinitionBuilder rpc : addedRpcs) {
+            rpcs.add(rpc.build());
+        }
+        instance.setRpcs(rpcs);
+
+        // DEVIATIONS
+        final Set<Deviation> deviations = new HashSet<Deviation>();
+        for (DeviationBuilder entry : addedDeviations) {
+            deviations.add(entry.build());
+        }
+        instance.setDeviations(deviations);
+
+        // EXTENSIONS
+        final List<ExtensionDefinition> extensions = new ArrayList<ExtensionDefinition>();
+        for (ExtensionBuilder eb : addedExtensions) {
+            extensions.add(eb.build());
+        }
+        Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP);
+        instance.setExtensionSchemaNodes(extensions);
+
+        // IDENTITIES
+        final Set<IdentitySchemaNode> identities = new TreeSet<IdentitySchemaNode>(Comparators.SCHEMA_NODE_COMP);
+        for (IdentitySchemaNodeBuilder id : addedIdentities) {
+            identities.add(id.build());
+        }
+        instance.setIdentities(identities);
+
+        // UNKNOWN NODES
+        final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+        for (UnknownSchemaNodeBuilder unb : addedUnknownNodes) {
+            unknownNodes.add(unb.build());
+        }
+        instance.setUnknownSchemaNodes(unknownNodes);
+
+        return instance;
+    }
+
+    @Override
+    public void setParent(Builder parent) {
+        throw new YangParseException(name, 0, "Can not set parent to module");
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return null;
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return addedTypedefs;
+    }
+
+    public void enterNode(final Builder node) {
+        actualPath.push(node);
+    }
+
+    public void exitNode() {
+        actualPath.pop();
+    }
+
+    public Builder getActualNode() {
+        if (actualPath.isEmpty()) {
+            return null;
+        } else {
+            return actualPath.get(0);
+        }
+    }
+
+    public Builder getActualParent() {
+        if (actualPath.size() < 2) {
+            return null;
+        } else {
+            return actualPath.get(1);
+        }
+    }
+
+    public Set<TypeAwareBuilder> getDirtyNodes() {
+        return dirtyNodes;
+    }
+
+    public List<AugmentationSchemaBuilder> getAllAugments() {
+        return allAugments;
+    }
+
+    public Set<IdentitySchemaNodeBuilder> getIdentities() {
+        return addedIdentities;
+    }
+
+    public List<UsesNodeBuilder> getAllUsesNodes() {
+        return allUsesNodes;
+    }
+
+    public Set<DeviationBuilder> getDeviations() {
+        return addedDeviations;
+    }
+
+    public List<UnknownSchemaNodeBuilder> getAllUnknownNodes() {
+        return allUnknownNodes;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public URI getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(final URI namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getPrefix() {
+        return prefix;
+    }
+
+    public Date getRevision() {
+        return revision;
+    }
+
+    public int getAugmentsResolved() {
+        return augmentsResolved;
+    }
+
+    public void augmentResolved() {
+        augmentsResolved++;
+    }
+
+    public void markActualNodeDirty() {
+        final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) getActualNode();
+        dirtyNodes.add(nodeBuilder);
+    }
+
+    public void setRevision(final Date revision) {
+        this.revision = revision;
+    }
+
+    public void setPrefix(final String prefix) {
+        this.prefix = prefix;
+    }
+
+    public void setYangVersion(final String yangVersion) {
+        instance.setYangVersion(yangVersion);
+    }
+
+    public void setDescription(final String description) {
+        instance.setDescription(description);
+    }
+
+    public void setReference(final String reference) {
+        instance.setReference(reference);
+    }
+
+    public void setOrganization(final String organization) {
+        instance.setOrganization(organization);
+    }
+
+    public void setContact(final String contact) {
+        instance.setContact(contact);
+    }
+
+    public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
+        final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
+        return imports.add(moduleImport);
+    }
+
+    public Set<ModuleImport> getModuleImports() {
+        return imports;
+    }
+
+    public ExtensionBuilder addExtension(final QName qname, final int line) {
+        final String extName = qname.getLocalName();
+        for (ExtensionBuilder addedExtension : addedExtensions) {
+            if (addedExtension.getQName().getLocalName().equals(extName)) {
+                throw new YangParseException(moduleName, line, "Can not add extension '" + extName
+                        + "': extension with same name already declared at line " + addedExtension.getLine());
+            }
+        }
+        final ExtensionBuilder builder = new ExtensionBuilder(name, line, qname);
+        addedExtensions.add(builder);
+        return builder;
+    }
+
+    public ContainerSchemaNodeBuilder addContainerNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    public ListSchemaNodeBuilder addListNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        final ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(name, line, qname, schemaPath);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    public LeafSchemaNodeBuilder addLeafNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(name, line, qname, schemaPath);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    public LeafListSchemaNodeBuilder addLeafListNode(final int line, final QName qname, final SchemaPath schemaPath) {
+        final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(name, line, qname, schemaPath);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    public GroupingBuilder addGrouping(final int line, final QName qname) {
+        final GroupingBuilder builder = new GroupingBuilderImpl(name, line, qname);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+
+        String groupingName = qname.getLocalName();
+        if (parent.equals(this)) {
+            for (GroupingBuilder addedGrouping : addedGroupings) {
+                if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
+                    throw new YangParseException(name, line, "grouping with same name '" + groupingName
+                            + "' already declared at line " + addedGrouping.getLine());
+                }
+            }
+            addedGroupings.add(builder);
+        } else {
+            if (parent instanceof DataNodeContainerBuilder) {
+                DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
+                for (GroupingBuilder addedGrouping : parentNode.getGroupingBuilders()) {
+                    if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
+                        throw new YangParseException(name, line, "grouping with same name '" + groupingName
+                                + "' already declared at line " + addedGrouping.getLine());
+                    }
+                }
+                parentNode.addGrouping(builder);
+            } else if (parent instanceof RpcDefinitionBuilder) {
+                RpcDefinitionBuilder parentNode = (RpcDefinitionBuilder) parent;
+                for (GroupingBuilder child : parentNode.getGroupings()) {
+                    if (child.getQName().getLocalName().equals(groupingName)) {
+                        throw new YangParseException(name, line, "grouping with same name '" + groupingName
+                                + "' already declared at line " + child.getLine());
+                    }
+                }
+                parentNode.addGrouping(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of grouping " + groupingName);
+            }
+        }
+
+        return builder;
+    }
+
+    public AugmentationSchemaBuilder addAugment(final int line, final String augmentTargetStr) {
+        final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name, line, augmentTargetStr);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+
+        if (parent.equals(this)) {
+            // augment can be declared only under 'module' ...
+            addedAugments.add(builder);
+        } else {
+            // ... or 'uses' statement
+            if (parent instanceof UsesNodeBuilder) {
+                ((UsesNodeBuilder) parent).addAugment(builder);
+            } else {
+                throw new YangParseException(name, line, "Augment can be declared only under module or uses statement.");
+            }
+        }
+        allAugments.add(builder);
+
+        return builder;
+    }
+
+    @Override
+    public void addUsesNode(UsesNodeBuilder usesBuilder) {
+        addedUsesNodes.add(usesBuilder);
+        allUsesNodes.add(usesBuilder);
+    }
+
+    public UsesNodeBuilder addUsesNode(final int line, final String groupingPathStr) {
+        final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(name, line, groupingPathStr);
+
+        Builder parent = getActualNode();
+        usesBuilder.setParent(parent);
+
+        if (parent.equals(this)) {
+            addedUsesNodes.add(usesBuilder);
+        } else {
+            if (!(parent instanceof DataNodeContainerBuilder)) {
+                throw new YangParseException(name, line, "Unresolved parent of uses '" + groupingPathStr + "'.");
+            }
+            if (parent instanceof AugmentationSchemaBuilder) {
+                usesBuilder.setAugmenting(true);
+            }
+            ((DataNodeContainerBuilder) parent).addUsesNode(usesBuilder);
+        }
+        allUsesNodes.add(usesBuilder);
+        return usesBuilder;
+    }
+
+    public void addRefine(final RefineHolder refine) {
+        final Builder parent = getActualNode();
+        if (!(parent instanceof UsesNodeBuilder)) {
+            throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
+        }
+        ((UsesNodeBuilder) parent).addRefine(refine);
+        refine.setParent(parent);
+    }
+
+    public RpcDefinitionBuilder addRpc(final int line, final QName qname) {
+        Builder parent = getActualNode();
+        if (!(parent.equals(this))) {
+            throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
+        }
+
+        final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(name, line, qname);
+
+        String rpcName = qname.getLocalName();
+        for (RpcDefinitionBuilder rpc : addedRpcs) {
+            if (rpc.getQName().getLocalName().equals(rpcName)) {
+                throw new YangParseException(name, line, "rpc with same name '" + rpcName
+                        + "' already declared at line " + rpc.getLine());
+            }
+        }
+        for (DataSchemaNodeBuilder addedChild : addedChildNodes) {
+            if (addedChild.getQName().getLocalName().equals(rpcName)) {
+                throw new YangParseException(name, line, "Can not add rpc: node with same name '" + rpcName
+                        + "' already declared at line " + addedChild.getLine());
+            }
+        }
+        for (NotificationBuilder addedNotification : addedNotifications) {
+            if (addedNotification.getQName().getLocalName().equals(rpcName)) {
+                throw new YangParseException(name, line, "Can not add rpc: notification with same name '" + rpcName
+                        + "' already declared at line " + addedNotification.getLine());
+            }
+        }
+        addedRpcs.add(rpcBuilder);
+        return rpcBuilder;
+    }
+
+    public ContainerSchemaNodeBuilder addRpcInput(final int line, final QName qname, final SchemaPath schemaPath) {
+        final Builder parent = getActualNode();
+        if (!(parent instanceof RpcDefinitionBuilder)) {
+            throw new YangParseException(name, line, "input can be defined only in rpc statement");
+        }
+        final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
+
+        final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
+        inputBuilder.setParent(rpc);
+
+        rpc.setInput(inputBuilder);
+        return inputBuilder;
+    }
+
+    public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName qname, final int line) {
+        final Builder parent = getActualNode();
+        if (!(parent instanceof RpcDefinitionBuilder)) {
+            throw new YangParseException(name, line, "output can be defined only in rpc statement");
+        }
+        final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
+
+        final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
+        outputBuilder.setParent(rpc);
+
+        rpc.setOutput(outputBuilder);
+        return outputBuilder;
+    }
+
+    public NotificationBuilder addNotification(final int line, final QName qname) {
+        final Builder parent = getActualNode();
+        if (!(parent.equals(this))) {
+            throw new YangParseException(name, line, "notification can be defined only in module or submodule");
+        }
+
+        String notificationName = qname.getLocalName();
+        for (NotificationBuilder nb : addedNotifications) {
+            if (nb.getQName().equals(qname)) {
+                throw new YangParseException(name, line, "notification with same name '" + notificationName
+                        + "' already declared at line " + nb.getLine());
+            }
+        }
+        for (RpcDefinitionBuilder rpc : addedRpcs) {
+            if (rpc.getQName().getLocalName().equals(notificationName)) {
+                throw new YangParseException(name, line, "Can not add notification: rpc with same name '"
+                        + notificationName + "' already declared at line " + rpc.getLine());
+            }
+        }
+        for (DataSchemaNodeBuilder addedChild : addedChildNodes) {
+            if (addedChild.getQName().getLocalName().equals(notificationName)) {
+                throw new YangParseException(name, line, "Can not add notification: node with same name '"
+                        + notificationName + "' already declared at line " + addedChild.getLine());
+            }
+        }
+
+        final NotificationBuilder builder = new NotificationBuilder(name, line, qname);
+        addedNotifications.add(builder);
+
+        return builder;
+    }
+
+    public FeatureBuilder addFeature(final int line, final QName qname) {
+        Builder parent = getActualNode();
+        if (!(parent.equals(this))) {
+            throw new YangParseException(name, line, "feature can be defined only in module or submodule");
+        }
+
+        final FeatureBuilder builder = new FeatureBuilder(name, line, qname);
+
+        String featureName = qname.getLocalName();
+        for (FeatureBuilder addedFeature : addedFeatures) {
+            if (addedFeature.getQName().getLocalName().equals(featureName)) {
+                throw new YangParseException(name, line, "feature with same name '" + featureName
+                        + "' already declared at line " + addedFeature.getLine());
+            }
+        }
+        addedFeatures.add(builder);
+        return builder;
+    }
+
+    public ChoiceBuilder addChoice(final int line, final QName qname) {
+        final ChoiceBuilder builder = new ChoiceBuilder(name, line, qname);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    public ChoiceCaseBuilder addCase(final int line, final QName qname) {
+        Builder parent = getActualNode();
+        if (parent == null || parent.equals(this)) {
+            throw new YangParseException(name, line, "'case' parent not found");
+        }
+
+        final ChoiceCaseBuilder builder = new ChoiceCaseBuilder(name, line, qname);
+        builder.setParent(parent);
+
+        if (parent instanceof ChoiceBuilder) {
+            ((ChoiceBuilder) parent).addCase(builder);
+        } else if (parent instanceof AugmentationSchemaBuilder) {
+            ((AugmentationSchemaBuilder) parent).addChildNode(builder);
+        } else {
+            throw new YangParseException(name, line, "Unresolved parent of 'case' " + qname.getLocalName());
+        }
+
+        return builder;
+    }
+
+    public AnyXmlBuilder addAnyXml(final int line, final QName qname, final SchemaPath schemaPath) {
+        final AnyXmlBuilder builder = new AnyXmlBuilder(name, line, qname, schemaPath);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+        addChildToParent(parent, builder, qname.getLocalName());
+
+        return builder;
+    }
+
+    @Override
+    public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
+        String nodeName = typedefBuilder.getQName().getLocalName();
+        for (TypeDefinitionBuilder tdb : addedTypedefs) {
+            if (tdb.getQName().getLocalName().equals(nodeName)) {
+                throw new YangParseException(name, typedefBuilder.getLine(), "typedef with same name '" + nodeName
+                        + "' already declared at line " + tdb.getLine());
+            }
+        }
+        addedTypedefs.add(typedefBuilder);
+    }
+
+    public TypeDefinitionBuilderImpl addTypedef(final int line, final QName qname) {
+        final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(name, line, qname);
+
+        Builder parent = getActualNode();
+        builder.setParent(parent);
+
+        String typedefName = qname.getLocalName();
+        if (parent.equals(this)) {
+            for (TypeDefinitionBuilder tdb : addedTypedefs) {
+                if (tdb.getQName().getLocalName().equals(typedefName)) {
+                    throw new YangParseException(name, line, "typedef with same name '" + typedefName
+                            + "' already declared at line " + tdb.getLine());
+                }
+            }
+            addedTypedefs.add(builder);
+        } else {
+            if (parent instanceof DataNodeContainerBuilder) {
+                DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
+                for (TypeDefinitionBuilder child : parentNode.getTypeDefinitionBuilders()) {
+                    if (child.getQName().getLocalName().equals(typedefName)) {
+                        throw new YangParseException(name, line, "typedef with same name '" + typedefName
+                                + "' already declared at line " + child.getLine());
+                    }
+                }
+                parentNode.addTypedef(builder);
+            } else if (parent instanceof RpcDefinitionBuilder) {
+                RpcDefinitionBuilder rpcParent = (RpcDefinitionBuilder) parent;
+                for (TypeDefinitionBuilder tdb : rpcParent.getTypeDefinitions()) {
+                    if (tdb.getQName().getLocalName().equals(builder.getQName().getLocalName())) {
+                        throw new YangParseException(name, line, "typedef with same name '" + typedefName
+                                + "' already declared at line " + tdb.getLine());
+                    }
+                }
+                rpcParent.addTypedef(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of typedef " + typedefName);
+            }
+        }
+
+        return builder;
+    }
+
+    public void setType(final TypeDefinition<?> type) {
+        Builder parent = getActualNode();
+        if (parent == null || !(parent instanceof TypeAwareBuilder)) {
+            throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
+                    + "'. Invalid parent node: " + parent);
+        }
+        ((TypeAwareBuilder) parent).setType(type);
+    }
+
+    public UnionTypeBuilder addUnionType(final int line, final URI namespace, final Date revision) {
+        final Builder parent = getActualNode();
+        if (parent == null) {
+            throw new YangParseException(name, line, "Unresolved parent of union type");
+        } else {
+            final UnionTypeBuilder union = new UnionTypeBuilder(name, line);
+            if (parent instanceof TypeAwareBuilder) {
+                ((TypeAwareBuilder) parent).setTypedef(union);
+                return union;
+            } else {
+                throw new YangParseException(name, line, "Invalid parent of union type.");
+            }
+        }
+    }
+
+    public void addIdentityrefType(final int line, final SchemaPath schemaPath, final String baseString) {
+        final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(name, line, baseString, schemaPath);
+
+        final Builder parent = getActualNode();
+        if (parent == null) {
+            throw new YangParseException(name, line, "Unresolved parent of identityref type.");
+        } else {
+            if (parent instanceof TypeAwareBuilder) {
+                final TypeAwareBuilder typeParent = (TypeAwareBuilder) parent;
+                typeParent.setTypedef(identityref);
+                dirtyNodes.add(typeParent);
+            } else {
+                throw new YangParseException(name, line, "Invalid parent of identityref type.");
+            }
+        }
+    }
+
+    public DeviationBuilder addDeviation(final int line, final String targetPath) {
+        Builder parent = getActualNode();
+        if (!(parent.equals(this))) {
+            throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
+        }
+
+        final DeviationBuilder builder = new DeviationBuilder(name, line, targetPath);
+        addedDeviations.add(builder);
+        return builder;
+    }
+
+    public IdentitySchemaNodeBuilder addIdentity(final QName qname, final List<String> parentPath, final int line) {
+        Builder parent = getActualNode();
+        if (!(parent.equals(this))) {
+            throw new YangParseException(name, line, "identity can be defined only in module or submodule");
+        }
+        String identityName = qname.getLocalName();
+        for (IdentitySchemaNodeBuilder idBuilder : addedIdentities) {
+            if (idBuilder.getQName().equals(qname)) {
+                throw new YangParseException(name, line, "identity with same name '" + identityName
+                        + "' already declared at line " + idBuilder.getLine());
+            }
+        }
+
+        final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(name, line, qname);
+        addedIdentities.add(builder);
+        return builder;
+    }
+
+    @Override
+    public void addUnknownNodeBuilder(final UnknownSchemaNodeBuilder builder) {
+        addedUnknownNodes.add(builder);
+        allUnknownNodes.add(builder);
+    }
+
+    public UnknownSchemaNodeBuilder addUnknownSchemaNode(final int line, final QName qname) {
+        final Builder parent = getActualNode();
+        final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(name, line, qname);
+        builder.setParent(parent);
+        allUnknownNodes.add(builder);
+
+        if (parent.equals(this)) {
+            addedUnknownNodes.add(builder);
+        } else {
+            if (parent instanceof SchemaNodeBuilder) {
+                ((SchemaNodeBuilder) parent).addUnknownNodeBuilder(builder);
+            } else if (parent instanceof DataNodeContainerBuilder) {
+                ((DataNodeContainerBuilder) parent).addUnknownNodeBuilder(builder);
+            } else if (parent instanceof RefineHolder) {
+                ((RefineHolder) parent).addUnknownNodeBuilder(builder);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
+                        + "'");
+            }
+        }
+
+        return builder;
+    }
+
+    @Override
+    public String toString() {
+        return "module " + name;
+    }
+
+    private final class ModuleImpl implements Module {
+        private URI namespace;
+        private final String name;
+        private Date revision;
+        private String prefix;
+        private String yangVersion;
+        private String description;
+        private String reference;
+        private String organization;
+        private String contact;
+        private Set<ModuleImport> imports = Collections.emptySet();
+        private Set<FeatureDefinition> features = Collections.emptySet();
+        private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
+        private Set<NotificationDefinition> notifications = Collections.emptySet();
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private Set<RpcDefinition> rpcs = Collections.emptySet();
+        private Set<Deviation> deviations = Collections.emptySet();
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<GroupingDefinition> groupings = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private List<ExtensionDefinition> extensionNodes = Collections.emptyList();
+        private Set<IdentitySchemaNode> identities = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private ModuleImpl(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public URI getNamespace() {
+            return namespace;
+        }
+
+        private void setNamespace(URI namespace) {
+            this.namespace = namespace;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Date getRevision() {
+            return revision;
+        }
+
+        private void setRevision(Date revision) {
+            this.revision = revision;
+        }
+
+        @Override
+        public String getPrefix() {
+            return prefix;
+        }
+
+        private void setPrefix(String prefix) {
+            this.prefix = prefix;
+        }
+
+        @Override
+        public String getYangVersion() {
+            return yangVersion;
+        }
+
+        private void setYangVersion(String yangVersion) {
+            this.yangVersion = yangVersion;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public String getOrganization() {
+            return organization;
+        }
+
+        private void setOrganization(String organization) {
+            this.organization = organization;
+        }
+
+        @Override
+        public String getContact() {
+            return contact;
+        }
+
+        private void setContact(String contact) {
+            this.contact = contact;
+        }
+
+        @Override
+        public Set<ModuleImport> getImports() {
+            return imports;
+        }
+
+        private void setImports(Set<ModuleImport> imports) {
+            if (imports != null) {
+                this.imports = imports;
+            }
+        }
+
+        @Override
+        public Set<FeatureDefinition> getFeatures() {
+            return features;
+        }
+
+        private void setFeatures(Set<FeatureDefinition> features) {
+            if (features != null) {
+                this.features = features;
+            }
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+            if (typeDefinitions != null) {
+                this.typeDefinitions = typeDefinitions;
+            }
+        }
+
+        @Override
+        public Set<NotificationDefinition> getNotifications() {
+            return notifications;
+        }
+
+        private void setNotifications(Set<NotificationDefinition> notifications) {
+            if (notifications != null) {
+                this.notifications = notifications;
+            }
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAugmentations() {
+            return augmentations;
+        }
+
+        private void setAugmentations(Set<AugmentationSchema> augmentations) {
+            if (augmentations != null) {
+                this.augmentations = augmentations;
+            }
+        }
+
+        @Override
+        public Set<RpcDefinition> getRpcs() {
+            return rpcs;
+        }
+
+        private void setRpcs(Set<RpcDefinition> rpcs) {
+            if (rpcs != null) {
+                this.rpcs = rpcs;
+            }
+        }
+
+        @Override
+        public Set<Deviation> getDeviations() {
+            return deviations;
+        }
+
+        private void setDeviations(Set<Deviation> deviations) {
+            if (deviations != null) {
+                this.deviations = deviations;
+            }
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            return new LinkedHashSet<DataSchemaNode>(childNodes.values());
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            if (groupings != null) {
+                this.groupings = groupings;
+            }
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        @Override
+        public List<ExtensionDefinition> getExtensionSchemaNodes() {
+            return extensionNodes;
+        }
+
+        private void setExtensionSchemaNodes(final List<ExtensionDefinition> extensionNodes) {
+            if (extensionNodes != null) {
+                this.extensionNodes = extensionNodes;
+            }
+        }
+
+        @Override
+        public Set<IdentitySchemaNode> getIdentities() {
+            return identities;
+        }
+
+        private void setIdentities(final Set<IdentitySchemaNode> identities) {
+            if (identities != null) {
+                this.identities = identities;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+            result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
+            result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ModuleImpl other = (ModuleImpl) obj;
+            if (namespace == null) {
+                if (other.namespace != null) {
+                    return false;
+                }
+            } else if (!namespace.equals(other.namespace)) {
+                return false;
+            }
+            if (name == null) {
+                if (other.name != null) {
+                    return false;
+                }
+            } else if (!name.equals(other.name)) {
+                return false;
+            }
+            if (revision == null) {
+                if (other.revision != null) {
+                    return false;
+                }
+            } else if (!revision.equals(other.revision)) {
+                return false;
+            }
+            if (prefix == null) {
+                if (other.prefix != null) {
+                    return false;
+                }
+            } else if (!prefix.equals(other.prefix)) {
+                return false;
+            }
+            if (yangVersion == null) {
+                if (other.yangVersion != null) {
+                    return false;
+                }
+            } else if (!yangVersion.equals(other.yangVersion)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append("name=" + name);
+            sb.append(", namespace=" + namespace);
+            sb.append(", revision=" + revision);
+            sb.append(", prefix=" + prefix);
+            sb.append(", yangVersion=" + yangVersion);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Add child to parent. Method checks for duplicates and add given child
+     * node to parent. If node with same name is found, throws exception. If
+     * parent is null, child node will be added directly to module.
+     *
+     * @param parent
+     * @param child
+     * @param childName
+     */
+    private void addChildToParent(final Builder parent, final DataSchemaNodeBuilder child, final String childName) {
+        final int line = child.getLine();
+        if (parent.equals(this)) {
+            // if parent == null => node is defined under module
+            // All leafs, leaf-lists, lists, containers, choices, rpcs,
+            // notifications, and anyxmls defined within a parent node or at the
+            // top level of the module or its submodules share the same
+            // identifier namespace.
+            for (DataSchemaNodeBuilder childNode : addedChildNodes) {
+                if (childNode.getQName().getLocalName().equals(childName)) {
+                    throw new YangParseException(name, line, "Can not add '" + child
+                            + "': node with same name already declared at line " + childNode.getLine());
+                }
+            }
+            for (RpcDefinitionBuilder rpc : addedRpcs) {
+                if (rpc.getQName().getLocalName().equals(childName)) {
+                    throw new YangParseException(name, line, "Can not add '" + child
+                            + "': rpc with same name already declared at line " + rpc.getLine());
+                }
+            }
+            for (NotificationBuilder notification : addedNotifications) {
+                if (notification.getQName().getLocalName().equals(childName)) {
+                    throw new YangParseException(name, line, "Can not add '" + child
+                            + "': notification with same name already declared at line " + notification.getLine());
+                }
+            }
+            addedChildNodes.add(child);
+        } else {
+            // no need for checking rpc and notification because they can be
+            // defined only under module or submodule
+            if (parent instanceof DataNodeContainerBuilder) {
+                DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
+                for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) {
+                    if (childNode.getQName().getLocalName().equals(childName)) {
+                        throw new YangParseException(name, line, "Can not add '" + child + "': node with same name '"
+                                + childName + "' already declared at line " + childNode.getLine());
+                    }
+                }
+                parentNode.addChildNode(child);
+            } else if (parent instanceof ChoiceBuilder) {
+                ChoiceBuilder parentNode = (ChoiceBuilder) parent;
+                for (ChoiceCaseBuilder caseBuilder : parentNode.getCases()) {
+                    if (caseBuilder.getQName().getLocalName().equals(childName)) {
+                        throw new YangParseException(name, line, "Can not add '" + child + "': case with same name '"
+                                + childName + "' already declared at line " + caseBuilder.getLine());
+                    }
+                }
+                parentNode.addCase(child);
+            } else {
+                throw new YangParseException(name, line, "Unresolved parent of node '" + childName + "'.");
+            }
+        }
+    }
+
+    private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
+        final ModuleImport moduleImport = new ModuleImport() {
+            @Override
+            public String getModuleName() {
+                return moduleName;
+            }
+
+            @Override
+            public Date getRevision() {
+                return revision;
+            }
+
+            @Override
+            public String getPrefix() {
+                return prefix;
+            }
+
+            @Override
+            public int hashCode() {
+                final int prime = 31;
+                int result = 1;
+                result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
+                result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+                result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
+                return result;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (this == obj) {
+                    return true;
+                }
+                if (obj == null) {
+                    return false;
+                }
+                if (getClass() != obj.getClass()) {
+                    return false;
+                }
+                ModuleImport other = (ModuleImport) obj;
+                if (getModuleName() == null) {
+                    if (other.getModuleName() != null) {
+                        return false;
+                    }
+                } else if (!getModuleName().equals(other.getModuleName())) {
+                    return false;
+                }
+                if (getRevision() == null) {
+                    if (other.getRevision() != null) {
+                        return false;
+                    }
+                } else if (!getRevision().equals(other.getRevision())) {
+                    return false;
+                }
+                if (getPrefix() == null) {
+                    if (other.getPrefix() != null) {
+                        return false;
+                    }
+                } else if (!getPrefix().equals(other.getPrefix())) {
+                    return false;
+                }
+                return true;
+            }
+
+            @Override
+            public String toString() {
+                return "ModuleImport[moduleName=" + moduleName + ", revision=" + revision + ", prefix=" + prefix + "]";
+            }
+        };
+        return moduleImport;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/NotificationBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/NotificationBuilder.java
new file mode 100644 (file)
index 0000000..eab1cff
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class NotificationBuilder extends AbstractDataNodeContainerBuilder implements SchemaNodeBuilder,
+        AugmentationTargetBuilder {
+    private boolean isBuilt;
+    private final NotificationDefinitionImpl instance;
+    private SchemaPath schemaPath;
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+    private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
+    private Set<AugmentationSchema> augmentations;
+    private final Set<AugmentationSchemaBuilder> addedAugmentations = new HashSet<AugmentationSchemaBuilder>();
+
+    NotificationBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new NotificationDefinitionImpl(qname);
+    }
+
+    @Override
+    public NotificationDefinition build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+
+            // CHILD NODES
+            final Map<QName, DataSchemaNode> childs = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
+            for (DataSchemaNodeBuilder node : addedChildNodes) {
+                childs.put(node.getQName(), node.build());
+            }
+            instance.setChildNodes(childs);
+
+            // GROUPINGS
+            final Set<GroupingDefinition> groupingDefs = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+            for (GroupingBuilder builder : addedGroupings) {
+                groupingDefs.add(builder.build());
+            }
+            instance.setGroupings(groupingDefs);
+
+            // TYPEDEFS
+            final Set<TypeDefinition<?>> typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+            for (TypeDefinitionBuilder entry : addedTypedefs) {
+                typedefs.add(entry.build());
+            }
+            instance.setTypeDefinitions(typedefs);
+
+            // USES
+            final Set<UsesNode> uses = new HashSet<UsesNode>();
+            for (UsesNodeBuilder builder : addedUsesNodes) {
+                uses.add(builder.build());
+            }
+            instance.setUses(uses);
+
+            // AUGMENTATIONS
+            if (augmentations == null) {
+                augmentations = new HashSet<AugmentationSchema>();
+                for (AugmentationSchemaBuilder builder : addedAugmentations) {
+                    augmentations.add(builder.build());
+                }
+            }
+            instance.setAvailableAugmentations(augmentations);
+
+            // UNKNOWN NODES
+            final List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                unknownNodes.add(b.build());
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    @Override
+    public void rebuild() {
+        isBuilt = false;
+        build();
+    }
+
+    @Override
+    public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
+        return addedTypedefs;
+    }
+
+    @Override
+    public void addTypedef(final TypeDefinitionBuilder type) {
+        addedTypedefs.add(type);
+    }
+
+    @Override
+    public void addUsesNode(final UsesNodeBuilder usesNodeBuilder) {
+        addedUsesNodes.add(usesNodeBuilder);
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    public Set<AugmentationSchemaBuilder> getAugmentations() {
+        return addedAugmentations;
+    }
+
+    @Override
+    public void addAugmentation(AugmentationSchemaBuilder augment) {
+        addedAugmentations.add(augment);
+    }
+
+    public void setAugmentations(final Set<AugmentationSchema> augmentations) {
+        this.augmentations = augmentations;
+    }
+
+    @Override
+    public String toString() {
+        return "notification " + getQName().getLocalName();
+    }
+
+    public final class NotificationDefinitionImpl implements NotificationDefinition {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
+        private Set<GroupingDefinition> groupings = Collections.emptySet();
+        private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
+        private Set<UsesNode> uses = Collections.emptySet();
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private NotificationDefinitionImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(final String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public Set<DataSchemaNode> getChildNodes() {
+            return new HashSet<DataSchemaNode>(childNodes.values());
+        }
+
+        private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
+            if (childNodes != null) {
+                this.childNodes = childNodes;
+            }
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            if (groupings != null) {
+                this.groupings = groupings;
+            }
+        }
+
+        @Override
+        public Set<UsesNode> getUses() {
+            return uses;
+        }
+
+        private void setUses(Set<UsesNode> uses) {
+            if (uses != null) {
+                this.uses = uses;
+            }
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(final Set<TypeDefinition<?>> typeDefinitions) {
+            if (typeDefinitions != null) {
+                this.typeDefinitions = typeDefinitions;
+            }
+        }
+
+        @Override
+        public Set<AugmentationSchema> getAvailableAugmentations() {
+            return augmentations;
+        }
+
+        private void setAvailableAugmentations(Set<AugmentationSchema> augmentations) {
+            if (augmentations != null) {
+                this.augmentations = augmentations;
+            }
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(QName name) {
+            return childNodes.get(name);
+        }
+
+        @Override
+        public DataSchemaNode getDataChildByName(String name) {
+            DataSchemaNode result = null;
+            for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
+                if (entry.getKey().getLocalName().equals(name)) {
+                    result = entry.getValue();
+                    break;
+                }
+            }
+            return result;
+        }
+
+        public NotificationBuilder toBuilder() {
+            return NotificationBuilder.this;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final NotificationDefinitionImpl other = (NotificationDefinitionImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(NotificationDefinitionImpl.class.getSimpleName());
+            sb.append("[qname=" + qname + ", path=" + path + "]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/RpcDefinitionBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/RpcDefinitionBuilder.java
new file mode 100644 (file)
index 0000000..53190d0
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.RpcDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class RpcDefinitionBuilder extends AbstractSchemaNodeBuilder {
+    private boolean isBuilt;
+    private final RpcDefinitionImpl instance;
+    private ContainerSchemaNodeBuilder inputBuilder;
+    private ContainerSchemaNodeBuilder outputBuilder;
+    private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
+    private final Set<GroupingBuilder> addedGroupings = new HashSet<GroupingBuilder>();
+
+    RpcDefinitionBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        this.instance = new RpcDefinitionImpl(qname);
+    }
+
+    @Override
+    public RpcDefinition build() {
+        if (!isBuilt) {
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+
+            final ContainerSchemaNode input = inputBuilder == null ? null : inputBuilder.build();
+            final ContainerSchemaNode output = outputBuilder == null ? null : outputBuilder.build();
+            instance.setInput(input);
+            instance.setOutput(output);
+
+            instance.setPath(schemaPath);
+
+            // TYPEDEFS
+            final Set<TypeDefinition<?>> typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
+            for (TypeDefinitionBuilder entry : addedTypedefs) {
+                typedefs.add(entry.build());
+            }
+            instance.setTypeDefinitions(typedefs);
+
+            // GROUPINGS
+            final Set<GroupingDefinition> groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
+            for (GroupingBuilder entry : addedGroupings) {
+                groupings.add(entry.build());
+            }
+            instance.setGroupings(groupings);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    void setInput(final ContainerSchemaNodeBuilder inputBuilder) {
+        this.inputBuilder = inputBuilder;
+    }
+
+    void setOutput(final ContainerSchemaNodeBuilder outputBuilder) {
+        this.outputBuilder = outputBuilder;
+    }
+
+    public Set<TypeDefinitionBuilder> getTypeDefinitions() {
+        return addedTypedefs;
+    }
+
+    public void addTypedef(final TypeDefinitionBuilder type) {
+        addedTypedefs.add(type);
+    }
+
+    public Set<GroupingBuilder> getGroupings() {
+        return addedGroupings;
+    }
+
+    public void addGrouping(GroupingBuilder grouping) {
+        addedGroupings.add(grouping);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+        result = prime * result + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof RpcDefinitionBuilder)) {
+            return false;
+        }
+        final RpcDefinitionBuilder other = (RpcDefinitionBuilder) obj;
+        if (other.qname == null) {
+            if (this.qname != null) {
+                return false;
+            }
+        } else if (!other.qname.equals(this.qname)) {
+            return false;
+        }
+        if (other.schemaPath == null) {
+            if (this.schemaPath != null) {
+                return false;
+            }
+        } else if (!other.schemaPath.equals(this.schemaPath)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "rpc " + qname.getLocalName();
+    }
+
+    private final class RpcDefinitionImpl implements RpcDefinition {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status;
+        private ContainerSchemaNode input;
+        private ContainerSchemaNode output;
+        private Set<TypeDefinition<?>> typeDefinitions;
+        private Set<GroupingDefinition> groupings;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+        private RpcDefinitionImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(Status status) {
+            this.status = status;
+        }
+
+        @Override
+        public ContainerSchemaNode getInput() {
+            return input;
+        }
+
+        private void setInput(ContainerSchemaNode input) {
+            this.input = input;
+        }
+
+        @Override
+        public ContainerSchemaNode getOutput() {
+            return output;
+        }
+
+        private void setOutput(ContainerSchemaNode output) {
+            this.output = output;
+        }
+
+        @Override
+        public Set<TypeDefinition<?>> getTypeDefinitions() {
+            return typeDefinitions;
+        }
+
+        private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
+            this.typeDefinitions = typeDefinitions;
+        }
+
+        @Override
+        public Set<GroupingDefinition> getGroupings() {
+            return groupings;
+        }
+
+        private void setGroupings(Set<GroupingDefinition> groupings) {
+            this.groupings = groupings;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final RpcDefinitionImpl other = (RpcDefinitionImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(RpcDefinitionImpl.class.getSimpleName() + "[");
+            sb.append("qname=" + qname);
+            sb.append(", path=" + path);
+            sb.append(", input=" + input);
+            sb.append(", output=" + output + "]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java
new file mode 100644 (file)
index 0000000..5f2ca1c
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractTypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+public final class TypeDefinitionBuilderImpl extends AbstractTypeAwareBuilder implements TypeDefinitionBuilder {
+    private SchemaPath schemaPath;
+    private List<RangeConstraint> ranges = Collections.emptyList();
+    private List<LengthConstraint> lengths = Collections.emptyList();
+    private List<PatternConstraint> patterns = Collections.emptyList();
+    private Integer fractionDigits = null;
+
+    private String description;
+    private String reference;
+    private Status status = Status.CURRENT;
+    private String units;
+    private Object defaultValue;
+    private boolean addedByUses;
+
+    public TypeDefinitionBuilderImpl(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+    }
+
+    public TypeDefinitionBuilderImpl(TypeDefinitionBuilder tdb) {
+        super(tdb.getModuleName(), tdb.getLine(), tdb.getQName());
+        schemaPath = tdb.getPath();
+
+        type = tdb.getType();
+        typedef = tdb.getTypedef();
+
+        unknownNodes = tdb.getUnknownNodes();
+        for (UnknownSchemaNodeBuilder usnb : tdb.getUnknownNodeBuilders()) {
+            addedUnknownNodes.add(usnb);
+        }
+        ranges = tdb.getRanges();
+        lengths = tdb.getLengths();
+        patterns = tdb.getPatterns();
+        fractionDigits = tdb.getFractionDigits();
+
+        description = tdb.getDescription();
+        reference = tdb.getReference();
+        status = tdb.getStatus();
+        units = tdb.getUnits();
+        defaultValue = tdb.getDefaultValue();
+        addedByUses = tdb.isAddedByUses();
+    }
+
+    @Override
+    public TypeDefinition<? extends TypeDefinition<?>> build() {
+        TypeDefinition<?> result = null;
+        ExtendedType.Builder typeBuilder = null;
+        if ((type == null || type instanceof UnknownType) && typedef == null) {
+            throw new YangParseException("Unresolved type: '" + qname.getLocalName() + "'.");
+        }
+        if (type == null || type instanceof UnknownType) {
+            type = typedef.build();
+        }
+
+        typeBuilder = new ExtendedType.Builder(qname, type, description, reference, schemaPath);
+
+        typeBuilder.status(status);
+        typeBuilder.units(units);
+        typeBuilder.defaultValue(defaultValue);
+        typeBuilder.addedByUses(addedByUses);
+
+        typeBuilder.ranges(ranges);
+        typeBuilder.lengths(lengths);
+        typeBuilder.patterns(patterns);
+        typeBuilder.fractionDigits(fractionDigits);
+
+        // UNKNOWN NODES
+        if (unknownNodes == null) {
+            unknownNodes = new ArrayList<UnknownSchemaNode>();
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                unknownNodes.add(b.build());
+            }
+            Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+        }
+        typeBuilder.unknownSchemaNodes(unknownNodes);
+        result = typeBuilder.build();
+        return result;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.schemaPath = schemaPath;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    @Override
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        if (status != null) {
+            this.status = status;
+        }
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    @Override
+    public String getUnits() {
+        return units;
+    }
+
+    @Override
+    public void setUnits(final String units) {
+        this.units = units;
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return defaultValue;
+    }
+
+    @Override
+    public void setDefaultValue(final Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownNodes() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public List<RangeConstraint> getRanges() {
+        return ranges;
+    }
+
+    @Override
+    public void setRanges(final List<RangeConstraint> ranges) {
+        if (ranges != null) {
+            this.ranges = ranges;
+        }
+    }
+
+    @Override
+    public List<LengthConstraint> getLengths() {
+        return lengths;
+    }
+
+    @Override
+    public void setLengths(final List<LengthConstraint> lengths) {
+        if (lengths != null) {
+            this.lengths = lengths;
+        }
+    }
+
+    @Override
+    public List<PatternConstraint> getPatterns() {
+        return patterns;
+    }
+
+    @Override
+    public void setPatterns(final List<PatternConstraint> patterns) {
+        if (patterns != null) {
+            this.patterns = patterns;
+        }
+    }
+
+    @Override
+    public Integer getFractionDigits() {
+        return fractionDigits;
+    }
+
+    @Override
+    public void setFractionDigits(final Integer fractionDigits) {
+        this.fractionDigits = fractionDigits;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder result = new StringBuilder("TypedefBuilder[" + qname.getLocalName());
+        result.append(", type=");
+        if (type == null) {
+            result.append(typedef);
+        } else {
+            result.append(type);
+        }
+        result.append("]");
+        return result.toString();
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnionTypeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnionTypeBuilder.java
new file mode 100644 (file)
index 0000000..6c57c25
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.UnionType;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractTypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+
+/**
+ * Builder for YANG union type. User can add type to this union as
+ * TypeDefinition object (resolved type) or in form of TypeDefinitionBuilder.
+ * When build is called, types in builder form will be built and add to resolved
+ * types.
+ */
+public final class UnionTypeBuilder extends AbstractTypeAwareBuilder implements TypeDefinitionBuilder {
+    private final static String NAME = "union";
+
+    private final List<TypeDefinition<?>> types;
+    private final List<TypeDefinitionBuilder> typedefs;
+    private UnionType instance;
+    private boolean isBuilt;
+
+    private SchemaPath path;
+
+    public UnionTypeBuilder(final String moduleName, final int line) {
+        super(moduleName, line, null);
+        types = new ArrayList<TypeDefinition<?>>();
+        typedefs = new ArrayList<TypeDefinitionBuilder>();
+    }
+
+    public List<TypeDefinition<?>> getTypes() {
+        return types;
+    }
+
+    @Override
+    public TypeDefinition<?> getType() {
+        return null;
+    }
+
+    public List<TypeDefinitionBuilder> getTypedefs() {
+        return Collections.unmodifiableList(typedefs);
+    }
+
+    @Override
+    public TypeDefinitionBuilder getTypedef() {
+        return null;
+    }
+
+    @Override
+    public void setType(final TypeDefinition<?> type) {
+        types.add(type);
+    }
+
+    @Override
+    public void setTypedef(final TypeDefinitionBuilder tdb) {
+        typedefs.add(tdb);
+    }
+
+    @Override
+    public UnionType build() {
+        if (!isBuilt) {
+            instance = new UnionType(path, types);
+            for (TypeDefinitionBuilder tdb : typedefs) {
+                types.add(tdb.build());
+            }
+            isBuilt = true;
+        }
+        return instance;
+    }
+
+    @Override
+    public void setPath(final SchemaPath schemaPath) {
+        this.path = schemaPath;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        throw new YangParseException(moduleName, line, "Can not set description to " + NAME);
+    }
+
+    @Override
+    public void setReference(final String reference) {
+        throw new YangParseException(moduleName, line, "Can not set reference to " + NAME);
+    }
+
+    @Override
+    public void setStatus(final Status status) {
+        throw new YangParseException(moduleName, line, "Can not set status to " + NAME);
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return false;
+    }
+
+    @Override
+    public void setAddedByUses(final boolean addedByUses) {
+        throw new YangParseException(moduleName, line, "Union type can not be added by uses.");
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownNodes() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void addUnknownNodeBuilder(final UnknownSchemaNodeBuilder unknownNode) {
+        // not yet supported
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return path;
+    }
+
+    @Override
+    public String getDescription() {
+        return null;
+    }
+
+    @Override
+    public String getReference() {
+        return null;
+    }
+
+    @Override
+    public Status getStatus() {
+        return null;
+    }
+
+    @Override
+    public List<RangeConstraint> getRanges() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setRanges(List<RangeConstraint> ranges) {
+        throw new YangParseException(moduleName, line, "Can not set ranges to " + NAME);
+    }
+
+    @Override
+    public List<LengthConstraint> getLengths() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setLengths(List<LengthConstraint> lengths) {
+        throw new YangParseException(moduleName, line, "Can not set lengths to " + NAME);
+    }
+
+    @Override
+    public List<PatternConstraint> getPatterns() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void setPatterns(List<PatternConstraint> patterns) {
+        throw new YangParseException(moduleName, line, "Can not set patterns to " + NAME);
+    }
+
+    @Override
+    public Integer getFractionDigits() {
+        return null;
+    }
+
+    @Override
+    public void setFractionDigits(Integer fractionDigits) {
+        throw new YangParseException(moduleName, line, "Can not set fraction digits to " + NAME);
+    }
+
+    @Override
+    public List<UnknownSchemaNodeBuilder> getUnknownNodeBuilders() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return null;
+    }
+
+    @Override
+    public void setDefaultValue(Object defaultValue) {
+        throw new YangParseException(moduleName, line, "Can not set default value to " + NAME);
+    }
+
+    @Override
+    public String getUnits() {
+        return null;
+    }
+
+    @Override
+    public void setUnits(String units) {
+        throw new YangParseException(moduleName, line, "Can not set units to " + NAME);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder result = new StringBuilder(UnionTypeBuilder.class.getSimpleName() + "[");
+        result.append(", types=" + types);
+        result.append(", typedefs=" + typedefs);
+        result.append("]");
+        return result.toString();
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnknownSchemaNodeBuilder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnknownSchemaNodeBuilder.java
new file mode 100644 (file)
index 0000000..e7b344b
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.builder.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.Comparators;
+
+public final class UnknownSchemaNodeBuilder extends AbstractSchemaNodeBuilder {
+    private boolean isBuilt;
+    private final UnknownSchemaNodeImpl instance;
+    private boolean addedByUses;
+    private QName nodeType;
+    private String nodeParameter;
+
+    public UnknownSchemaNodeBuilder(final String moduleName, final int line, final QName qname) {
+        super(moduleName, line, qname);
+        instance = new UnknownSchemaNodeImpl(qname);
+    }
+
+    public UnknownSchemaNodeBuilder(UnknownSchemaNodeBuilder b) {
+        super(b.getModuleName(), b.getLine(), b.getQName());
+        instance = new UnknownSchemaNodeImpl(qname);
+        schemaPath = b.getPath();
+        description = b.getDescription();
+        reference = b.getReference();
+        status = b.getStatus();
+        addedByUses = b.isAddedByUses();
+        unknownNodes = b.unknownNodes;
+        addedUnknownNodes.addAll(b.addedUnknownNodes);
+        nodeType = b.getNodeType();
+        nodeParameter = b.getNodeParameter();
+    }
+
+    @Override
+    public UnknownSchemaNode build() {
+        if (!isBuilt) {
+            instance.setPath(schemaPath);
+            instance.setNodeType(nodeType);
+            instance.setNodeParameter(nodeParameter);
+            instance.setDescription(description);
+            instance.setReference(reference);
+            instance.setStatus(status);
+            instance.setAddedByUses(addedByUses);
+
+            // UNKNOWN NODES
+            if (unknownNodes == null) {
+                unknownNodes = new ArrayList<UnknownSchemaNode>();
+                for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
+                    unknownNodes.add(b.build());
+                }
+                Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
+            }
+            instance.setUnknownSchemaNodes(unknownNodes);
+
+            isBuilt = true;
+        }
+
+        return instance;
+    }
+
+    public boolean isAddedByUses() {
+        return addedByUses;
+    }
+
+    public void setAddedByUses(final boolean addedByUses) {
+        this.addedByUses = addedByUses;
+    }
+
+    public QName getNodeType() {
+        return nodeType;
+    }
+
+    public void setNodeType(final QName nodeType) {
+        this.nodeType = nodeType;
+    }
+
+    public String getNodeParameter() {
+        return nodeParameter;
+    }
+
+    public void setNodeParameter(final String nodeParameter) {
+        this.nodeParameter = nodeParameter;
+    }
+
+    private final class UnknownSchemaNodeImpl implements UnknownSchemaNode {
+        private final QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status = Status.CURRENT;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private QName nodeType;
+        private String nodeParameter;
+        private boolean addedByUses;
+
+        private UnknownSchemaNodeImpl(final QName qname) {
+            this.qname = qname;
+        }
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        private void setPath(final SchemaPath path) {
+            this.path = path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        private void setDescription(final String description) {
+            this.description = description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        private void setReference(final String reference) {
+            this.reference = reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        private void setStatus(final Status status) {
+            if (status != null) {
+                this.status = status;
+            }
+        }
+
+        @Override
+        public boolean isAddedByUses() {
+            return addedByUses;
+        }
+
+        private void setAddedByUses(final boolean addedByUses) {
+            this.addedByUses = addedByUses;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
+            if (unknownNodes != null) {
+                this.unknownNodes = unknownNodes;
+            }
+        }
+
+        @Override
+        public QName getNodeType() {
+            return nodeType;
+        }
+
+        private void setNodeType(final QName nodeType) {
+            this.nodeType = nodeType;
+        }
+
+        @Override
+        public String getNodeParameter() {
+            return nodeParameter;
+        }
+
+        private void setNodeParameter(final String nodeParameter) {
+            this.nodeParameter = nodeParameter;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(UnknownSchemaNodeImpl.class.getSimpleName());
+            sb.append("[");
+            sb.append(qname);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UsesNodeBuilderImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UsesNodeBuilderImpl.java
new file mode 100644 (file)
index 0000000..ee07e8b
--- /dev/null
@@ -0,0 +1,335 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.yang.parser.builder.impl;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;\r
+import org.opendaylight.controller.yang.model.api.SchemaNode;\r
+import org.opendaylight.controller.yang.model.api.SchemaPath;\r
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;\r
+import org.opendaylight.controller.yang.model.api.UsesNode;\r
+import org.opendaylight.controller.yang.parser.builder.api.AbstractBuilder;\r
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;\r
+import org.opendaylight.controller.yang.parser.builder.api.Builder;\r
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;\r
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;\r
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;\r
+import org.opendaylight.controller.yang.parser.util.RefineHolder;\r
+import org.opendaylight.controller.yang.parser.util.YangParseException;\r
+\r
+public final class UsesNodeBuilderImpl extends AbstractBuilder implements UsesNodeBuilder {\r
+    private boolean isBuilt;\r
+    private UsesNodeImpl instance;\r
+    private DataNodeContainerBuilder parent;\r
+    private final String groupingName;\r
+    private SchemaPath groupingPath;\r
+    private boolean augmenting;\r
+    private boolean addedByUses;\r
+    private final Set<AugmentationSchemaBuilder> addedAugments = new HashSet<AugmentationSchemaBuilder>();\r
+    private final List<SchemaNodeBuilder> refineBuilders = new ArrayList<SchemaNodeBuilder>();\r
+    private final List<RefineHolder> refines = new ArrayList<RefineHolder>();\r
+\r
+    public UsesNodeBuilderImpl(final String moduleName, final int line, final String groupingName) {\r
+        super(moduleName, line);\r
+        this.groupingName = groupingName;\r
+    }\r
+\r
+    public UsesNodeBuilderImpl(UsesNodeBuilder b) {\r
+        super(b.getModuleName(), b.getLine());\r
+        groupingName = b.getGroupingName();\r
+        parent = b.getParent();\r
+        groupingPath = b.getGroupingPath();\r
+        augmenting = b.isAugmenting();\r
+        addedByUses = b.isAddedByUses();\r
+        addedAugments.addAll(b.getAugmentations());\r
+        refineBuilders.addAll(b.getRefineNodes());\r
+        refines.addAll(b.getRefines());\r
+    }\r
+\r
+    @Override\r
+    public UsesNode build() {\r
+        if (!isBuilt) {\r
+            instance = new UsesNodeImpl(groupingPath);\r
+            instance.setAugmenting(augmenting);\r
+            instance.setAddedByUses(addedByUses);\r
+\r
+            // AUGMENTATIONS\r
+            final Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();\r
+            for (AugmentationSchemaBuilder builder : addedAugments) {\r
+                augments.add(builder.build());\r
+            }\r
+            instance.setAugmentations(augments);\r
+\r
+            // REFINES\r
+            final Map<SchemaPath, SchemaNode> refineNodes = new HashMap<SchemaPath, SchemaNode>();\r
+            for (SchemaNodeBuilder refineBuilder : refineBuilders) {\r
+                SchemaNode refineNode = refineBuilder.build();\r
+                refineNodes.put(refineNode.getPath(), refineNode);\r
+            }\r
+            instance.setRefines(refineNodes);\r
+\r
+            // UNKNOWN NODES\r
+            List<UnknownSchemaNode> unknownNodes = new ArrayList<UnknownSchemaNode>();\r
+            for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {\r
+                unknownNodes.add(b.build());\r
+            }\r
+            instance.setUnknownSchemaNodes(unknownNodes);\r
+\r
+            isBuilt = true;\r
+        }\r
+        return instance;\r
+    }\r
+\r
+    @Override\r
+    public DataNodeContainerBuilder getParent() {\r
+        return parent;\r
+    }\r
+\r
+    @Override\r
+    public void setParent(Builder parent) {\r
+        if (!(parent instanceof DataNodeContainerBuilder)) {\r
+            throw new YangParseException(moduleName, line, "Unresolved parent of uses '" + groupingName + "'.");\r
+        }\r
+        this.parent = (DataNodeContainerBuilder) parent;\r
+    }\r
+\r
+    @Override\r
+    public SchemaPath getGroupingPath() {\r
+        return groupingPath;\r
+    }\r
+\r
+    @Override\r
+    public void setGroupingPath(SchemaPath groupingPath) {\r
+        this.groupingPath = groupingPath;\r
+    }\r
+\r
+    @Override\r
+    public String getGroupingName() {\r
+        return groupingName;\r
+    }\r
+\r
+    @Override\r
+    public Set<AugmentationSchemaBuilder> getAugmentations() {\r
+        return addedAugments;\r
+    }\r
+\r
+    @Override\r
+    public void addAugment(final AugmentationSchemaBuilder augmentBuilder) {\r
+        addedAugments.add(augmentBuilder);\r
+    }\r
+\r
+    @Override\r
+    public boolean isAugmenting() {\r
+        return augmenting;\r
+    }\r
+\r
+    @Override\r
+    public void setAugmenting(final boolean augmenting) {\r
+        this.augmenting = augmenting;\r
+    }\r
+\r
+    @Override\r
+    public boolean isAddedByUses() {\r
+        return addedByUses;\r
+    }\r
+\r
+    @Override\r
+    public void setAddedByUses(final boolean addedByUses) {\r
+        this.addedByUses = addedByUses;\r
+    }\r
+\r
+    @Override\r
+    public List<SchemaNodeBuilder> getRefineNodes() {\r
+        return refineBuilders;\r
+    }\r
+\r
+    @Override\r
+    public void addRefineNode(SchemaNodeBuilder refineNode) {\r
+        refineBuilders.add(refineNode);\r
+    }\r
+\r
+    @Override\r
+    public List<RefineHolder> getRefines() {\r
+        return refines;\r
+    }\r
+\r
+    @Override\r
+    public void addRefine(RefineHolder refine) {\r
+        refines.add(refine);\r
+    }\r
+\r
+    @Override\r
+    public int hashCode() {\r
+        final int prime = 31;\r
+        int result = 1;\r
+        result = prime * result + ((groupingName == null) ? 0 : groupingName.hashCode());\r
+        return result;\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+        if (this == obj)\r
+            return true;\r
+        if (obj == null)\r
+            return false;\r
+        if (getClass() != obj.getClass())\r
+            return false;\r
+        UsesNodeBuilderImpl other = (UsesNodeBuilderImpl) obj;\r
+        if (groupingName == null) {\r
+            if (other.groupingName != null)\r
+                return false;\r
+        } else if (!groupingName.equals(other.groupingName))\r
+            return false;\r
+\r
+        if (parent == null) {\r
+            if (other.parent != null)\r
+                return false;\r
+        } else if (!parent.equals(other.parent))\r
+            return false;\r
+        if (refines == null) {\r
+            if (other.refines != null)\r
+                return false;\r
+        } else if (!refines.equals(other.refines))\r
+            return false;\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        return "uses '" + groupingName + "'";\r
+    }\r
+\r
+    public final class UsesNodeImpl implements UsesNode {\r
+        private final SchemaPath groupingPath;\r
+        private Set<AugmentationSchema> augmentations = Collections.emptySet();\r
+        private boolean augmenting;\r
+        private boolean addedByUses;\r
+        private Map<SchemaPath, SchemaNode> refines = Collections.emptyMap();\r
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();\r
+\r
+        private UsesNodeImpl(final SchemaPath groupingPath) {\r
+            this.groupingPath = groupingPath;\r
+        }\r
+\r
+        @Override\r
+        public SchemaPath getGroupingPath() {\r
+            return groupingPath;\r
+        }\r
+\r
+        @Override\r
+        public Set<AugmentationSchema> getAugmentations() {\r
+            return augmentations;\r
+        }\r
+\r
+        private void setAugmentations(final Set<AugmentationSchema> augmentations) {\r
+            if (augmentations != null) {\r
+                this.augmentations = augmentations;\r
+            }\r
+        }\r
+\r
+        @Override\r
+        public boolean isAugmenting() {\r
+            return augmenting;\r
+        }\r
+\r
+        private void setAugmenting(final boolean augmenting) {\r
+            this.augmenting = augmenting;\r
+        }\r
+\r
+        @Override\r
+        public boolean isAddedByUses() {\r
+            return addedByUses;\r
+        }\r
+\r
+        private void setAddedByUses(final boolean addedByUses) {\r
+            this.addedByUses = addedByUses;\r
+        }\r
+\r
+        @Override\r
+        public Map<SchemaPath, SchemaNode> getRefines() {\r
+            return refines;\r
+        }\r
+\r
+        private void setRefines(Map<SchemaPath, SchemaNode> refines) {\r
+            if (refines != null) {\r
+                this.refines = refines;\r
+            }\r
+        }\r
+\r
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {\r
+            return unknownNodes;\r
+        }\r
+\r
+        private void setUnknownSchemaNodes(List<UnknownSchemaNode> unknownSchemaNodes) {\r
+            if (unknownSchemaNodes != null) {\r
+                this.unknownNodes = unknownSchemaNodes;\r
+            }\r
+        }\r
+\r
+        public UsesNodeBuilder toBuilder() {\r
+            return UsesNodeBuilderImpl.this;\r
+        }\r
+\r
+        @Override\r
+        public int hashCode() {\r
+            final int prime = 31;\r
+            int result = 1;\r
+            result = prime * result + ((groupingPath == null) ? 0 : groupingPath.hashCode());\r
+            result = prime * result + ((augmentations == null) ? 0 : augmentations.hashCode());\r
+            result = prime * result + (augmenting ? 1231 : 1237);\r
+            return result;\r
+        }\r
+\r
+        @Override\r
+        public boolean equals(Object obj) {\r
+            if (this == obj) {\r
+                return true;\r
+            }\r
+            if (obj == null) {\r
+                return false;\r
+            }\r
+            if (getClass() != obj.getClass()) {\r
+                return false;\r
+            }\r
+            final UsesNodeImpl other = (UsesNodeImpl) obj;\r
+            if (groupingPath == null) {\r
+                if (other.groupingPath != null) {\r
+                    return false;\r
+                }\r
+            } else if (!groupingPath.equals(other.groupingPath)) {\r
+                return false;\r
+            }\r
+            if (augmentations == null) {\r
+                if (other.augmentations != null) {\r
+                    return false;\r
+                }\r
+            } else if (!augmentations.equals(other.augmentations)) {\r
+                return false;\r
+            }\r
+            if (augmenting != other.augmenting) {\r
+                return false;\r
+            }\r
+            return true;\r
+        }\r
+\r
+        @Override\r
+        public String toString() {\r
+            StringBuilder sb = new StringBuilder(UsesNodeImpl.class.getSimpleName());\r
+            sb.append("[groupingPath=" + groupingPath + "]");\r
+            return sb.toString();\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/SchemaContextImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/SchemaContextImpl.java
new file mode 100644 (file)
index 0000000..611d2ce
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+import org.opendaylight.controller.yang.model.api.RpcDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+
+final class SchemaContextImpl implements SchemaContext {
+    private final Set<Module> modules;
+
+    SchemaContextImpl(final Set<Module> modules) {
+        this.modules = modules;
+    }
+
+    @Override
+    public Set<DataSchemaNode> getDataDefinitions() {
+        final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
+        for (Module m : modules) {
+            dataDefs.addAll(m.getChildNodes());
+        }
+        return dataDefs;
+    }
+
+    @Override
+    public Set<Module> getModules() {
+        return modules;
+    }
+
+    @Override
+    public Set<NotificationDefinition> getNotifications() {
+        final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
+        for (Module m : modules) {
+            notifications.addAll(m.getNotifications());
+        }
+        return notifications;
+    }
+
+    @Override
+    public Set<RpcDefinition> getOperations() {
+        final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
+        for (Module m : modules) {
+            rpcs.addAll(m.getRpcs());
+        }
+        return rpcs;
+    }
+
+    @Override
+    public Set<ExtensionDefinition> getExtensions() {
+        final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
+        for (Module m : modules) {
+            extensions.addAll(m.getExtensionSchemaNodes());
+        }
+        return extensions;
+    }
+
+    @Override
+    public Module findModuleByName(final String name, final Date revision) {
+        if (name != null) {
+            for (final Module module : modules) {
+                if (revision == null) {
+                    if (module.getName().equals(name)) {
+                        return module;
+                    }
+                } else if (module.getName().equals(name) && module.getRevision().equals(revision)) {
+                    return module;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Module findModuleByNamespace(final URI namespace) {
+        if (namespace != null) {
+            for (final Module module : modules) {
+                if (module.getNamespace().equals(namespace)) {
+                    return module;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangErrorListener.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangErrorListener.java
new file mode 100644 (file)
index 0000000..2725162
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class YangErrorListener extends BaseErrorListener {
+    private final static Logger logger = LoggerFactory.getLogger(YangErrorListener.class);
+
+    @Override
+    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine,
+            String msg, RecognitionException e) {
+        logger.warn("line " + line + ":" + charPositionInLine + " " + msg);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java
new file mode 100644 (file)
index 0000000..065d270
--- /dev/null
@@ -0,0 +1,1413 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.opendaylight.controller.yang.parser.util.ParserUtils.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataNodeContainer;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.SchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.IdentityrefType;
+import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.DeviationBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl.UsesNodeImpl;
+import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
+import org.opendaylight.controller.yang.parser.util.RefineHolder;
+import org.opendaylight.controller.yang.parser.util.RefineUtils;
+import org.opendaylight.controller.yang.parser.util.TypeConstraints;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public final class YangParserImpl implements YangModelParser {
+    private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
+
+    @Override
+    public Set<Module> parseYangModels(final List<File> yangFiles) {
+        return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
+    }
+
+    @Override
+    public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
+        if (yangFiles != null) {
+            final Map<InputStream, File> inputStreams = Maps.newHashMap();
+
+            for (final File yangFile : yangFiles) {
+                try {
+                    inputStreams.put(new FileInputStream(yangFile), yangFile);
+                } catch (FileNotFoundException e) {
+                    LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
+                }
+            }
+
+            Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
+
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
+                    Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
+
+            for (InputStream is : inputStreams.keySet()) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    LOG.debug("Failed to close stream.");
+                }
+            }
+
+            return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
+        }
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
+        return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
+    }
+
+    @Override
+    public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
+        if (yangModelStreams != null) {
+            Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
+                    yangModelStreams, builderToStreamMap, context);
+            return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
+        }
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
+        if (yangFiles != null) {
+            final Map<InputStream, File> inputStreams = Maps.newHashMap();
+
+            for (final File yangFile : yangFiles) {
+                try {
+                    inputStreams.put(new FileInputStream(yangFile), yangFile);
+                } catch (FileNotFoundException e) {
+                    LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
+                }
+            }
+
+            Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
+                    Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
+
+            for (InputStream is : inputStreams.keySet()) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    LOG.debug("Failed to close stream.");
+                }
+            }
+
+            Map<File, Module> retVal = Maps.newLinkedHashMap();
+            Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
+
+            for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
+                retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
+                        builderToModule.getValue());
+            }
+
+            return retVal;
+        }
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
+        Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
+
+        final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
+                builderToStreamMap);
+        Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
+        Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
+
+        for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
+            retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
+        }
+        return retVal;
+    }
+
+    @Override
+    public SchemaContext resolveSchemaContext(final Set<Module> modules) {
+        return new SchemaContextImpl(modules);
+    }
+
+    private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
+            Map<ModuleBuilder, InputStream> streamToBuilderMap) {
+
+        final ParseTreeWalker walker = new ParseTreeWalker();
+        final List<ParseTree> trees = parseStreams(inputStreams);
+        final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
+
+        // validate yang
+        new YangModelBasicValidator(walker).validate(trees);
+
+        YangParserListenerImpl yangModelParser = null;
+        for (int i = 0; i < trees.size(); i++) {
+            yangModelParser = new YangParserListenerImpl();
+            walker.walk(yangModelParser, trees.get(i));
+            ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
+
+            // We expect the order of trees and streams has to be the same
+            streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
+            builders[i] = moduleBuilder;
+        }
+        return builders;
+    }
+
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
+            Map<ModuleBuilder, InputStream> streamToBuilderMap) {
+        return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
+    }
+
+    private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
+            final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
+            final SchemaContext context) {
+        final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
+
+        // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
+        // of items stored in map.
+        final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
+
+        // module dependency graph sorted
+        List<ModuleBuilder> sorted = null;
+        if (context == null) {
+            sorted = ModuleDependencySort.sort(builders);
+        } else {
+            sorted = ModuleDependencySort.sortWithContext(context, builders);
+        }
+
+        for (final ModuleBuilder builder : sorted) {
+            if (builder == null) {
+                continue;
+            }
+            final String builderName = builder.getName();
+            Date builderRevision = builder.getRevision();
+            if (builderRevision == null) {
+                builderRevision = new Date(0L);
+            }
+            TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
+            if (builderByRevision == null) {
+                builderByRevision = new TreeMap<Date, ModuleBuilder>();
+            }
+            builderByRevision.put(builderRevision, builder);
+            modules.put(builderName, builderByRevision);
+        }
+        return modules;
+    }
+
+    private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
+        final List<ParseTree> trees = new ArrayList<ParseTree>();
+        for (InputStream yangStream : yangStreams) {
+            trees.add(parseStream(yangStream));
+        }
+        return trees;
+    }
+
+    private ParseTree parseStream(final InputStream yangStream) {
+        ParseTree result = null;
+        try {
+            final ANTLRInputStream input = new ANTLRInputStream(yangStream);
+            final YangLexer lexer = new YangLexer(input);
+            final CommonTokenStream tokens = new CommonTokenStream(lexer);
+            final YangParser parser = new YangParser(tokens);
+            parser.removeErrorListeners();
+            parser.addErrorListener(new YangErrorListener());
+
+            result = parser.yang();
+        } catch (IOException e) {
+            LOG.warn("Exception while reading yang file: " + yangStream, e);
+        }
+        return result;
+    }
+
+    private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        // fix unresolved nodes
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                fixUnresolvedNodes(modules, moduleBuilder);
+            }
+        }
+        resolveAugments(modules);
+        resolveDeviations(modules);
+
+        // build
+        // LinkedHashMap MUST be used otherwise the values will not maintain
+        // order!
+        // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
+        final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                final Module module = moduleBuilder.build();
+                modulesByRevision.put(childEntry.getKey(), module);
+                result.put(moduleBuilder, module);
+            }
+        }
+        return result;
+    }
+
+    private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            SchemaContext context) {
+        // fix unresolved nodes
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
+            }
+        }
+        resolveAugmentsWithContext(modules, context);
+        resolveDeviationsWithContext(modules, context);
+
+        // build
+        // LinkedHashMap MUST be used otherwise the values will not maintain
+        // order!
+        // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
+        final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                final Module module = moduleBuilder.build();
+                modulesByRevision.put(childEntry.getKey(), module);
+                result.put(moduleBuilder, module);
+            }
+        }
+        return result;
+    }
+
+    private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
+        resolveDirtyNodes(modules, builder);
+        resolveIdentities(modules, builder);
+        resolveUsesRefine(modules, builder);
+        resolveUnknownNodes(modules, builder);
+    }
+
+    private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder, final SchemaContext context) {
+        resolveDirtyNodesWithContext(modules, builder, context);
+        resolveIdentitiesWithContext(modules, builder, context);
+        resolveUsesRefineWithContext(modules, builder, context);
+        resolveUnknownNodesWithContext(modules, builder, context);
+    }
+
+    /**
+     * Search for dirty nodes (node which contains UnknownType) and resolve
+     * unknown types.
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     */
+    private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
+        if (!dirtyNodes.isEmpty()) {
+            for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
+                if (nodeToResolve instanceof UnionTypeBuilder) {
+                    // special handling for union types
+                    resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
+                } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
+                    // special handling for identityref types
+                    IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
+                    nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
+                } else {
+                    resolveType(nodeToResolve, modules, module);
+                }
+            }
+        }
+    }
+
+    private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, SchemaContext context) {
+        final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
+        if (!dirtyNodes.isEmpty()) {
+            for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
+                if (nodeToResolve instanceof UnionTypeBuilder) {
+                    // special handling for union types
+                    resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
+                } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
+                    // special handling for identityref types
+                    IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
+                    nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
+                } else {
+                    resolveTypeWithContext(nodeToResolve, modules, module, context);
+                }
+            }
+        }
+    }
+
+    /**
+     * Resolve unknown type of node. It is assumed that type of node is either
+     * UnknownType or ExtendedType with UnknownType as base type.
+     *
+     * @param nodeToResolve
+     *            node with type to resolve
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     */
+    private void resolveType(final TypeAwareBuilder nodeToResolve,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        TypeDefinitionBuilder resolvedType = null;
+        final int line = nodeToResolve.getLine();
+        final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
+        final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
+        final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
+                line);
+
+        final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
+                unknownTypeQName.getLocalName(), module.getName(), line);
+
+        if (nodeToResolveType instanceof ExtendedType) {
+            final ExtendedType extType = (ExtendedType) nodeToResolveType;
+            final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
+                    modules, module, nodeToResolve.getLine());
+            resolvedType = newType;
+        } else {
+            resolvedType = targetTypeBuilder;
+        }
+
+        // validate constraints
+        final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
+                new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
+        constraints.validateConstraints();
+
+        nodeToResolve.setTypedef(resolvedType);
+    }
+
+    /**
+     * Resolve unknown type of node. It is assumed that type of node is either
+     * UnknownType or ExtendedType with UnknownType as base type.
+     *
+     * @param nodeToResolve
+     *            node with type to resolve
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @param context
+     *            SchemaContext containing already resolved modules
+     */
+    private void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
+            final SchemaContext context) {
+        TypeDefinitionBuilder resolvedType = null;
+        final int line = nodeToResolve.getLine();
+        final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
+        final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
+        final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
+                unknownTypeQName.getPrefix(), line);
+
+        if (dependentModuleBuilder == null) {
+            final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
+            final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
+            final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
+
+            if (nodeToResolveType instanceof ExtendedType) {
+                final ExtendedType extType = (ExtendedType) nodeToResolveType;
+                final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
+                        nodeToResolve.getLine());
+
+                nodeToResolve.setTypedef(newType);
+            } else {
+                if (nodeToResolve instanceof TypeDefinitionBuilder) {
+                    TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
+                    TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
+                            new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
+                    tdb.setLengths(tc.getLength());
+                    tdb.setPatterns(tc.getPatterns());
+                    tdb.setRanges(tc.getRange());
+                    tdb.setFractionDigits(tc.getFractionDigits());
+                }
+                nodeToResolve.setType(type);
+            }
+
+        } else {
+            final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
+                    dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
+
+            if (nodeToResolveType instanceof ExtendedType) {
+                final ExtendedType extType = (ExtendedType) nodeToResolveType;
+                final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
+                        modules, module, nodeToResolve.getLine());
+                resolvedType = newType;
+            } else {
+                resolvedType = targetTypeBuilder;
+            }
+
+            // validate constraints
+            final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
+                    module.getName(), nodeToResolve.getLine()), modules, module, context);
+            constraints.validateConstraints();
+
+            nodeToResolve.setTypedef(resolvedType);
+        }
+    }
+
+    private void resolveTypeUnion(final UnionTypeBuilder union,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
+
+        final List<TypeDefinition<?>> unionTypes = union.getTypes();
+        final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
+        for (TypeDefinition<?> unionType : unionTypes) {
+            if (unionType instanceof UnknownType) {
+                final UnknownType ut = (UnknownType) unionType;
+                final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
+                        .getPrefix(), union.getLine());
+                final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
+                        .getQName().getLocalName(), builder.getName(), union.getLine());
+                union.setTypedef(resolvedType);
+                toRemove.add(ut);
+            } else if (unionType instanceof ExtendedType) {
+                final ExtendedType extType = (ExtendedType) unionType;
+                final TypeDefinition<?> extTypeBase = extType.getBaseType();
+                if (extTypeBase instanceof UnknownType) {
+                    final UnknownType ut = (UnknownType) extTypeBase;
+                    final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
+                            .getPrefix(), union.getLine());
+                    final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
+                            ut.getQName().getLocalName(), builder.getName(), union.getLine());
+
+                    final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
+                            extType, modules, builder, union.getLine());
+
+                    union.setTypedef(newType);
+                    toRemove.add(extType);
+                }
+            }
+        }
+        unionTypes.removeAll(toRemove);
+    }
+
+    private void resolveTypeUnionWithContext(final UnionTypeBuilder union,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
+            final SchemaContext context) {
+
+        final List<TypeDefinition<?>> unionTypes = union.getTypes();
+        final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
+        for (TypeDefinition<?> unionType : unionTypes) {
+            if (unionType instanceof UnknownType) {
+                final UnknownType ut = (UnknownType) unionType;
+                final QName utQName = ut.getQName();
+                final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
+                        utQName.getPrefix(), union.getLine());
+
+                if (dependentModuleBuilder == null) {
+                    Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
+                            union.getLine());
+                    Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
+                    TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
+                    union.setType(type);
+                    toRemove.add(ut);
+                } else {
+                    final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
+                            utQName.getLocalName(), builder.getName(), union.getLine());
+                    union.setTypedef(resolvedType);
+                    toRemove.add(ut);
+                }
+
+            } else if (unionType instanceof ExtendedType) {
+                final ExtendedType extType = (ExtendedType) unionType;
+                TypeDefinition<?> extTypeBase = extType.getBaseType();
+                if (extTypeBase instanceof UnknownType) {
+                    final UnknownType ut = (UnknownType) extTypeBase;
+                    final QName utQName = ut.getQName();
+                    final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
+                            utQName.getPrefix(), union.getLine());
+
+                    if (dependentModuleBuilder == null) {
+                        final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
+                                union.getLine());
+                        Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
+                        TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
+                        final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
+
+                        union.setTypedef(newType);
+                        toRemove.add(extType);
+                    } else {
+                        final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
+                                dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
+
+                        final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
+                                extType, modules, builder, union.getLine());
+
+                        union.setTypedef(newType);
+                        toRemove.add(extType);
+                    }
+                }
+            }
+        }
+        unionTypes.removeAll(toRemove);
+    }
+
+    /**
+     * Go through all augment definitions and resolve them. It is expected that
+     * modules are already sorted by their dependencies. This method also finds
+     * augment target node and add child nodes to it.
+     *
+     * @param modules
+     *            all available modules
+     */
+    private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
+        final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
+                allModulesList.add(inner.getValue());
+                allModulesSet.add(inner.getValue());
+            }
+        }
+
+        for (int i = 0; i < allModulesList.size(); i++) {
+            final ModuleBuilder module = allModulesList.get(i);
+            // try to resolve augments in module
+            resolveAugment(modules, module);
+            // while all augments are not resolved
+            final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
+            while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
+                ModuleBuilder nextModule = null;
+                // try resolve other module augments
+                try {
+                    nextModule = allModulesIterator.next();
+                    resolveAugment(modules, nextModule);
+                } catch (NoSuchElementException e) {
+                    throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
+                }
+                // then try to resolve first module again
+                resolveAugment(modules, module);
+            }
+        }
+    }
+
+    /**
+     * Tries to resolve augments in given module. If augment target node is not
+     * found, do nothing.
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     */
+    private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        if (module.getAugmentsResolved() < module.getAllAugments().size()) {
+            for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
+
+                if (!augmentBuilder.isResolved()) {
+                    final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
+                    final List<QName> path = augmentTargetSchemaPath.getPath();
+
+                    final QName qname = path.get(0);
+                    String prefix = qname.getPrefix();
+                    if (prefix == null) {
+                        prefix = module.getPrefix();
+                    }
+
+                    final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
+                            augmentBuilder.getLine());
+                    processAugmentation(augmentBuilder, path, module, dependentModule);
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Go through all augment definitions and resolve them. This method works in
+     * same way as {@link #resolveAugments(Map)} except that if target node is
+     * not found in loaded modules, it search for target node in given context.
+     *
+     * @param modules
+     *            all loaded modules
+     * @param context
+     *            SchemaContext containing already resolved modules
+     */
+    private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final SchemaContext context) {
+        final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
+        final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
+                allModulesList.add(inner.getValue());
+                allModulesSet.add(inner.getValue());
+            }
+        }
+
+        for (int i = 0; i < allModulesList.size(); i++) {
+            final ModuleBuilder module = allModulesList.get(i);
+            // try to resolve augments in module
+            resolveAugmentWithContext(modules, module, context);
+            // while all augments are not resolved
+            final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
+            while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
+                ModuleBuilder nextModule = null;
+                // try resolve other module augments
+                try {
+                    nextModule = allModulesIterator.next();
+                    resolveAugmentWithContext(modules, nextModule, context);
+                } catch (NoSuchElementException e) {
+                    throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
+                }
+                // then try to resolve first module again
+                resolveAugmentWithContext(modules, module, context);
+            }
+        }
+    }
+
+    /**
+     * Tries to resolve augments in given module. If augment target node is not
+     * found, do nothing.
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     */
+    private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final SchemaContext context) {
+        if (module.getAugmentsResolved() < module.getAllAugments().size()) {
+
+            for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
+                final int line = augmentBuilder.getLine();
+
+                if (!augmentBuilder.isResolved()) {
+                    final List<QName> path = augmentBuilder.getTargetPath().getPath();
+                    final QName qname = path.get(0);
+                    String prefix = qname.getPrefix();
+                    if (prefix == null) {
+                        prefix = module.getPrefix();
+                    }
+
+                    // try to find augment target module in loaded modules...
+                    final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
+                            line);
+                    if (dependentModuleBuilder == null) {
+                        // perform augmentation on module from context and
+                        // continue to next augment
+                        processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
+                        continue;
+                    } else {
+                        processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
+                    }
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Go through identity statements defined in current module and resolve
+     * their 'base' statement if present.
+     *
+     * @param modules
+     *            all modules
+     * @param module
+     *            module being resolved
+     */
+    private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
+        for (IdentitySchemaNodeBuilder identity : identities) {
+            final String baseIdentityName = identity.getBaseIdentityName();
+            if (baseIdentityName != null) {
+                String baseIdentityPrefix = null;
+                String baseIdentityLocalName = null;
+                if (baseIdentityName.contains(":")) {
+                    final String[] splitted = baseIdentityName.split(":");
+                    baseIdentityPrefix = splitted[0];
+                    baseIdentityLocalName = splitted[1];
+                } else {
+                    baseIdentityPrefix = module.getPrefix();
+                    baseIdentityLocalName = baseIdentityName;
+                }
+                final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
+                        identity.getLine());
+
+                final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
+                for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
+                    if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
+                        identity.setBaseIdentity(idBuilder);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Go through identity statements defined in current module and resolve
+     * their 'base' statement. Method tries to find base identity in given
+     * modules. If base identity is not found, method will search it in context.
+     *
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @param context
+     *            SchemaContext containing already resolved modules
+     */
+    private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final SchemaContext context) {
+        final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
+        for (IdentitySchemaNodeBuilder identity : identities) {
+            final String baseIdentityName = identity.getBaseIdentityName();
+            if (baseIdentityName != null) {
+                String baseIdentityPrefix = null;
+                String baseIdentityLocalName = null;
+                if (baseIdentityName.contains(":")) {
+                    final String[] splitted = baseIdentityName.split(":");
+                    baseIdentityPrefix = splitted[0];
+                    baseIdentityLocalName = splitted[1];
+                } else {
+                    baseIdentityPrefix = module.getPrefix();
+                    baseIdentityLocalName = baseIdentityName;
+                }
+                final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
+                        baseIdentityPrefix, identity.getLine());
+
+                if (dependentModuleBuilder == null) {
+                    final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
+                            identity.getLine());
+                    final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
+                    for (IdentitySchemaNode idNode : dependentModuleIdentities) {
+                        if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
+                            identity.setBaseIdentity(idNode);
+                        }
+                    }
+                } else {
+                    final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
+                            .getIdentities();
+                    for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
+                        if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
+                            identity.setBaseIdentity(idBuilder);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Go through uses statements defined in current module and resolve their
+     * refine statements.
+     *
+     * @param modules
+     *            all modules
+     * @param module
+     *            module being resolved
+     */
+    private void resolveUsesRefine(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
+        for (UsesNodeBuilder usesNode : allModuleUses) {
+            // refine
+            final int line = usesNode.getLine();
+            final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
+            usesNode.setGroupingPath(targetGrouping.getPath());
+            for (RefineHolder refine : usesNode.getRefines()) {
+                final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(targetGrouping,
+                        refine, module.getName());
+                if (nodeToRefine instanceof GroupingMember) {
+                    ((GroupingMember) nodeToRefine).setAddedByUses(true);
+                }
+                RefineUtils.performRefine(nodeToRefine, refine, line);
+                usesNode.addRefineNode(nodeToRefine);
+            }
+
+            // child nodes
+            processUsesNode(module, usesNode, targetGrouping);
+        }
+    }
+
+    /**
+     * Tries to search target grouping in given modules and resolve refine
+     * nodes. If grouping is not found in modules, method tries to find it in
+     * modules from context.
+     *
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @param context
+     *            SchemaContext containing already resolved modules
+     */
+    private void resolveUsesRefineWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final SchemaContext context) {
+        final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
+        for (UsesNodeBuilder usesNode : moduleUses) {
+            final int line = usesNode.getLine();
+
+            final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
+            if (targetGroupingBuilder == null) {
+                final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
+                usesNode.setGroupingPath(targetGrouping.getPath());
+                for (RefineHolder refine : usesNode.getRefines()) {
+                    final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingDefinition(
+                            targetGrouping, refine);
+                    if (nodeToRefine instanceof GroupingMember) {
+                        ((GroupingMember) nodeToRefine).setAddedByUses(true);
+                    }
+                    RefineUtils.performRefine(nodeToRefine, refine, line);
+                    usesNode.addRefineNode(nodeToRefine);
+                }
+
+                processUsesNode(usesNode, targetGrouping);
+            } else {
+                usesNode.setGroupingPath(targetGroupingBuilder.getPath());
+                for (RefineHolder refine : usesNode.getRefines()) {
+                    final SchemaNodeBuilder nodeToRefine = RefineUtils.getRefineNodeFromGroupingBuilder(
+                            targetGroupingBuilder, refine, module.getName());
+                    if (nodeToRefine instanceof GroupingMember) {
+                        ((GroupingMember) nodeToRefine).setAddedByUses(true);
+                    }
+                    RefineUtils.performRefine(nodeToRefine, refine, line);
+                    usesNode.addRefineNode(nodeToRefine);
+                }
+
+                processUsesNode(module, usesNode, targetGroupingBuilder);
+            }
+        }
+    }
+
+    /**
+     * Search given modules for grouping by name defined in uses node.
+     *
+     * @param usesBuilder
+     *            builder of uses statement
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @return grouping with given name if found, null otherwise
+     */
+    private GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
+            final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        final int line = usesBuilder.getLine();
+        final String groupingString = usesBuilder.getGroupingName();
+        String groupingPrefix;
+        String groupingName;
+
+        if (groupingString.contains(":")) {
+            String[] splitted = groupingString.split(":");
+            if (splitted.length != 2 || groupingString.contains("/")) {
+                throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
+            }
+            groupingPrefix = splitted[0];
+            groupingName = splitted[1];
+        } else {
+            groupingPrefix = module.getPrefix();
+            groupingName = groupingString;
+        }
+
+        ModuleBuilder dependentModule = null;
+        if (groupingPrefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
+        }
+
+        if (dependentModule == null) {
+            return null;
+        }
+
+        GroupingBuilder result = null;
+        Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
+        result = findGroupingBuilder(groupings, groupingName);
+        if (result != null) {
+            return result;
+        }
+
+        Builder parent = usesBuilder.getParent();
+
+        while (parent != null) {
+            if (parent instanceof DataNodeContainerBuilder) {
+                groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
+            } else if (parent instanceof RpcDefinitionBuilder) {
+                groupings = ((RpcDefinitionBuilder) parent).getGroupings();
+            }
+            result = findGroupingBuilder(groupings, groupingName);
+            if (result == null) {
+                parent = parent.getParent();
+            } else {
+                break;
+            }
+        }
+
+        if (result == null) {
+            throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
+                    + "' not found.");
+        }
+        return result;
+    }
+
+    /**
+     * Search context for grouping by name defined in uses node.
+     *
+     * @param usesBuilder
+     *            builder of uses statement
+     * @param module
+     *            current module
+     * @param context
+     *            SchemaContext containing already resolved modules
+     * @return grouping with given name if found, null otherwise
+     */
+    private GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
+            final ModuleBuilder module, final SchemaContext context) {
+        final int line = usesBuilder.getLine();
+        String groupingString = usesBuilder.getGroupingName();
+        String groupingPrefix;
+        String groupingName;
+
+        if (groupingString.contains(":")) {
+            String[] splitted = groupingString.split(":");
+            if (splitted.length != 2 || groupingString.contains("/")) {
+                throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
+            }
+            groupingPrefix = splitted[0];
+            groupingName = splitted[1];
+        } else {
+            groupingPrefix = module.getPrefix();
+            groupingName = groupingString;
+        }
+
+        Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
+        return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
+    }
+
+    /**
+     * Add nodes defined in target grouping to current context. Refinement has
+     * to be already performed.
+     *
+     * @param module current module
+     * @param usesNode
+     * @param targetGrouping
+     */
+    private void processUsesNode(final ModuleBuilder module, final UsesNodeBuilder usesNode, final GroupingBuilder targetGrouping) {
+        List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
+        DataNodeContainerBuilder parent = usesNode.getParent();
+        URI namespace = null;
+        Date revision = null;
+        String prefix = null;
+        if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
+            namespace = module.getNamespace();
+            revision = module.getRevision();
+            prefix = module.getPrefix();
+        } else {
+            QName parentQName = parent.getQName();
+            namespace = parentQName.getNamespace();
+            revision = parentQName.getRevision();
+            prefix = parentQName.getPrefix();
+        }
+        SchemaPath parentPath = parent.getPath();
+        for (DataSchemaNodeBuilder child : targetGrouping.getChildNodeBuilders()) {
+            if (child != null) {
+                // if node is refined, take it from refined nodes and continue
+                SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
+                if (refined != null) {
+                    refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName(), namespace,
+                            revision, prefix));
+                    parent.addChildNode((DataSchemaNodeBuilder) refined);
+                    continue;
+                }
+
+                DataSchemaNodeBuilder newChild = null;
+                if (child instanceof AnyXmlBuilder) {
+                    newChild = new AnyXmlBuilder((AnyXmlBuilder) child);
+                } else if (child instanceof ChoiceBuilder) {
+                    newChild = new ChoiceBuilder((ChoiceBuilder) child);
+                } else if (child instanceof ContainerSchemaNodeBuilder) {
+                    newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child);
+                } else if (child instanceof LeafListSchemaNodeBuilder) {
+                    newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child);
+                } else if (child instanceof LeafSchemaNodeBuilder) {
+                    newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child);
+                } else if (child instanceof ListSchemaNodeBuilder) {
+                    newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child);
+                }
+
+                if (newChild == null) {
+                    throw new YangParseException(usesNode.getModuleName(), usesNode.getLine(),
+                            "Unknown member of target grouping while resolving uses node.");
+                }
+
+                if (newChild instanceof GroupingMember) {
+                    ((GroupingMember) newChild).setAddedByUses(true);
+                }
+
+                newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName(), namespace, revision,
+                        prefix));
+                parent.addChildNode(newChild);
+            }
+        }
+        for (GroupingBuilder g : targetGrouping.getGroupingBuilders()) {
+            GroupingBuilder newGrouping = new GroupingBuilderImpl(g);
+            newGrouping.setAddedByUses(true);
+            newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName(), namespace,
+                    revision, prefix));
+            parent.addGrouping(newGrouping);
+        }
+        for (TypeDefinitionBuilder td : targetGrouping.getTypeDefinitionBuilders()) {
+            TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td);
+            newType.setAddedByUses(true);
+            newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName(), namespace, revision, prefix));
+            parent.addTypedef(newType);
+        }
+        for (UsesNodeBuilder un : targetGrouping.getUses()) {
+            UsesNodeBuilder newUses = new UsesNodeBuilderImpl(un);
+            newUses.setAddedByUses(true);
+            // uses has not path
+            parent.addUsesNode(newUses);
+        }
+        for (UnknownSchemaNodeBuilder un : targetGrouping.getUnknownNodeBuilders()) {
+            UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un);
+            newUn.setAddedByUses(true);
+            newUn.setPath(createSchemaPath(parentPath, un.getQName().getLocalName(), namespace, revision, prefix));
+            parent.addUnknownNodeBuilder(newUn);
+        }
+    }
+
+    private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
+        final String moduleName = usesNode.getModuleName();
+        final int line = usesNode.getLine();
+        List<SchemaNodeBuilder> refineNodes = usesNode.getRefineNodes();
+        DataNodeContainerBuilder parent = usesNode.getParent();
+        URI namespace = null;
+        Date revision = null;
+        String prefix = null;
+        if (parent instanceof ModuleBuilder) {
+            ModuleBuilder module = (ModuleBuilder) parent;
+            namespace = module.getNamespace();
+            revision = module.getRevision();
+            prefix = module.getPrefix();
+        } else {
+            QName parentQName = parent.getQName();
+            namespace = parentQName.getNamespace();
+            revision = parentQName.getRevision();
+            prefix = parentQName.getPrefix();
+        }
+        SchemaPath parentPath = parent.getPath();
+        for (DataSchemaNode child : targetGrouping.getChildNodes()) {
+            if (child != null) {
+                // if node is refined, take it from refined nodes and continue
+                SchemaNodeBuilder refined = getRefined(child.getQName(), refineNodes);
+                if (refined != null) {
+                    refined.setPath(createSchemaPath(parentPath, refined.getQName().getLocalName(), namespace,
+                            revision, prefix));
+                    parent.addChildNode((DataSchemaNodeBuilder) refined);
+                    continue;
+                }
+
+                DataSchemaNodeBuilder newChild = null;
+                if (child instanceof AnyXmlSchemaNode) {
+                    newChild = createAnyXml((AnyXmlSchemaNode) child, moduleName, line);
+                } else if (child instanceof ChoiceNode) {
+                    newChild = createChoice((ChoiceNode) child, moduleName, line);
+                } else if (child instanceof ContainerSchemaNode) {
+                    newChild = createContainer((ContainerSchemaNode) child, moduleName, line);
+                } else if (child instanceof LeafListSchemaNode) {
+                    newChild = createLeafList((LeafListSchemaNode) child, moduleName, line);
+                } else if (child instanceof LeafSchemaNode) {
+                    newChild = createLeafBuilder((LeafSchemaNode) child, moduleName, line);
+                } else if (child instanceof ListSchemaNode) {
+                    newChild = createList((ListSchemaNode) child, moduleName, line);
+                }
+
+                if (newChild == null) {
+                    throw new YangParseException(moduleName, line,
+                            "Unknown member of target grouping while resolving uses node.");
+                }
+
+                if (newChild instanceof GroupingMember) {
+                    ((GroupingMember) newChild).setAddedByUses(true);
+                }
+                newChild.setPath(createSchemaPath(parentPath, newChild.getQName().getLocalName(), namespace, revision,
+                        prefix));
+                parent.addChildNode(newChild);
+            }
+        }
+        for (GroupingDefinition g : targetGrouping.getGroupings()) {
+            GroupingBuilder newGrouping = createGrouping(g, moduleName, line);
+            newGrouping.setAddedByUses(true);
+            newGrouping.setPath(createSchemaPath(parentPath, newGrouping.getQName().getLocalName(), namespace,
+                    revision, prefix));
+            parent.addGrouping(newGrouping);
+        }
+        for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
+            TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, moduleName, line);
+            newType.setAddedByUses(true);
+            newType.setPath(createSchemaPath(parentPath, newType.getQName().getLocalName(), namespace, revision, prefix));
+            parent.addTypedef(newType);
+        }
+        for (UsesNode un : targetGrouping.getUses()) {
+            if (un instanceof UsesNodeImpl) {
+                UsesNodeBuilder newUses = new UsesNodeBuilderImpl(((UsesNodeImpl) un).toBuilder());
+                newUses.setAddedByUses(true);
+                // uses has not path
+                parent.addUsesNode(newUses);
+            }
+        }
+        for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
+            UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, moduleName, line);
+            newNode.setAddedByUses(true);
+            newNode.setPath(createSchemaPath(parentPath, un.getQName().getLocalName(), namespace, revision, prefix));
+            parent.addUnknownNodeBuilder(newNode);
+        }
+    }
+
+    private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
+            final IdentityrefTypeBuilder idref) {
+        QName result = null;
+        String baseString = idref.getBaseString();
+        if (baseString.contains(":")) {
+            String[] splittedBase = baseString.split(":");
+            if (splittedBase.length > 2) {
+                throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
+                        + baseString);
+            }
+            String prefix = splittedBase[0];
+            String name = splittedBase[1];
+            ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
+            result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
+        } else {
+            result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
+        }
+        return result;
+    }
+
+    private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
+            QName nodeType = usnb.getNodeType();
+            if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
+                try {
+                    ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
+                            usnb.getLine());
+                    QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
+                            nodeType.getPrefix(), nodeType.getLocalName());
+                    usnb.setNodeType(newNodeType);
+                } catch (YangParseException e) {
+                    LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
+                }
+            }
+        }
+    }
+
+    private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final SchemaContext context) {
+        for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
+            QName nodeType = unknownNodeBuilder.getNodeType();
+            if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
+                try {
+                    ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
+                            nodeType.getPrefix(), unknownNodeBuilder.getLine());
+
+                    QName newNodeType = null;
+                    if (dependentModuleBuilder == null) {
+                        Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
+                                unknownNodeBuilder.getLine());
+                        newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
+                                nodeType.getPrefix(), nodeType.getLocalName());
+                    } else {
+                        newNodeType = new QName(dependentModuleBuilder.getNamespace(),
+                                dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
+                    }
+
+                    unknownNodeBuilder.setNodeType(newNodeType);
+                } catch (YangParseException e) {
+                    LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
+                            + nodeType);
+                }
+            }
+        }
+    }
+
+    private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
+                ModuleBuilder b = inner.getValue();
+                resolveDeviation(modules, b);
+            }
+        }
+    }
+
+    private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
+        for (DeviationBuilder dev : module.getDeviations()) {
+            int line = dev.getLine();
+            SchemaPath targetPath = dev.getTargetPath();
+            List<QName> path = targetPath.getPath();
+            QName q0 = path.get(0);
+            String prefix = q0.getPrefix();
+            if (prefix == null) {
+                prefix = module.getPrefix();
+            }
+
+            ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
+            processDeviation(dev, dependentModuleBuilder, path, module);
+        }
+    }
+
+    private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final SchemaContext context) {
+        for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
+                ModuleBuilder b = inner.getValue();
+                resolveDeviationWithContext(modules, b, context);
+            }
+        }
+    }
+
+    private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final SchemaContext context) {
+        for (DeviationBuilder dev : module.getDeviations()) {
+            int line = dev.getLine();
+            SchemaPath targetPath = dev.getTargetPath();
+            List<QName> path = targetPath.getPath();
+            QName q0 = path.get(0);
+            String prefix = q0.getPrefix();
+            if (prefix == null) {
+                prefix = module.getPrefix();
+            }
+            String name = null;
+
+            ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
+            if (dependentModuleBuilder == null) {
+                Module dependentModule = findModuleFromContext(context, module, prefix, line);
+                Object currentParent = dependentModule;
+
+                for (int i = 0; i < path.size(); i++) {
+                    if (currentParent == null) {
+                        throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+                    }
+                    QName q = path.get(i);
+                    name = q.getLocalName();
+                    if (currentParent instanceof DataNodeContainer) {
+                        currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
+                    }
+                }
+
+                if (currentParent == null) {
+                    throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+                }
+                if (currentParent instanceof SchemaNode) {
+                    dev.setTargetPath(((SchemaNode) currentParent).getPath());
+                }
+
+            } else {
+                processDeviation(dev, dependentModuleBuilder, path, module);
+            }
+        }
+    }
+
+    /**
+     * Correct deviation target path in deviation builder.
+     *
+     * @param dev
+     *            deviation
+     * @param dependentModuleBuilder
+     *            module containing deviation target
+     * @param path
+     *            current deviation target path
+     * @param module
+     *            current module
+     */
+    private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
+            final List<QName> path, final ModuleBuilder module) {
+        final int line = dev.getLine();
+        Builder currentParent = dependentModuleBuilder;
+
+        for (int i = 0; i < path.size(); i++) {
+            if (currentParent == null) {
+                throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+            }
+            QName q = path.get(i);
+            String name = q.getLocalName();
+            if (currentParent instanceof DataNodeContainerBuilder) {
+                currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
+            }
+        }
+
+        if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
+            throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
+        }
+        dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserListenerImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserListenerImpl.java
new file mode 100644 (file)
index 0000000..b6944d1
--- /dev/null
@@ -0,0 +1,958 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.opendaylight.controller.yang.parser.util.ParserListenerUtils.*;
+
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Stack;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.*;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Contact_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_not_supported_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_replace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Organization_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.util.YangTypesConverter;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.DeviationBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ExtensionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.FeatureBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.util.RefineHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class YangParserListenerImpl extends YangParserBaseListener {
+    private static final Logger logger = LoggerFactory.getLogger(YangParserListenerImpl.class);
+
+    private ModuleBuilder moduleBuilder;
+    private String moduleName;
+    private URI namespace;
+    private String yangModelPrefix;
+    private Date revision = new Date(0L);
+
+    public final static DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+    private final Stack<String> actualPath = new Stack<String>();
+
+    @Override
+    public void enterModule_stmt(YangParser.Module_stmtContext ctx) {
+        moduleName = stringFromNode(ctx);
+        logger.debug("enter module " + moduleName);
+        actualPath.push(moduleName);
+        moduleBuilder = new ModuleBuilder(moduleName);
+
+        String description = null;
+        String reference = null;
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else {
+                if (description != null && reference != null) {
+                    break;
+                }
+            }
+        }
+        moduleBuilder.setDescription(description);
+        moduleBuilder.setReference(reference);
+    }
+
+    @Override
+    public void exitModule_stmt(YangParser.Module_stmtContext ctx) {
+        exitLog("module", actualPath.pop());
+    }
+
+    @Override
+    public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
+        enterLog("module_header", "", ctx.getStart().getLine());
+        String yangVersion = null;
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree treeNode = ctx.getChild(i);
+            if (treeNode instanceof Namespace_stmtContext) {
+                final String namespaceStr = stringFromNode(treeNode);
+                namespace = URI.create(namespaceStr);
+                moduleBuilder.setNamespace(namespace);
+                setLog("namespace", namespaceStr);
+            } else if (treeNode instanceof Prefix_stmtContext) {
+                yangModelPrefix = stringFromNode(treeNode);
+                moduleBuilder.setPrefix(yangModelPrefix);
+                setLog("prefix", yangModelPrefix);
+            } else if (treeNode instanceof Yang_version_stmtContext) {
+                yangVersion = stringFromNode(treeNode);
+                setLog("yang-version", yangVersion);
+            }
+        }
+
+        if (yangVersion == null) {
+            yangVersion = "1";
+        }
+        moduleBuilder.setYangVersion(yangVersion);
+    }
+
+    @Override
+    public void exitModule_header_stmts(Module_header_stmtsContext ctx) {
+        exitLog("module_header", "");
+    }
+
+    @Override
+    public void enterMeta_stmts(YangParser.Meta_stmtsContext ctx) {
+        enterLog("meta_stmt", "", ctx.getStart().getLine());
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Organization_stmtContext) {
+                final String organization = stringFromNode(child);
+                moduleBuilder.setOrganization(organization);
+                setLog("organization", organization);
+            } else if (child instanceof Contact_stmtContext) {
+                final String contact = stringFromNode(child);
+                moduleBuilder.setContact(contact);
+                setLog("contact", contact);
+            } else if (child instanceof Description_stmtContext) {
+                final String description = stringFromNode(child);
+                moduleBuilder.setDescription(description);
+                setLog("description", description);
+            } else if (child instanceof Reference_stmtContext) {
+                final String reference = stringFromNode(child);
+                moduleBuilder.setReference(reference);
+                setLog("reference", reference);
+            }
+        }
+    }
+
+    @Override
+    public void exitMeta_stmts(YangParser.Meta_stmtsContext ctx) {
+        exitLog("meta_stmt", "");
+    }
+
+    @Override
+    public void enterRevision_stmts(Revision_stmtsContext ctx) {
+        enterLog("revisions", "", ctx.getStart().getLine());
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree treeNode = ctx.getChild(i);
+            if (treeNode instanceof Revision_stmtContext) {
+                updateRevisionForRevisionStatement(treeNode);
+            }
+        }
+    }
+
+    @Override
+    public void exitRevision_stmts(Revision_stmtsContext ctx) {
+        exitLog("revisions", "");
+    }
+
+    private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
+        final String revisionDateStr = stringFromNode(treeNode);
+        try {
+            final Date revision = simpleDateFormat.parse(revisionDateStr);
+            if ((revision != null) && (this.revision.compareTo(revision) < 0)) {
+                this.revision = revision;
+                moduleBuilder.setRevision(this.revision);
+                setLog("revision", this.revision.toString());
+                for (int i = 0; i < treeNode.getChildCount(); ++i) {
+                    ParseTree child = treeNode.getChild(i);
+                    if (child instanceof Reference_stmtContext) {
+                        moduleBuilder.setReference(stringFromNode(child));
+                    }
+                }
+            }
+        } catch (ParseException e) {
+            final String message = "Failed to parse revision string: " + revisionDateStr;
+            logger.warn(message);
+        }
+    }
+
+    @Override
+    public void enterImport_stmt(Import_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String importName = stringFromNode(ctx);
+        enterLog("import", importName, line);
+
+        String importPrefix = null;
+        Date importRevision = null;
+
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree treeNode = ctx.getChild(i);
+            if (treeNode instanceof Prefix_stmtContext) {
+                importPrefix = stringFromNode(treeNode);
+            }
+            if (treeNode instanceof Revision_date_stmtContext) {
+                String importRevisionStr = stringFromNode(treeNode);
+                try {
+                    importRevision = simpleDateFormat.parse(importRevisionStr);
+                } catch (ParseException e) {
+                    logger.warn("Failed to parse import revision-date at line " + line + ": " + importRevisionStr);
+                }
+            }
+        }
+        moduleBuilder.addModuleImport(importName, importRevision, importPrefix);
+        setLog("import", "(" + importName + "; " + importRevision + "; " + importPrefix + ")");
+    }
+
+    @Override
+    public void exitImport_stmt(Import_stmtContext ctx) {
+        exitLog("import", "");
+    }
+
+    @Override
+    public void enterAugment_stmt(YangParser.Augment_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String augmentPath = stringFromNode(ctx);
+        enterLog("augment", augmentPath, line);
+
+        AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                builder.setDescription(stringFromNode(child));
+            } else if (child instanceof Reference_stmtContext) {
+                builder.setReference(stringFromNode(child));
+            } else if (child instanceof Status_stmtContext) {
+                builder.setStatus(parseStatus((Status_stmtContext) child));
+            } else if (child instanceof When_stmtContext) {
+                builder.addWhenCondition(stringFromNode(child));
+            }
+        }
+
+        moduleBuilder.enterNode(builder);
+        actualPath.push(augmentPath);
+    }
+
+    @Override
+    public void exitAugment_stmt(YangParser.Augment_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("augment", actualPath.pop());
+    }
+
+    @Override
+    public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String extName = stringFromNode(ctx);
+        enterLog("extension", extName, line);
+
+        QName qname = new QName(namespace, revision, yangModelPrefix, extName);
+        ExtensionBuilder builder = moduleBuilder.addExtension(qname, line);
+        parseSchemaNodeArgs(ctx, builder);
+
+        String argument = null;
+        boolean yin = false;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Argument_stmtContext) {
+                argument = stringFromNode(child);
+                yin = parseYinValue((Argument_stmtContext) child);
+                break;
+            }
+        }
+        builder.setArgument(argument);
+        builder.setYinElement(yin);
+
+        moduleBuilder.enterNode(builder);
+        actualPath.push(extName);
+    }
+
+    @Override
+    public void exitExtension_stmt(YangParser.Extension_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("extension", actualPath.pop());
+    }
+
+    @Override
+    public void enterTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String typedefName = stringFromNode(ctx);
+        enterLog("typedef", typedefName, line);
+
+        QName typedefQName = new QName(namespace, revision, yangModelPrefix, typedefName);
+        TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(typedefName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+        builder.setUnits(parseUnits(ctx));
+        builder.setDefaultValue(parseDefault(ctx));
+    }
+
+    @Override
+    public void exitTypedef_stmt(YangParser.Typedef_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("typedef", actualPath.pop());
+    }
+
+    @Override
+    public void enterType_stmt(YangParser.Type_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String typeName = stringFromNode(ctx);
+        enterLog("type", typeName, line);
+
+        final QName typeQName = parseQName(typeName);
+
+        TypeDefinition<?> type = null;
+        Type_body_stmtsContext typeBody = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
+                typeBody = (Type_body_stmtsContext) ctx.getChild(i);
+                break;
+            }
+        }
+
+        // if this is base yang type...
+        if (YangTypesConverter.isBaseYangType(typeName)) {
+            if (typeBody == null) {
+                // check for types which must have body
+                checkMissingBody(typeName, moduleName, line);
+                // if there are no constraints, just grab default base yang type
+                type = YangTypesConverter.javaTypeForBaseYangType(actualPath, namespace, revision, typeName);
+                moduleBuilder.setType(type);
+            } else {
+                if ("union".equals(typeName)) {
+                    SchemaPath p = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, typeName);
+                    UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, namespace, revision);
+                    moduleBuilder.enterNode(unionBuilder);
+                    unionBuilder.setPath(p);
+                } else if ("identityref".equals(typeName)) {
+                    SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, typeName);
+                    moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody));
+                } else {
+                    type = parseTypeWithBody(typeName, typeBody, actualPath, namespace, revision, yangModelPrefix,
+                            moduleBuilder.getActualNode());
+                    moduleBuilder.setType(type);
+                }
+            }
+        } else {
+            type = parseUnknownTypeWithBody(typeQName, typeBody, actualPath, namespace, revision, yangModelPrefix,
+                    moduleBuilder.getActualNode());
+            // add parent node of this type statement to dirty nodes
+            moduleBuilder.markActualNodeDirty();
+            moduleBuilder.setType(type);
+        }
+
+        actualPath.push(typeName);
+    }
+
+    private QName parseQName(String typeName) {
+        QName typeQName;
+        if (typeName.contains(":")) {
+            String[] splittedName = typeName.split(":");
+            String prefix = splittedName[0];
+            String name = splittedName[1];
+            if (prefix.equals(yangModelPrefix)) {
+                typeQName = new QName(namespace, revision, prefix, name);
+            } else {
+                typeQName = new QName(null, null, prefix, name);
+            }
+        } else {
+            typeQName = new QName(namespace, revision, yangModelPrefix, typeName);
+        }
+        return typeQName;
+    }
+
+    @Override
+    public void exitType_stmt(YangParser.Type_stmtContext ctx) {
+        final String typeName = stringFromNode(ctx);
+        if ("union".equals(typeName)) {
+            moduleBuilder.exitNode();
+        }
+        exitLog("type", actualPath.pop());
+    }
+
+    @Override
+    public void enterGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String groupName = stringFromNode(ctx);
+        enterLog("grouping", groupName, line);
+
+        QName groupQName = new QName(namespace, revision, yangModelPrefix, groupName);
+        GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(groupName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+    }
+
+    @Override
+    public void exitGrouping_stmt(YangParser.Grouping_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("grouping", actualPath.pop());
+    }
+
+    @Override
+    public void enterContainer_stmt(Container_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String containerName = stringFromNode(ctx);
+        enterLog("container", containerName, line);
+
+        QName containerQName = new QName(namespace, revision, yangModelPrefix, containerName);
+        SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, containerName);
+
+        ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(containerName);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree childNode = ctx.getChild(i);
+            if (childNode instanceof Presence_stmtContext) {
+                builder.setPresence(true);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void exitContainer_stmt(Container_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("container", actualPath.pop());
+    }
+
+    @Override
+    public void enterLeaf_stmt(Leaf_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String leafName = stringFromNode(ctx);
+        enterLog("leaf", leafName, line);
+
+        QName leafQName = new QName(namespace, revision, yangModelPrefix, leafName);
+        SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, leafName);
+
+        LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, schemaPath);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(leafName);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+
+        String defaultStr = null;
+        String unitsStr = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Default_stmtContext) {
+                defaultStr = stringFromNode(child);
+            } else if (child instanceof Units_stmtContext) {
+                unitsStr = stringFromNode(child);
+            }
+        }
+        builder.setDefaultStr(defaultStr);
+        builder.setUnits(unitsStr);
+    }
+
+    @Override
+    public void exitLeaf_stmt(YangParser.Leaf_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("leaf", actualPath.pop());
+    }
+
+    @Override
+    public void enterUses_stmt(YangParser.Uses_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String groupingPathStr = stringFromNode(ctx);
+        enterLog("uses", groupingPathStr, line);
+
+        UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPathStr);
+
+        moduleBuilder.enterNode(builder);
+        actualPath.push(groupingPathStr);
+    }
+
+    @Override
+    public void exitUses_stmt(YangParser.Uses_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("uses", actualPath.pop());
+    }
+
+    @Override public void enterUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String augmentPath = stringFromNode(ctx);
+        enterLog("augment", augmentPath, line);
+
+        AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                builder.setDescription(stringFromNode(child));
+            } else if (child instanceof Reference_stmtContext) {
+                builder.setReference(stringFromNode(child));
+            } else if (child instanceof Status_stmtContext) {
+                builder.setStatus(parseStatus((Status_stmtContext) child));
+            } else if (child instanceof When_stmtContext) {
+                builder.addWhenCondition(stringFromNode(child));
+            }
+        }
+
+        moduleBuilder.enterNode(builder);
+        actualPath.push(augmentPath);
+    }
+
+    @Override public void exitUses_augment_stmt(YangParser.Uses_augment_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("augment", actualPath.pop());
+    }
+
+    @Override
+    public void enterRefine_stmt(YangParser.Refine_stmtContext ctx) {
+        final String refineString = stringFromNode(ctx);
+        enterLog("refine", refineString, ctx.getStart().getLine());
+
+        RefineHolder refine = parseRefine(ctx, moduleName);
+        moduleBuilder.addRefine(refine);
+        moduleBuilder.enterNode(refine);
+        actualPath.push(refineString);
+    }
+
+    @Override
+    public void exitRefine_stmt(YangParser.Refine_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("refine", actualPath.pop());
+    }
+
+    @Override
+    public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String leafListName = stringFromNode(ctx);
+        enterLog("leaf-list", leafListName, line);
+
+        QName leafListQName = new QName(namespace, revision, yangModelPrefix, leafListName);
+        SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, leafListName);
+
+        LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, schemaPath);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(leafListName);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, ctx.getStart().getLine()));
+
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree childNode = ctx.getChild(i);
+            if (childNode instanceof Ordered_by_stmtContext) {
+                final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
+                final boolean userOrdered = parseUserOrdered(orderedBy);
+                builder.setUserOrdered(userOrdered);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void exitLeaf_list_stmt(YangParser.Leaf_list_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("leaf-list", actualPath.pop());
+    }
+
+    @Override
+    public void enterList_stmt(List_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String listName = stringFromNode(ctx);
+        enterLog("list", listName, line);
+
+        QName listQName = new QName(namespace, revision, yangModelPrefix, listName);
+        SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, listName);
+
+        ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, schemaPath);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(listName);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+
+        String keyDefinition = "";
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            ParseTree childNode = ctx.getChild(i);
+            if (childNode instanceof Ordered_by_stmtContext) {
+                final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
+                final boolean userOrdered = parseUserOrdered(orderedBy);
+                builder.setUserOrdered(userOrdered);
+            } else if (childNode instanceof Key_stmtContext) {
+                keyDefinition = stringFromNode(childNode);
+                List<QName> key = createListKey(keyDefinition, namespace, revision, yangModelPrefix);
+                builder.setKeyDefinition(key);
+            }
+        }
+    }
+
+    @Override
+    public void exitList_stmt(List_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("list", actualPath.pop());
+    }
+
+    @Override
+    public void enterAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String anyXmlName = stringFromNode(ctx);
+        enterLog("anyxml", anyXmlName, line);
+
+        QName anyXmlQName = new QName(namespace, revision, yangModelPrefix, anyXmlName);
+        SchemaPath schemaPath = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, anyXmlName);
+
+        AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, schemaPath);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(anyXmlName);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+    }
+
+    @Override
+    public void exitAnyxml_stmt(YangParser.Anyxml_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("anyxml", actualPath.pop());
+    }
+
+    @Override
+    public void enterChoice_stmt(YangParser.Choice_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String choiceName = stringFromNode(ctx);
+        enterLog("choice", choiceName, line);
+
+        QName choiceQName = new QName(namespace, revision, yangModelPrefix, choiceName);
+
+        ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(choiceName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+        builder.setConfiguration(getConfig(ctx, moduleBuilder.getActualParent(), moduleName, line));
+
+        // set 'default' case
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Default_stmtContext) {
+                String defaultCase = stringFromNode(child);
+                builder.setDefaultCase(defaultCase);
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void exitChoice_stmt(YangParser.Choice_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("choice", actualPath.pop());
+    }
+
+    @Override
+    public void enterCase_stmt(YangParser.Case_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String caseName = stringFromNode(ctx);
+        enterLog("case", caseName, line);
+
+        QName caseQName = new QName(namespace, revision, yangModelPrefix, caseName);
+        ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(caseName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+    }
+
+    @Override
+    public void exitCase_stmt(YangParser.Case_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("case", actualPath.pop());
+    }
+
+    @Override
+    public void enterNotification_stmt(YangParser.Notification_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String notificationName = stringFromNode(ctx);
+        enterLog("notification", notificationName, line);
+
+        QName notificationQName = new QName(namespace, revision, yangModelPrefix, notificationName);
+        NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(notificationName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+    }
+
+    @Override
+    public void exitNotification_stmt(YangParser.Notification_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("notification", actualPath.pop());
+    }
+
+    // Unknown nodes
+    @Override
+    public void enterIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String nodeParameter = stringFromNode(ctx);
+        enterLog("unknown-node", nodeParameter, line);
+
+        QName nodeType = null;
+
+        final String nodeTypeStr = ctx.getChild(0).getText();
+        final String[] splittedElement = nodeTypeStr.split(":");
+        if (splittedElement.length == 1) {
+            nodeType = new QName(null, null, yangModelPrefix, splittedElement[0]);
+        } else {
+            nodeType = new QName(null, null, splittedElement[0], splittedElement[1]);
+        }
+
+        QName qname;
+        if (nodeParameter != null) {
+            String[] splittedName = nodeParameter.split(":");
+            if (splittedName.length == 2) {
+                qname = new QName(null, null, splittedName[0], splittedName[1]);
+            } else {
+                qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]);
+            }
+        } else {
+            qname = new QName(namespace, revision, yangModelPrefix, nodeParameter);
+        }
+
+        UnknownSchemaNodeBuilder builder = moduleBuilder.addUnknownSchemaNode(line, qname);
+        builder.setNodeType(nodeType);
+        builder.setNodeParameter(nodeParameter);
+        actualPath.push(nodeParameter);
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+        moduleBuilder.enterNode(builder);
+    }
+
+    @Override
+    public void exitIdentifier_stmt(YangParser.Identifier_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("unknown-node", actualPath.pop());
+    }
+
+    @Override
+    public void enterRpc_stmt(YangParser.Rpc_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String rpcName = stringFromNode(ctx);
+        enterLog("rpc", rpcName, line);
+
+        QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName);
+        RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName);
+        moduleBuilder.enterNode(rpcBuilder);
+        actualPath.push(rpcName);
+
+        rpcBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, rpcBuilder);
+    }
+
+    @Override
+    public void exitRpc_stmt(YangParser.Rpc_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("rpc", actualPath.pop());
+    }
+
+    @Override
+    public void enterInput_stmt(YangParser.Input_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String input = "input";
+        enterLog(input, input, line);
+
+        QName rpcQName = new QName(namespace, revision, yangModelPrefix, input);
+        SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, input);
+
+        ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(input);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+    }
+
+    @Override
+    public void exitInput_stmt(YangParser.Input_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("input", actualPath.pop());
+    }
+
+    @Override
+    public void enterOutput_stmt(YangParser.Output_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String output = "output";
+        enterLog(output, output, line);
+
+        QName rpcQName = new QName(namespace, revision, yangModelPrefix, output);
+        SchemaPath path = createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix, output);
+
+        ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(output);
+
+        parseSchemaNodeArgs(ctx, builder);
+        parseConstraints(ctx, builder.getConstraints());
+    }
+
+    @Override
+    public void exitOutput_stmt(YangParser.Output_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("output", actualPath.pop());
+    }
+
+    @Override
+    public void enterFeature_stmt(YangParser.Feature_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String featureName = stringFromNode(ctx);
+        enterLog("feature", featureName, line);
+
+        QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName);
+        FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName);
+        moduleBuilder.enterNode(featureBuilder);
+        actualPath.push(featureName);
+
+        featureBuilder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, featureBuilder);
+    }
+
+    @Override
+    public void exitFeature_stmt(YangParser.Feature_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("feature", actualPath.pop());
+    }
+
+    @Override
+    public void enterDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String targetPath = stringFromNode(ctx);
+        enterLog("deviation", targetPath, line);
+
+        String reference = null;
+        String deviate = null;
+        DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(targetPath);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else if (child instanceof Deviate_not_supported_stmtContext) {
+                deviate = stringFromNode(child);
+            } else if (child instanceof Deviate_add_stmtContext) {
+                deviate = stringFromNode(child);
+            } else if (child instanceof Deviate_replace_stmtContext) {
+                deviate = stringFromNode(child);
+            } else if (child instanceof Deviate_delete_stmtContext) {
+                deviate = stringFromNode(child);
+            }
+        }
+        builder.setReference(reference);
+        builder.setDeviate(deviate);
+    }
+
+    @Override
+    public void exitDeviation_stmt(YangParser.Deviation_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("deviation", actualPath.pop());
+    }
+
+    @Override
+    public void enterIdentity_stmt(YangParser.Identity_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String identityName = stringFromNode(ctx);
+        enterLog("identity", identityName, line);
+
+        final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName);
+        IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, actualPath, line);
+        moduleBuilder.enterNode(builder);
+        actualPath.push(identityName);
+
+        builder.setPath(createActualSchemaPath(actualPath, namespace, revision, yangModelPrefix));
+        parseSchemaNodeArgs(ctx, builder);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Base_stmtContext) {
+                String baseIdentityName = stringFromNode(child);
+                builder.setBaseIdentityName(baseIdentityName);
+            }
+        }
+    }
+
+    @Override
+    public void exitIdentity_stmt(YangParser.Identity_stmtContext ctx) {
+        moduleBuilder.exitNode();
+        exitLog("identity", actualPath.pop());
+    }
+
+    public ModuleBuilder getModuleBuilder() {
+        return moduleBuilder;
+    }
+
+    private void enterLog(String p1, String p2, int line) {
+        logger.debug("entering " + p1 + " " + p2 + " (" + line + ")");
+    }
+
+    private void exitLog(String p1, String p2) {
+        logger.debug("exiting " + p1 + " " + p2);
+    }
+
+    private void setLog(String p1, String p2) {
+        logger.debug("setting " + p1 + " " + p2);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/BitImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/BitImpl.java
new file mode 100644 (file)
index 0000000..c6bbc65
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
+
+final class BitImpl implements BitsTypeDefinition.Bit {
+    private final Long position;
+    private final QName qname;
+    private final SchemaPath schemaPath;
+    private final String description;
+    private final String reference;
+    private final Status status;
+    private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+
+    BitImpl(final Long position, final QName qname,
+            final SchemaPath schemaPath, final String description,
+            final String reference, final Status status,
+            final List<UnknownSchemaNode> unknownNodes) {
+        this.position = position;
+        this.qname = qname;
+        this.schemaPath = schemaPath;
+        this.description = description;
+        this.reference = reference;
+        this.status = status;
+        if(unknownNodes != null) {
+            this.unknownNodes = unknownNodes;
+        }
+    }
+
+    @Override
+    public QName getQName() {
+        return qname;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return schemaPath;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public Status getStatus() {
+        return status;
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return unknownNodes;
+    }
+
+    @Override
+    public Long getPosition() {
+        return position;
+    }
+
+    @Override
+    public String getName() {
+        return qname.getLocalName();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result
+                + ((qname == null) ? 0 : qname.hashCode());
+        result = prime * result
+                + ((schemaPath == null) ? 0 : schemaPath.hashCode());
+        result = prime * result
+                + ((position == null) ? 0 : position.hashCode());
+        result = prime
+                * result
+                + ((unknownNodes == null) ? 0 : unknownNodes.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Bit other = (Bit) obj;
+        if (qname == null) {
+            if (other.getQName() != null) {
+                return false;
+            }
+        } else if (!qname.equals(other.getQName())) {
+            return false;
+        }
+        if (schemaPath == null) {
+            if (other.getPath() != null) {
+                return false;
+            }
+        } else if (!schemaPath.equals(other.getPath())) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return Bit.class.getSimpleName() + "[name="
+                + qname.getLocalName() + ", position=" + position + "]";
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/Comparators.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/Comparators.java
new file mode 100644 (file)
index 0000000..ea87eec
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.util.Comparator;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.SchemaNode;
+
+public class Comparators {
+
+    public static final QNameComparator QNAME_COMP = new QNameComparator();
+    public static final SchemaNodeComparator SCHEMA_NODE_COMP = new SchemaNodeComparator();
+
+    private Comparators() {
+    }
+
+    private static final class QNameComparator implements Comparator<QName> {
+        @Override
+        public int compare(QName o1, QName o2) {
+            return o1.getLocalName().compareTo(o2.getLocalName());
+        }
+    }
+
+    private static final class SchemaNodeComparator implements Comparator<SchemaNode> {
+        @Override
+        public int compare(SchemaNode o1, SchemaNode o2) {
+            return o1.getQName().getLocalName().compareTo(o2.getQName().getLocalName());
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySort.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySort.java
new file mode 100644 (file)
index 0000000..aea9409
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.controller.yang.parser.util.TopologicalSort.Node;
+import org.opendaylight.controller.yang.parser.util.TopologicalSort.NodeImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Creates a module dependency graph from provided {@link ModuleBuilder}s and
+ * provides a {@link #sort()} method. It is topological sort and returns modules
+ * in order in which they should be processed (e.g. if A imports B, sort returns
+ * {B, A}).
+ */
+public final class ModuleDependencySort {
+
+    private static final Date DEFAULT_REVISION = new Date(0);
+    private static final Logger logger = LoggerFactory.getLogger(ModuleDependencySort.class);
+
+    /**
+     * Topological sort of module builder dependency graph.
+     *
+     * @return Sorted list of Module builders. Modules can be further processed
+     *         in returned order.
+     */
+    public static List<ModuleBuilder> sort(ModuleBuilder... builders) {
+        List<Node> sorted = sortInternal(Arrays.asList(builders));
+        // Cast to ModuleBuilder from Node and return
+        return Lists.transform(sorted, new Function<Node, ModuleBuilder>() {
+
+            @Override
+            public ModuleBuilder apply(Node input) {
+                return (ModuleBuilder) ((ModuleNodeImpl) input).getReference();
+            }
+        });
+    }
+
+    public static List<ModuleBuilder> sortWithContext(SchemaContext context, ModuleBuilder... builders) {
+        List<Object> modules = new ArrayList<Object>();
+        Collections.addAll(modules, builders);
+        modules.addAll(context.getModules());
+
+        List<Node> sorted = sortInternal(modules);
+        // Cast to ModuleBuilder from Node if possible and return
+        return Lists.transform(sorted, new Function<Node, ModuleBuilder>() {
+
+            @Override
+            public ModuleBuilder apply(Node input) {
+                if (((ModuleNodeImpl) input).getReference() instanceof ModuleBuilder) {
+                    return (ModuleBuilder) ((ModuleNodeImpl) input).getReference();
+                } else {
+                    return null;
+                }
+            }
+        });
+    }
+
+    /**
+     * Topological sort of module dependency graph.
+     *
+     * @return Sorted list of Modules. Modules can be further processed in
+     *         returned order.
+     */
+    public static List<Module> sort(Module... modules) {
+        List<Node> sorted = sortInternal(Arrays.asList(modules));
+        // Cast to Module from Node and return
+        return Lists.transform(sorted, new Function<Node, Module>() {
+
+            @Override
+            public Module apply(Node input) {
+                return (Module) ((ModuleNodeImpl) input).getReference();
+            }
+        });
+    }
+
+    private static List<Node> sortInternal(List<?> modules) {
+        Map<String, Map<Date, ModuleNodeImpl>> moduleGraph = createModuleGraph(modules);
+
+        Set<Node> nodes = Sets.newHashSet();
+        for (Map<Date, ModuleNodeImpl> map : moduleGraph.values()) {
+            for (ModuleNodeImpl node : map.values()) {
+                nodes.add(node);
+            }
+        }
+
+        return TopologicalSort.sort(nodes);
+    }
+
+    @VisibleForTesting
+    static Map<String, Map<Date, ModuleNodeImpl>> createModuleGraph(List<?> builders) {
+        Map<String, Map<Date, ModuleNodeImpl>> moduleGraph = Maps.newHashMap();
+
+        processModules(moduleGraph, builders);
+        processDependencies(moduleGraph, builders);
+
+        return moduleGraph;
+    }
+
+    /**
+     * Extract module:revision from module builders
+     */
+    private static void processDependencies(Map<String, Map<Date, ModuleNodeImpl>> moduleGraph, List<?> builders) {
+        Map<String, Date> imported = Maps.newHashMap();
+
+        // Create edges in graph
+        for (Object mb : builders) {
+
+            String fromName = null;
+            Date fromRevision = null;
+            Set<ModuleImport> imports = null;
+
+            if (mb instanceof Module) {
+                fromName = ((Module) mb).getName();
+                fromRevision = ((Module) mb).getRevision();
+                imports = ((Module) mb).getImports();
+            } else if (mb instanceof ModuleBuilder) {
+                fromName = ((ModuleBuilder) mb).getName();
+                fromRevision = ((ModuleBuilder) mb).getRevision();
+                imports = ((ModuleBuilder) mb).getModuleImports();
+            }
+            // no need to check if other Type of object, check is performed in
+            // process modules
+
+            if (fromRevision == null)
+                fromRevision = DEFAULT_REVISION;
+
+            for (ModuleImport imprt : imports) {
+                String toName = imprt.getModuleName();
+                Date toRevision = imprt.getRevision() == null ? DEFAULT_REVISION : imprt.getRevision();
+
+                ModuleNodeImpl from = moduleGraph.get(fromName).get(fromRevision);
+
+                ModuleNodeImpl to = getModuleByNameAndRevision(moduleGraph, fromName, fromRevision, toName, toRevision);
+
+                /*
+                 * Check imports: If module is imported twice with different
+                 * revisions then throw exception
+                 */
+                if (imported.get(toName) != null && !imported.get(toName).equals(toRevision)) {
+                    if (!imported.get(toName).equals(DEFAULT_REVISION) && !toRevision.equals(DEFAULT_REVISION)) {
+                        ex(String.format("Module:%s imported twice with different revisions:%s, %s", toName,
+                                formatRevDate(imported.get(toName)), formatRevDate(toRevision)));
+                    }
+
+                }
+
+                imported.put(toName, toRevision);
+
+                from.addEdge(to);
+            }
+        }
+    }
+
+    /**
+     * Get imported module by its name and revision from moduleGraph
+     */
+    private static ModuleNodeImpl getModuleByNameAndRevision(Map<String, Map<Date, ModuleNodeImpl>> moduleGraph,
+            String fromName, Date fromRevision, String toName, Date toRevision) {
+        ModuleNodeImpl to = null;
+
+        if (moduleGraph.get(toName) == null || !moduleGraph.get(toName).containsKey(toRevision)) {
+            // If revision is not specified in import, but module exists
+            // with different revisions, take first
+            if (moduleGraph.get(toName) != null && !moduleGraph.get(toName).isEmpty()
+                    && toRevision.equals(DEFAULT_REVISION)) {
+                to = moduleGraph.get(toName).values().iterator().next();
+                logger.warn(String
+                        .format("Import:%s:%s by module:%s:%s does not specify revision, using:%s:%s for module dependency sort",
+                                toName, formatRevDate(toRevision), fromName, formatRevDate(fromRevision), to.getName(),
+                                formatRevDate(to.getRevision())));
+            } else
+                ex(String.format("Not existing module imported:%s:%s by:%s:%s", toName, formatRevDate(toRevision),
+                        fromName, formatRevDate(fromRevision)));
+        } else {
+            to = moduleGraph.get(toName).get(toRevision);
+        }
+        return to;
+    }
+
+    private static void ex(String message) {
+        throw new YangValidationException(message);
+    }
+
+    /**
+     * Extract dependencies from module builders or modules to fill dependency
+     * graph
+     */
+    private static void processModules(Map<String, Map<Date, ModuleNodeImpl>> moduleGraph, List<?> builders) {
+
+        // Process nodes
+        for (Object mb : builders) {
+
+            String name = null;
+            Date rev = null;
+
+            if (mb instanceof Module) {
+                name = ((Module) mb).getName();
+                rev = ((Module) mb).getRevision();
+            } else if (mb instanceof ModuleBuilder) {
+                name = ((ModuleBuilder) mb).getName();
+                rev = ((ModuleBuilder) mb).getRevision();
+            } else {
+                throw new IllegalStateException(String.format(
+                        "Unexpected type of node for sort, expected only:%s, %s, got:%s", Module.class,
+                        ModuleBuilder.class, mb.getClass()));
+            }
+
+            if (rev == null)
+                rev = DEFAULT_REVISION;
+
+            if (moduleGraph.get(name) == null)
+                moduleGraph.put(name, Maps.<Date, ModuleNodeImpl> newHashMap());
+
+            if (moduleGraph.get(name).get(rev) != null)
+                ex(String.format("Module:%s with revision:%s declared twice", name, formatRevDate(rev)));
+
+            moduleGraph.get(name).put(rev, new ModuleNodeImpl(name, rev, mb));
+        }
+    }
+
+    private static String formatRevDate(Date rev) {
+        return rev == DEFAULT_REVISION ? "default" : YangParserListenerImpl.simpleDateFormat.format(rev);
+    }
+
+    @VisibleForTesting
+    static class ModuleNodeImpl extends NodeImpl {
+        private final String name;
+        private final Date revision;
+        private final Object originalObject;
+
+        public ModuleNodeImpl(String name, Date revision, Object builder) {
+            this.name = name;
+            this.revision = revision;
+            this.originalObject = builder;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Date getRevision() {
+            return revision;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result + ((revision == null) ? 0 : revision.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ModuleNodeImpl other = (ModuleNodeImpl) obj;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            if (revision == null) {
+                if (other.revision != null)
+                    return false;
+            } else if (!revision.equals(other.revision))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "Module [name=" + name + ", revision=" + formatRevDate(revision) + "]";
+        }
+
+        public Object getReference() {
+            return originalObject;
+        }
+
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/MustDefinitionImpl.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/MustDefinitionImpl.java
new file mode 100644 (file)
index 0000000..977b3ff
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+
+final class MustDefinitionImpl implements MustDefinition {
+    private final String mustStr;
+    private final String description;
+    private final String reference;
+    private final String errorAppTag;
+    private final String errorMessage;
+
+    MustDefinitionImpl(String mustStr, String description, String reference,
+            String errorAppTag, String errorMessage) {
+        this.mustStr = mustStr;
+        this.description = description;
+        this.reference = reference;
+        this.errorAppTag = errorAppTag;
+        this.errorMessage = errorMessage;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String getErrorAppTag() {
+        return errorAppTag;
+    }
+
+    @Override
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    @Override
+    public String getReference() {
+        return reference;
+    }
+
+    @Override
+    public RevisionAwareXPath getXpath() {
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mustStr == null) ? 0 : mustStr.hashCode());
+        result = prime * result
+                + ((description == null) ? 0 : description.hashCode());
+        result = prime * result
+                + ((reference == null) ? 0 : reference.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final MustDefinitionImpl other = (MustDefinitionImpl) obj;
+        if (mustStr == null) {
+            if (other.mustStr != null) {
+                return false;
+            }
+        } else if (!mustStr.equals(other.mustStr)) {
+            return false;
+        }
+        if (description == null) {
+            if (other.description != null) {
+                return false;
+            }
+        } else if (!description.equals(other.description)) {
+            return false;
+        }
+        if (reference == null) {
+            if (other.reference != null) {
+                return false;
+            }
+        } else if (!reference.equals(other.reference)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return mustStr;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserListenerUtils.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserListenerUtils.java
new file mode 100644 (file)
index 0000000..d2ca3a7
--- /dev/null
@@ -0,0 +1,1667 @@
+/*
+ * 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/eplv10.html
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Stack;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.*;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Error_app_tag_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Error_message_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Identityref_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Instance_identifier_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leafref_specificationContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_value_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_value_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Path_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_anyxml_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_choice_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_container_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_leaf_list_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_leaf_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_list_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_pomContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Value_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_stmtContext;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
+import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.opendaylight.controller.yang.model.util.BaseConstraints;
+import org.opendaylight.controller.yang.model.util.BaseTypes;
+import org.opendaylight.controller.yang.model.util.BinaryType;
+import org.opendaylight.controller.yang.model.util.BitsType;
+import org.opendaylight.controller.yang.model.util.Decimal64;
+import org.opendaylight.controller.yang.model.util.EnumerationType;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
+import org.opendaylight.controller.yang.model.util.Int16;
+import org.opendaylight.controller.yang.model.util.Int32;
+import org.opendaylight.controller.yang.model.util.Int64;
+import org.opendaylight.controller.yang.model.util.Int8;
+import org.opendaylight.controller.yang.model.util.Leafref;
+import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.controller.yang.model.util.StringType;
+import org.opendaylight.controller.yang.model.util.Uint16;
+import org.opendaylight.controller.yang.model.util.Uint32;
+import org.opendaylight.controller.yang.model.util.Uint64;
+import org.opendaylight.controller.yang.model.util.Uint8;
+import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ConstraintsBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ParserListenerUtils {
+    private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
+
+    private ParserListenerUtils() {
+    }
+
+    /**
+     * Parse given tree and get first string value.
+     *
+     * @param treeNode
+     *            tree to parse
+     * @return first string value from given tree
+     */
+    public static String stringFromNode(final ParseTree treeNode) {
+        final String result = "";
+        for (int i = 0; i < treeNode.getChildCount(); ++i) {
+            if (treeNode.getChild(i) instanceof StringContext) {
+                final StringContext context = (StringContext) treeNode.getChild(i);
+                if (context != null) {
+                    return context.getChild(0).getText().replace("\"", "");
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse 'description', 'reference' and 'status' statements and fill in
+     * given builder.
+     *
+     * @param ctx
+     *            context to parse
+     * @param builder
+     *            builder to fill in with parsed statements
+     */
+    public static void parseSchemaNodeArgs(final ParseTree ctx, final SchemaNodeBuilder builder) {
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            final ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                final String desc = stringFromNode(child);
+                builder.setDescription(desc);
+            } else if (child instanceof Reference_stmtContext) {
+                final String ref = stringFromNode(child);
+                builder.setReference(ref);
+            } else if (child instanceof Status_stmtContext) {
+                final Status status = parseStatus((Status_stmtContext) child);
+                builder.setStatus(status);
+            }
+        }
+    }
+
+    /**
+     * Parse given context and return its value;
+     *
+     * @param ctx
+     *            status context
+     * @return value parsed from context
+     */
+    public static Status parseStatus(final Status_stmtContext ctx) {
+        Status result = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree statusArg = ctx.getChild(i);
+            if (statusArg instanceof Status_argContext) {
+                String statusArgStr = stringFromNode(statusArg);
+                if ("current".equals(statusArgStr)) {
+                    result = Status.CURRENT;
+                } else if ("deprecated".equals(statusArgStr)) {
+                    result = Status.DEPRECATED;
+                } else if ("obsolete".equals(statusArgStr)) {
+                    result = Status.OBSOLETE;
+                } else {
+                    LOG.warn("Invalid 'status' statement: " + statusArgStr);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse given tree and returns units statement as string.
+     *
+     * @param ctx
+     *            context to parse
+     * @return value of units statement as string or null if there is no units
+     *         statement
+     */
+    public static String parseUnits(final ParseTree ctx) {
+        String units = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Units_stmtContext) {
+                units = stringFromNode(child);
+                break;
+            }
+        }
+        return units;
+    }
+
+    /**
+     * Parse given tree and returns default statement as string.
+     *
+     * @param ctx
+     *            context to parse
+     * @return value of default statement as string or null if there is no
+     *         default statement
+     */
+    public static String parseDefault(final ParseTree ctx) {
+        String defaultValue = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Default_stmtContext) {
+                defaultValue = stringFromNode(child);
+                break;
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Create SchemaPath from actualPath and names.
+     *
+     * @param actualPath
+     *            current position in model
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @param names
+     * @return SchemaPath object.
+     */
+    public static SchemaPath createActualSchemaPath(final List<String> actualPath, final URI namespace,
+            final Date revision, final String prefix, final String... names) {
+        final List<QName> path = new ArrayList<QName>();
+        QName qname;
+        // start from index 1 - module name omited
+        for (int i = 1; i < actualPath.size(); i++) {
+            qname = new QName(namespace, revision, prefix, actualPath.get(i));
+            path.add(qname);
+        }
+        for (String name : names) {
+            qname = new QName(namespace, revision, prefix, name);
+            path.add(qname);
+        }
+        return new SchemaPath(path, true);
+    }
+
+    /**
+     * Create SchemaPath from given string.
+     *
+     * @param augmentPath
+     *            string representation of path
+     * @return SchemaPath object
+     */
+    public static SchemaPath parseAugmentPath(final String augmentPath) {
+        final boolean absolute = augmentPath.startsWith("/");
+        final String[] splittedPath = augmentPath.split("/");
+        List<QName> path = new ArrayList<QName>();
+        QName name;
+        for (String pathElement : splittedPath) {
+            if (pathElement.length() > 0) {
+                String[] splittedElement = pathElement.split(":");
+                if (splittedElement.length == 1) {
+                    name = new QName(null, null, null, splittedElement[0]);
+                } else {
+                    name = new QName(null, null, splittedElement[0], splittedElement[1]);
+                }
+                path.add(name);
+            }
+        }
+        return new SchemaPath(path, absolute);
+    }
+
+    /**
+     * Create java.util.List of QName objects from given key definition as
+     * string.
+     *
+     * @param keyDefinition
+     *            key definition as string
+     * @param namespace
+     *            current namespace
+     * @param revision
+     *            current revision
+     * @param prefix
+     *            current prefix
+     * @return YANG list key as java.util.List of QName objects
+     */
+    public static List<QName> createListKey(final String keyDefinition, final URI namespace, final Date revision,
+            final String prefix) {
+        List<QName> key = new ArrayList<QName>();
+        String[] splittedKey = keyDefinition.split(" ");
+
+        QName qname = null;
+        for (String keyElement : splittedKey) {
+            if (keyElement.length() != 0) {
+                qname = new QName(namespace, revision, prefix, keyElement);
+                key.add(qname);
+            }
+        }
+        return key;
+    }
+
+    /**
+     * Parse given type body of enumeration statement.
+     *
+     * @param ctx
+     *            type body context to parse
+     * @param path
+     *            actual position in YANG model
+     * @param moduleName current module name
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @return List of EnumPair object parsed from given context
+     */
+    private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
+            final List<String> path, final String moduleName, final URI namespace, final Date revision, final String prefix) {
+        List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree enumSpecChild = ctx.getChild(i);
+            if (enumSpecChild instanceof Enum_specificationContext) {
+                int highestValue = -1;
+                for (int j = 0; j < enumSpecChild.getChildCount(); j++) {
+                    ParseTree enumChild = enumSpecChild.getChild(j);
+                    if (enumChild instanceof Enum_stmtContext) {
+                        EnumPair enumPair = createEnumPair((Enum_stmtContext) enumChild, highestValue, path, moduleName, namespace,
+                                revision, prefix);
+                        if (enumPair.getValue() > highestValue) {
+                            highestValue = enumPair.getValue();
+                        }
+                        enumConstants.add(enumPair);
+                    }
+                }
+            }
+        }
+        return enumConstants;
+    }
+
+    /**
+     * Parse enum statement context
+     *
+     * @param ctx
+     *            enum statement context
+     * @param highestValue
+     *            current highest value in enumeration
+     * @param path
+     *            actual position in YANG model
+     * @param moduleName
+     *            current module name
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @return EnumPair object parsed from given context
+     */
+    private static EnumTypeDefinition.EnumPair createEnumPair(final Enum_stmtContext ctx, final int highestValue,
+            final List<String> path, final String moduleName, final URI namespace, final Date revision,
+            final String prefix) {
+        final String name = stringFromNode(ctx);
+        final QName qname = new QName(namespace, revision, prefix, name);
+        Integer value = null;
+
+        String description = null;
+        String reference = null;
+        Status status = null;
+
+        List<String> enumPairPath = new ArrayList<String>(path);
+        enumPairPath.add(name);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Value_stmtContext) {
+                String valueStr = stringFromNode(child);
+                value = Integer.valueOf(valueStr);
+            } else if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else if (child instanceof Status_stmtContext) {
+                status = parseStatus((Status_stmtContext) child);
+            }
+        }
+
+        if (value == null) {
+            value = highestValue + 1;
+        }
+        if (value < -2147483648 || value > 2147483647) {
+            throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on enum '" + name
+                    + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: " + value);
+        }
+
+        EnumPairImpl result = new EnumPairImpl();
+        result.qname = qname;
+        result.path = createActualSchemaPath(enumPairPath, namespace, revision, prefix);
+        result.description = description;
+        result.reference = reference;
+        result.status = status;
+        result.name = name;
+        result.value = value;
+        return result;
+    }
+
+    /**
+     * Internal implementation of EnumPair.
+     */
+    private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
+        private QName qname;
+        private SchemaPath path;
+        private String description;
+        private String reference;
+        private Status status;
+        private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        private String name;
+        private Integer value;
+
+        @Override
+        public QName getQName() {
+            return qname;
+        }
+
+        @Override
+        public SchemaPath getPath() {
+            return path;
+        }
+
+        @Override
+        public String getDescription() {
+            return description;
+        }
+
+        @Override
+        public String getReference() {
+            return reference;
+        }
+
+        @Override
+        public Status getStatus() {
+            return status;
+        }
+
+        @Override
+        public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+            return unknownNodes;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public Integer getValue() {
+            return value;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((qname == null) ? 0 : qname.hashCode());
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            result = prime * result + ((unknownNodes == null) ? 0 : unknownNodes.hashCode());
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result + ((value == null) ? 0 : value.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            EnumPairImpl other = (EnumPairImpl) obj;
+            if (qname == null) {
+                if (other.qname != null) {
+                    return false;
+                }
+            } else if (!qname.equals(other.qname)) {
+                return false;
+            }
+            if (path == null) {
+                if (other.path != null) {
+                    return false;
+                }
+            } else if (!path.equals(other.path)) {
+                return false;
+            }
+            if (unknownNodes == null) {
+                if (other.unknownNodes != null) {
+                    return false;
+                }
+            } else if (!unknownNodes.equals(other.unknownNodes)) {
+                return false;
+            }
+            if (name == null) {
+                if (other.name != null) {
+                    return false;
+                }
+            } else if (!name.equals(other.name)) {
+                return false;
+            }
+            if (value == null) {
+                if (other.value != null) {
+                    return false;
+                }
+            } else if (!value.equals(other.value)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + name + ", value=" + value + "]";
+        }
+    }
+
+    /**
+     * Get and parse range from given type body context.
+     *
+     * @param ctx
+     *            type body context to parse
+     * @return List of RangeConstraint created from this context
+     */
+    private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
+        List<RangeConstraint> rangeConstraints = Collections.emptyList();
+        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree numRestrChild = ctx.getChild(i);
+            if (numRestrChild instanceof Numerical_restrictionsContext) {
+                for (int j = 0; j < numRestrChild.getChildCount(); j++) {
+                    ParseTree rangeChild = numRestrChild.getChild(j);
+                    if (rangeChild instanceof Range_stmtContext) {
+                        rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
+                        break outer;
+                    }
+                }
+            }
+        }
+        return rangeConstraints;
+    }
+
+    /**
+     * Parse given range context.
+     *
+     * @param ctx
+     *            range context to parse
+     * @return List of RangeConstraints parsed from this context
+     */
+    private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
+        final int line = ctx.getStart().getLine();
+        List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
+        String description = null;
+        String reference = null;
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            }
+        }
+
+        String rangeStr = stringFromNode(ctx);
+        String trimmed = rangeStr.replace(" ", "");
+        String[] splittedRange = trimmed.split("\\|");
+        for (String rangeDef : splittedRange) {
+            String[] splittedRangeDef = rangeDef.split("\\.\\.");
+            Number min;
+            Number max;
+            if (splittedRangeDef.length == 1) {
+                min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+            } else {
+                min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+                max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
+            }
+            RangeConstraint range = BaseConstraints.rangeConstraint(min, max, description, reference);
+            rangeConstraints.add(range);
+        }
+
+        return rangeConstraints;
+    }
+
+    /**
+     * Get and parse length from given type body context.
+     *
+     * @param ctx
+     *            type body context to parse
+     * @return List of LengthConstraint created from this context
+     */
+    private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
+        List<LengthConstraint> lengthConstraints = Collections.emptyList();
+        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree stringRestrChild = ctx.getChild(i);
+            if (stringRestrChild instanceof String_restrictionsContext) {
+                for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
+                    ParseTree lengthChild = stringRestrChild.getChild(j);
+                    if (lengthChild instanceof Length_stmtContext) {
+                        lengthConstraints = parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
+                        break outer;
+                    }
+                }
+            }
+        }
+        return lengthConstraints;
+    }
+
+    /**
+     * Parse given length context.
+     *
+     * @param ctx
+     *            length context to parse
+     * @return List of LengthConstraints parsed from this context
+     */
+    private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
+        final int line = ctx.getStart().getLine();
+        List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
+        String description = null;
+        String reference = null;
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            }
+        }
+
+        String lengthStr = stringFromNode(ctx);
+        String trimmed = lengthStr.replace(" ", "");
+        String[] splittedRange = trimmed.split("\\|");
+        for (String rangeDef : splittedRange) {
+            String[] splittedRangeDef = rangeDef.split("\\.\\.");
+            Number min;
+            Number max;
+            if (splittedRangeDef.length == 1) {
+                min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+            } else {
+                min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+                max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
+            }
+            LengthConstraint range = BaseConstraints.lengthConstraint(min, max, description, reference);
+            lengthConstraints.add(range);
+        }
+
+        return lengthConstraints;
+    }
+
+    /**
+     * @param value
+     *            value to parse
+     * @return wrapper object of primitive java type or UnknownBoundaryNumber if
+     *         type is one of special YANG values 'min' or 'max'
+     */
+    private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
+        Number result = null;
+        if ("min".equals(value) || "max".equals(value)) {
+            result = new UnknownBoundaryNumber(value);
+        } else {
+            try {
+                result = Long.valueOf(value);
+            } catch (NumberFormatException e) {
+                throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse type body and return pattern constraints.
+     *
+     * @param ctx
+     *            type body
+     * @return list of pattern constraints
+     */
+    private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx) {
+        List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree stringRestrChild = ctx.getChild(i);
+            if (stringRestrChild instanceof String_restrictionsContext) {
+                for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
+                    ParseTree lengthChild = stringRestrChild.getChild(j);
+                    if (lengthChild instanceof Pattern_stmtContext) {
+                        patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));
+                    }
+                }
+            }
+        }
+        return patterns;
+    }
+
+    /**
+     * Internal helper method.
+     *
+     * @param ctx
+     *            pattern context
+     * @return PatternConstraint object
+     */
+    private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx) {
+        String description = null;
+        String reference = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            }
+        }
+        String pattern = patternStringFromNode(ctx);
+        return BaseConstraints.patternConstraint(pattern, description, reference);
+    }
+
+    /**
+     * Parse given context and return pattern value.
+     *
+     * @param ctx
+     *            context to parse
+     * @return pattern value as String
+     */
+    public static String patternStringFromNode(final Pattern_stmtContext ctx) {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof StringContext) {
+                for (int j = 0; j < child.getChildCount(); j++) {
+                    if (j % 2 == 0) {
+                        String patternToken = child.getChild(j).getText();
+                        result.append(patternToken.substring(1, patternToken.length() - 1));
+                    }
+                }
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Get fraction digits value from type body.
+     *
+     * @param ctx
+     *            type body context to parse
+     * @param moduleName
+     *            name of current module
+     * @return 'fraction-digits' value if present in given context, null
+     *         otherwise
+     */
+    private static Integer getFractionDigits(Type_body_stmtsContext ctx, String moduleName) {
+        Integer result = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree dec64specChild = ctx.getChild(i);
+            if (dec64specChild instanceof Decimal64_specificationContext) {
+                result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse decimal64 fraction-digits value.
+     *
+     * @param ctx
+     *            decimal64 context
+     * @param moduleName
+     *            name of current module
+     * @return fraction-digits value as Integer
+     */
+    private static Integer parseFractionDigits(Decimal64_specificationContext ctx, String moduleName) {
+        Integer result = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree fdChild = ctx.getChild(i);
+            if (fdChild instanceof Fraction_digits_stmtContext) {
+                String value = stringFromNode(fdChild);
+                try {
+                    result = Integer.valueOf(value);
+                } catch (NumberFormatException e) {
+                    throw new YangParseException(moduleName, ctx.getStart().getLine(),
+                            "Unable to parse fraction digits value '" + value + "'.", e);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Internal helper method for parsing bit statements from given type body
+     * context.
+     *
+     * @param ctx
+     *            type body context to parse
+     * @param actualPath
+     *            current position in YANG model
+     * @param moduleName current module name
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @return List of Bit objects created from this context
+     */
+    private static List<BitsTypeDefinition.Bit> getBits(Type_body_stmtsContext ctx, List<String> actualPath,
+            String moduleName, URI namespace, Date revision, String prefix) {
+        final List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
+        for (int j = 0; j < ctx.getChildCount(); j++) {
+            ParseTree bitsSpecChild = ctx.getChild(j);
+            if (bitsSpecChild instanceof Bits_specificationContext) {
+                long highestPosition = -1;
+                for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
+                    ParseTree bitChild = bitsSpecChild.getChild(k);
+                    if (bitChild instanceof Bit_stmtContext) {
+                        Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName, namespace,
+                                revision, prefix);
+                        if (bit.getPosition() > highestPosition) {
+                            highestPosition = bit.getPosition();
+                        }
+                        bits.add(bit);
+                    }
+                }
+            }
+        }
+        return bits;
+    }
+
+    /**
+     * Internal helper method for parsing bit context.
+     *
+     * @param ctx
+     *            bit statement context to parse
+     * @param highestPosition
+     *            current highest position in bits type
+     * @param actualPath
+     *            current position in YANG model
+     * @param moduleName current module name
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @return Bit object parsed from this context
+     */
+    private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, long highestPosition,
+            List<String> actualPath, final String moduleName, final URI namespace, final Date revision, final String prefix) {
+        String name = stringFromNode(ctx);
+        final QName qname = new QName(namespace, revision, prefix, name);
+        Long position = null;
+
+        String description = null;
+        String reference = null;
+        Status status = Status.CURRENT;
+
+        Stack<String> bitPath = new Stack<String>();
+        bitPath.addAll(actualPath);
+        bitPath.add(name);
+
+        SchemaPath schemaPath = createActualSchemaPath(bitPath, namespace, revision, prefix);
+
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Position_stmtContext) {
+                String positionStr = stringFromNode(child);
+                position = Long.valueOf(positionStr);
+            } else if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else if (child instanceof Status_stmtContext) {
+                status = parseStatus((Status_stmtContext) child);
+            }
+        }
+
+        if (position == null) {
+            position = highestPosition + 1;
+        }
+        if (position < 0 || position > 4294967295L) {
+            throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
+                    + "': the position value MUST be in the range 0 to 4294967295");
+        }
+
+        final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
+        return new BitImpl(position, qname, schemaPath, description, reference, status, unknownNodes);
+    }
+
+    /**
+     * Parse 'ordered-by' statement.
+     *
+     * The 'ordered-by' statement defines whether the order of entries within a
+     * list are determined by the user or the system. The argument is one of the
+     * strings "system" or "user". If not present, order defaults to "system".
+     *
+     * @param ctx
+     *            Ordered_by_stmtContext
+     * @return true, if ordered-by contains value 'user', false otherwise
+     */
+    public static boolean parseUserOrdered(Ordered_by_stmtContext ctx) {
+        boolean result = false;
+        for (int j = 0; j < ctx.getChildCount(); j++) {
+            ParseTree orderArg = ctx.getChild(j);
+            if (orderArg instanceof Ordered_by_argContext) {
+                String orderStr = stringFromNode(orderArg);
+                if ("system".equals(orderStr)) {
+                    result = false;
+                } else if ("user".equals(orderStr)) {
+                    result = true;
+                } else {
+                    LOG.warn("Invalid 'ordered-by' statement.");
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Get config statement from given context. If there is no config statement,
+     * return config value of parent
+     *
+     * @param ctx
+     *            context to parse
+     * @param parent
+     *            parent node
+     * @param moduleName
+     *            name of current module
+     * @param line
+     *            line in current module
+     * @return config statement parsed from given context
+     */
+    public static Boolean getConfig(final ParseTree ctx, final Builder parent, final String moduleName, final int line) {
+        Boolean result = null;
+        // parse configuration statement
+        Boolean config = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Config_stmtContext) {
+                config = parseConfig((Config_stmtContext) child, moduleName);
+                break;
+            }
+        }
+
+        // If 'config' is not specified, the default is the same as the parent
+        // schema node's 'config' value
+        if (config == null) {
+            if (parent instanceof DataSchemaNodeBuilder) {
+                Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
+                // If the parent node is a rpc input or output, it can has
+                // config set to null
+                result = parentConfig == null ? true : parentConfig;
+            } else if (parent instanceof ChoiceCaseBuilder) {
+                // If the parent node is a 'case' node, the value is the same as
+                // the 'case' node's parent 'choice' node
+                ChoiceCaseBuilder choiceCase = (ChoiceCaseBuilder) parent;
+                Builder choice = choiceCase.getParent();
+                Boolean parentConfig = null;
+                if (choice instanceof ChoiceBuilder) {
+                    parentConfig = ((ChoiceBuilder) choice).isConfiguration();
+                } else {
+                    parentConfig = true;
+                }
+                result = parentConfig;
+            } else {
+                result = true;
+            }
+        } else {
+            // Check first: if a node has 'config' set to 'false', no node
+            // underneath it can have 'config' set to 'true'
+            if (parent instanceof DataSchemaNodeBuilder && !(parent instanceof ChoiceCaseBuilder)) {
+                Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
+                if (!parentConfig && config) {
+                    throw new YangParseException(moduleName, line,
+                            "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
+                }
+            }
+            result = config;
+        }
+
+        return result;
+    }
+
+    /**
+     * Parse config statement.
+     *
+     * @param ctx
+     *            config context to parse
+     * @param moduleName current module name
+     * @return true if given context contains string 'true', false otherwise
+     */
+    private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
+        Boolean result = null;
+        if (ctx != null) {
+            for (int i = 0; i < ctx.getChildCount(); ++i) {
+                final ParseTree configContext = ctx.getChild(i);
+                if (configContext instanceof Config_argContext) {
+                    final String value = stringFromNode(configContext);
+                    if ("true".equals(value)) {
+                        result = true;
+                        break;
+                    } else if ("false".equals(value)) {
+                        result = false;
+                        break;
+                    } else {
+                        throw new YangParseException(moduleName, ctx.getStart().getLine(),
+                                "Failed to parse 'config' statement value: '" + value + "'.");
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse type body and create UnknownType definition.
+     *
+     * @param typedefQName
+     *            qname of current type
+     * @param ctx
+     *            type body
+     * @param actualPath
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @param parent
+     * @return UnknownType object with constraints from parsed type body
+     */
+    public static TypeDefinition<?> parseUnknownTypeWithBody(final QName typedefQName,
+            final Type_body_stmtsContext ctx, final List<String> actualPath, final URI namespace, final Date revision,
+            final String prefix, final Builder parent) {
+        String moduleName = parent.getModuleName();
+        String typeName = typedefQName.getLocalName();
+
+        UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName);
+
+        if (ctx != null) {
+            List<RangeConstraint> rangeStatements = getRangeConstraints(ctx, moduleName);
+            List<LengthConstraint> lengthStatements = getLengthConstraints(ctx, moduleName);
+            List<PatternConstraint> patternStatements = getPatternConstraint(ctx);
+            Integer fractionDigits = getFractionDigits(ctx, moduleName);
+
+            if (parent instanceof TypeDefinitionBuilder) {
+                TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
+                typedef.setRanges(rangeStatements);
+                typedef.setLengths(lengthStatements);
+                typedef.setPatterns(patternStatements);
+                typedef.setFractionDigits(fractionDigits);
+                return unknownType.build();
+            } else {
+                TypeDefinition<?> baseType = unknownType.build();
+                TypeDefinition<?> result = null;
+                QName qname = new QName(namespace, revision, prefix, typeName);
+                SchemaPath schemaPath = createTypeSchemaPath(actualPath, namespace, revision, prefix, typeName, false,
+                        false);
+
+                ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, null, null, schemaPath);
+                typeBuilder.ranges(rangeStatements);
+                typeBuilder.lengths(lengthStatements);
+                typeBuilder.patterns(patternStatements);
+                typeBuilder.fractionDigits(fractionDigits);
+                result = typeBuilder.build();
+
+                return result;
+            }
+        }
+
+        return unknownType.build();
+    }
+
+    /**
+     * Create TypeDefinition object based on given type name and type body.
+     *
+     * @param typeName
+     *            name of type
+     * @param typeBody
+     *            type body context
+     * @param actualPath
+     *            current path in schema
+     * @param namespace
+     *            current namespace
+     * @param revision
+     *            current revision
+     * @param prefix
+     *            current prefix
+     * @param parent
+     *            parent builder
+     * @return TypeDefinition object based on parsed values.
+     */
+    public static TypeDefinition<?> parseTypeWithBody(final String typeName,
+            final Type_body_stmtsContext typeBody, final List<String> actualPath, final URI namespace,
+            final Date revision, final String prefix, final Builder parent) {
+        final String moduleName = parent.getModuleName();
+        final int line = typeBody.getStart().getLine();
+        TypeDefinition<?> baseType = null;
+
+        Integer fractionDigits = getFractionDigits(typeBody, moduleName);
+        List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
+        List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);
+        List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
+
+        TypeConstraints constraints = new TypeConstraints(moduleName, line);
+        constraints.addFractionDigits(fractionDigits);
+        constraints.addLengths(lengthStatements);
+        constraints.addPatterns(patternStatements);
+        constraints.addRanges(rangeStatements);
+
+        SchemaPath baseTypePathFinal = createTypeSchemaPath(actualPath, namespace, revision, prefix, typeName, true,
+                true);
+        SchemaPath baseTypePath = createTypeSchemaPath(actualPath, namespace, revision, prefix, typeName, true, false);
+
+        if ("decimal64".equals(typeName)) {
+            if (rangeStatements.isEmpty()) {
+                return new Decimal64(baseTypePathFinal, fractionDigits);
+            }
+            Decimal64 decimalType = new Decimal64(baseTypePath, fractionDigits);
+            constraints.addRanges(decimalType.getRangeStatements());
+            baseType = decimalType;
+        } else if (typeName.startsWith("int")) {
+            IntegerTypeDefinition intType = null;
+            if ("int8".equals(typeName)) {
+                intType = new Int8(baseTypePath);
+            } else if ("int16".equals(typeName)) {
+                intType = new Int16(baseTypePath);
+            } else if ("int32".equals(typeName)) {
+                intType = new Int32(baseTypePath);
+            } else if ("int64".equals(typeName)) {
+                intType = new Int64(baseTypePath);
+            }
+            if (intType == null) {
+                throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
+            }
+            constraints.addRanges(intType.getRangeStatements());
+            baseType = intType;
+        } else if (typeName.startsWith("uint")) {
+            UnsignedIntegerTypeDefinition uintType = null;
+            if ("uint8".equals(typeName)) {
+                uintType = new Uint8(baseTypePath);
+            } else if ("uint16".equals(typeName)) {
+                uintType = new Uint16(baseTypePath);
+            } else if ("uint32".equals(typeName)) {
+                uintType = new Uint32(baseTypePath);
+            } else if ("uint64".equals(typeName)) {
+                uintType = new Uint64(baseTypePath);
+            }
+            if (uintType == null) {
+                throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
+            }
+            constraints.addRanges(uintType.getRangeStatements());
+            baseType = uintType;
+        } else if ("enumeration".equals(typeName)) {
+            List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName, namespace,
+                    revision, prefix);
+            return new EnumerationType(baseTypePathFinal, enumConstants);
+        } else if ("string".equals(typeName)) {
+            StringTypeDefinition stringType = new StringType(baseTypePath);
+            constraints.addLengths(stringType.getLengthStatements());
+            baseType = stringType;
+        } else if ("bits".equals(typeName)) {
+            return new BitsType(baseTypePathFinal, getBits(typeBody, actualPath, moduleName, namespace, revision, prefix));
+        } else if ("leafref".equals(typeName)) {
+            final String path = parseLeafrefPath(typeBody);
+            final boolean absolute = path.startsWith("/");
+            RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
+            return new Leafref(baseTypePathFinal, xpath);
+        } else if ("binary".equals(typeName)) {
+            BinaryTypeDefinition binaryType = new BinaryType(baseTypePath);
+            constraints.addLengths(binaryType.getLengthConstraints());
+            baseType = binaryType;
+        } else if ("instance-identifier".equals(typeName)) {
+            boolean requireInstance = isRequireInstance(typeBody);
+            return new InstanceIdentifier(baseTypePath, null, requireInstance);
+        }
+
+        if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
+            TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
+            typedef.setRanges(constraints.getRange());
+            typedef.setLengths(constraints.getLength());
+            typedef.setPatterns(constraints.getPatterns());
+            typedef.setFractionDigits(constraints.getFractionDigits());
+            return baseType;
+        }
+
+        TypeDefinition<?> result = null;
+        QName qname = new QName(namespace, revision, prefix, typeName);
+        ExtendedType.Builder typeBuilder = null;
+
+        SchemaPath schemaPath = createTypeSchemaPath(actualPath, namespace, revision, prefix, typeName, false, false);
+        typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
+
+        typeBuilder.ranges(constraints.getRange());
+        typeBuilder.lengths(constraints.getLength());
+        typeBuilder.patterns(constraints.getPatterns());
+        typeBuilder.fractionDigits(constraints.getFractionDigits());
+
+        result = typeBuilder.build();
+        return result;
+    }
+
+    /**
+     * Create SchemaPath object from given path list with namespace, revision
+     * and prefix based on given values.
+     *
+     * @param actualPath
+     *            current position in model
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @param typeName
+     * @param isBaseYangType
+     *            if this is base yang type
+     * @param isBaseYangTypeFinal
+     *            if this is base yang type without restrictions
+     * @return SchemaPath object.
+     */
+    private static SchemaPath createTypeSchemaPath(final List<String> actualPath, final URI namespace,
+            final Date revision, final String prefix, final String typeName, final boolean isBaseYangType,
+            final boolean isBaseYangTypeFinal) {
+        List<String> typePath = new ArrayList<String>(actualPath);
+        if (isBaseYangType && !isBaseYangTypeFinal) {
+            typePath.add(typeName);
+        }
+
+        final List<QName> path = new ArrayList<QName>();
+        QName qname;
+        // start from index 1 -> module name omited
+        for (int i = 1; i < typePath.size(); i++) {
+            qname = new QName(namespace, revision, prefix, typePath.get(i));
+            path.add(qname);
+        }
+        QName typeQName;
+        if (isBaseYangType) {
+            typeQName = new QName(BaseTypes.BaseTypesNamespace, typeName);
+        } else {
+            typeQName = new QName(namespace, revision, prefix, typeName);
+        }
+        path.add(typeQName);
+        return new SchemaPath(path, true);
+    }
+
+    /**
+     * Parse given context and find identityref base value.
+     *
+     * @param ctx
+     *            type body
+     * @return identityref base value as String
+     */
+    public static String getIdentityrefBase(Type_body_stmtsContext ctx) {
+        String result = null;
+        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Identityref_specificationContext) {
+                for (int j = 0; j < child.getChildCount(); j++) {
+                    ParseTree baseArg = child.getChild(j);
+                    if (baseArg instanceof Base_stmtContext) {
+                        result = stringFromNode(baseArg);
+                        break outer;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Parse type body statement and find require-instance value.
+     *
+     * @param ctx
+     *            type body context
+     * @return require-instance value
+     */
+    private static boolean isRequireInstance(Type_body_stmtsContext ctx) {
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Instance_identifier_specificationContext) {
+                for (int j = 0; j < child.getChildCount(); j++) {
+                    ParseTree reqStmt = child.getChild(j);
+                    if (reqStmt instanceof Require_instance_stmtContext) {
+                        for (int k = 0; k < reqStmt.getChildCount(); k++) {
+                            ParseTree reqArg = reqStmt.getChild(k);
+                            if (reqArg instanceof Require_instance_argContext) {
+                                return Boolean.valueOf(stringFromNode(reqArg));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Parse type body statement and find leafref path.
+     *
+     * @param ctx
+     *            type body context
+     * @return leafref path as String
+     */
+    private static String parseLeafrefPath(Type_body_stmtsContext ctx) {
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof Leafref_specificationContext) {
+                for (int j = 0; j < child.getChildCount(); j++) {
+                    ParseTree leafRefSpec = child.getChild(j);
+                    if (leafRefSpec instanceof Path_stmtContext) {
+                        return stringFromNode(leafRefSpec);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Internal helper method for parsing must statement.
+     *
+     * @param ctx
+     *            Must_stmtContext
+     * @return MustDefinition object based on parsed context
+     */
+    public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
+        StringBuilder mustText = new StringBuilder();
+        String description = null;
+        String reference = null;
+        String errorAppTag = null;
+        String errorMessage = null;
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            ParseTree child = ctx.getChild(i);
+            if (child instanceof StringContext) {
+                final StringContext context = (StringContext) child;
+                if (context.getChildCount() == 1) {
+                    String mustPart = context.getChild(0).getText();
+                    // trim start and end quotation
+                    mustText.append(mustPart.substring(1, mustPart.length() - 1));
+                } else {
+                    for (int j = 0; j < context.getChildCount(); j++) {
+                        String mustPart = context.getChild(j).getText();
+                        if (j == 0) {
+                            mustText.append(mustPart.substring(0, mustPart.length() - 1));
+                            continue;
+                        }
+                        if (j % 2 == 0) {
+                            mustText.append(mustPart.substring(1));
+                        }
+                    }
+                }
+            } else if (child instanceof Description_stmtContext) {
+                description = stringFromNode(child);
+            } else if (child instanceof Reference_stmtContext) {
+                reference = stringFromNode(child);
+            } else if (child instanceof Error_app_tag_stmtContext) {
+                errorAppTag = stringFromNode(child);
+            } else if (child instanceof Error_message_stmtContext) {
+                errorMessage = stringFromNode(child);
+            }
+        }
+
+        MustDefinition must = new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag,
+                errorMessage);
+        return must;
+    }
+
+    /**
+     * Parse given context and set constraints to constraints builder.
+     *
+     * @param ctx
+     *            context to parse
+     * @param constraints
+     *            ConstraintsBuilder to fill
+     */
+    public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree childNode = ctx.getChild(i);
+            if (childNode instanceof Max_elements_stmtContext) {
+                Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
+                constraints.setMaxElements(max);
+            } else if (childNode instanceof Min_elements_stmtContext) {
+                Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
+                constraints.setMinElements(min);
+            } else if (childNode instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) childNode);
+                constraints.addMustDefinition(must);
+            } else if (childNode instanceof Mandatory_stmtContext) {
+                for (int j = 0; j < childNode.getChildCount(); j++) {
+                    ParseTree mandatoryTree = ctx.getChild(j);
+                    if (mandatoryTree instanceof Mandatory_argContext) {
+                        Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
+                        constraints.setMandatory(mandatory);
+                    }
+                }
+            } else if (childNode instanceof When_stmtContext) {
+                constraints.addWhenCondition(stringFromNode(childNode));
+            }
+        }
+    }
+
+    private static Integer parseMinElements(Min_elements_stmtContext ctx, String moduleName) {
+        Integer result = null;
+        try {
+            for (int i = 0; i < ctx.getChildCount(); i++) {
+                ParseTree minArg = ctx.getChild(i);
+                if (minArg instanceof Min_value_argContext) {
+                    result = Integer.valueOf(stringFromNode(minArg));
+                }
+            }
+            if (result == null) {
+                throw new IllegalArgumentException();
+            }
+            return result;
+        } catch (Exception e) {
+            throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
+        }
+    }
+
+    private static Integer parseMaxElements(Max_elements_stmtContext ctx, String moduleName) {
+        Integer result = null;
+        try {
+            for (int i = 0; i < ctx.getChildCount(); i++) {
+                ParseTree maxArg = ctx.getChild(i);
+                if (maxArg instanceof Max_value_argContext) {
+                    result = Integer.valueOf(stringFromNode(maxArg));
+                }
+            }
+            if (result == null) {
+                throw new IllegalArgumentException();
+            }
+            return result;
+        } catch (Exception e) {
+            throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
+        }
+    }
+
+    /**
+     * Parse given context and return yin value.
+     *
+     * @param ctx
+     *            context to parse
+     * @return true if value is 'true', false otherwise
+     */
+    public static boolean parseYinValue(Argument_stmtContext ctx) {
+        boolean yinValue = false;
+        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+            ParseTree yin = ctx.getChild(i);
+            if (yin instanceof Yin_element_stmtContext) {
+                for (int j = 0; j < yin.getChildCount(); j++) {
+                    ParseTree yinArg = yin.getChild(j);
+                    if (yinArg instanceof Yin_element_argContext) {
+                        String yinString = stringFromNode(yinArg);
+                        if ("true".equals(yinString)) {
+                            yinValue = true;
+                            break outer;
+                        }
+                    }
+                }
+            }
+        }
+        return yinValue;
+    }
+
+    /**
+     * Check this base type.
+     *
+     * @param typeName
+     *            base YANG type name
+     * @param moduleName
+     *            name of current module
+     * @param line
+     *            line in module
+     * @throws YangParseException
+     *             if this is one of YANG type which MUST contain additional
+     *             informations in its body
+     */
+    public static void checkMissingBody(final String typeName, final String moduleName, final int line)
+            throws YangParseException {
+        if ("decimal64".equals(typeName)) {
+            throw new YangParseException(moduleName, line,
+                    "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
+        } else if ("identityref".equals(typeName)) {
+            throw new YangParseException(moduleName, line,
+                    "The 'base' statement MUST be present if the type is 'identityref'.");
+        } else if ("leafref".equals(typeName)) {
+            throw new YangParseException(moduleName, line,
+                    "The 'path' statement MUST be present if the type is 'leafref'.");
+        } else if ("bits".equals(typeName)) {
+            throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
+        } else if ("enumeration".equals(typeName)) {
+            throw new YangParseException(moduleName, line,
+                    "The 'enum' statement MUST be present if the type is 'enumeration'.");
+        }
+    }
+
+    /**
+     * Parse refine statement.
+     *
+     * @param refineCtx
+     *            refine statement
+     * @return RefineHolder object representing this refine statement
+     */
+    public static RefineHolder parseRefine(Refine_stmtContext refineCtx, String moduleName) {
+        final String refineTarget = stringFromNode(refineCtx);
+        final RefineHolder refine = new RefineHolder(moduleName, refineCtx.getStart().getLine(), refineTarget);
+        for (int i = 0; i < refineCtx.getChildCount(); i++) {
+            ParseTree refinePom = refineCtx.getChild(i);
+            if (refinePom instanceof Refine_pomContext) {
+                for (int j = 0; j < refinePom.getChildCount(); j++) {
+                    ParseTree refineStmt = refinePom.getChild(j);
+                    parseRefineDefault(refine, refineStmt);
+
+                    if (refineStmt instanceof Refine_leaf_stmtsContext) {
+                        parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
+                    } else if (refineStmt instanceof Refine_container_stmtsContext) {
+                        parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
+                    } else if (refineStmt instanceof Refine_list_stmtsContext) {
+                        parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
+                    } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
+                        parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
+                    } else if (refineStmt instanceof Refine_choice_stmtsContext) {
+                        parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
+                    } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
+                        parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
+                    }
+                }
+            }
+        }
+        return refine;
+    }
+
+    private static void parseRefineDefault(RefineHolder refine, ParseTree refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Description_stmtContext) {
+                String description = stringFromNode(refineArg);
+                refine.setDescription(description);
+            } else if (refineArg instanceof Reference_stmtContext) {
+                String reference = stringFromNode(refineArg);
+                refine.setReference(reference);
+            } else if (refineArg instanceof Config_stmtContext) {
+                Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
+                refine.setConfiguration(config);
+            }
+        }
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Default_stmtContext) {
+                String defaultStr = stringFromNode(refineArg);
+                refine.setDefaultStr(defaultStr);
+            } else if (refineArg instanceof Mandatory_stmtContext) {
+                for (int j = 0; j < refineArg.getChildCount(); j++) {
+                    ParseTree mandatoryTree = refineArg.getChild(j);
+                    if (mandatoryTree instanceof Mandatory_argContext) {
+                        Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
+                        refine.setMandatory(mandatory);
+                    }
+                }
+            } else if (refineArg instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) refineArg);
+                refine.setMust(must);
+
+            }
+        }
+        return refine;
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_container_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) refineArg);
+                refine.setMust(must);
+            } else if (refineArg instanceof Presence_stmtContext) {
+                refine.setPresence(true);
+            }
+        }
+        return refine;
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_list_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) refineArg);
+                refine.setMust(must);
+            } else if (refineArg instanceof Max_elements_stmtContext) {
+                Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
+                refine.setMaxElements(max);
+            } else if (refineArg instanceof Min_elements_stmtContext) {
+                Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
+                refine.setMinElements(min);
+            }
+        }
+        return refine;
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_list_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) refineArg);
+                refine.setMust(must);
+            } else if (refineArg instanceof Max_elements_stmtContext) {
+                Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
+                refine.setMaxElements(max);
+            } else if (refineArg instanceof Min_elements_stmtContext) {
+                Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
+                refine.setMinElements(min);
+            }
+        }
+        return refine;
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_choice_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Default_stmtContext) {
+                String defaultStr = stringFromNode(refineArg);
+                refine.setDefaultStr(defaultStr);
+            } else if (refineArg instanceof Mandatory_stmtContext) {
+                for (int j = 0; j < refineArg.getChildCount(); j++) {
+                    ParseTree mandatoryTree = refineArg.getChild(j);
+                    if (mandatoryTree instanceof Mandatory_argContext) {
+                        Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
+                        refine.setMandatory(mandatory);
+                    }
+                }
+            }
+        }
+        return refine;
+    }
+
+    private static RefineHolder parseRefine(RefineHolder refine, Refine_anyxml_stmtsContext refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Must_stmtContext) {
+                MustDefinition must = parseMust((Must_stmtContext) refineArg);
+                refine.setMust(must);
+            } else if (refineArg instanceof Mandatory_stmtContext) {
+                for (int j = 0; j < refineArg.getChildCount(); j++) {
+                    ParseTree mandatoryTree = refineArg.getChild(j);
+                    if (mandatoryTree instanceof Mandatory_argContext) {
+                        Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
+                        refine.setMandatory(mandatory);
+                    }
+                }
+            }
+        }
+        return refine;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserUtils.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserUtils.java
new file mode 100644 (file)
index 0000000..4fc58b3
--- /dev/null
@@ -0,0 +1,1299 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataNodeContainer;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.SchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.controller.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.opendaylight.controller.yang.model.util.BinaryType;
+import org.opendaylight.controller.yang.model.util.BitsType;
+import org.opendaylight.controller.yang.model.util.BooleanType;
+import org.opendaylight.controller.yang.model.util.Decimal64;
+import org.opendaylight.controller.yang.model.util.EmptyType;
+import org.opendaylight.controller.yang.model.util.EnumerationType;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.IdentityrefType;
+import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
+import org.opendaylight.controller.yang.model.util.Int16;
+import org.opendaylight.controller.yang.model.util.Int32;
+import org.opendaylight.controller.yang.model.util.Int64;
+import org.opendaylight.controller.yang.model.util.Int8;
+import org.opendaylight.controller.yang.model.util.Leafref;
+import org.opendaylight.controller.yang.model.util.StringType;
+import org.opendaylight.controller.yang.model.util.Uint16;
+import org.opendaylight.controller.yang.model.util.Uint32;
+import org.opendaylight.controller.yang.model.util.Uint64;
+import org.opendaylight.controller.yang.model.util.Uint8;
+import org.opendaylight.controller.yang.model.util.UnionType;
+import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingMember;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder.ChoiceNodeImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder.ChoiceCaseNodeImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.ConstraintsBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder.ContainerSchemaNodeImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder.ListSchemaNodeImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder.NotificationDefinitionImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+
+public final class ParserUtils {
+
+    private ParserUtils() {
+    }
+
+    /**
+     * Create new SchemaPath from given path and name.
+     *
+     * Append new qname to schema path created from name argument. New QName
+     * gets namespace, revision and prefix same as last qname in current schema
+     * path.
+     *
+     * @param schemaPath
+     * @param name
+     * @return
+     */
+    public static SchemaPath createSchemaPath(SchemaPath schemaPath, String name, URI namespace, Date revision, String prefix) {
+        List<QName> path = new ArrayList<QName>();
+        if(schemaPath != null) {
+            path.addAll(schemaPath.getPath());
+        }
+        QName newQName = new QName(namespace, revision, prefix, name);
+        path.add(newQName);
+        boolean abs = schemaPath == null ? true : schemaPath.isAbsolute();
+        return new SchemaPath(path, abs);
+    }
+
+    /**
+     * Get module import referenced by given prefix.
+     *
+     * @param builder
+     *            module to search
+     * @param prefix
+     *            prefix associated with import
+     * @return ModuleImport based on given prefix
+     */
+    public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
+        ModuleImport moduleImport = null;
+        for (ModuleImport mi : builder.getModuleImports()) {
+            if (mi.getPrefix().equals(prefix)) {
+                moduleImport = mi;
+                break;
+            }
+        }
+        return moduleImport;
+    }
+
+    /**
+     * Find dependent module based on given prefix
+     *
+     * @param modules
+     *            all available modules
+     * @param module
+     *            current module
+     * @param prefix
+     *            target module prefix
+     * @param line
+     *            current line in yang model
+     * @return
+     */
+    public static ModuleBuilder findDependentModuleBuilder(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final String prefix, final int line) {
+        ModuleBuilder dependentModule = null;
+        Date dependentModuleRevision = null;
+
+        if (prefix.equals(module.getPrefix())) {
+            dependentModule = module;
+        } else {
+            final ModuleImport dependentModuleImport = getModuleImport(module, prefix);
+            if (dependentModuleImport == null) {
+                throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
+            }
+            final String dependentModuleName = dependentModuleImport.getModuleName();
+            dependentModuleRevision = dependentModuleImport.getRevision();
+
+            final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
+            if (moduleBuildersByRevision == null) {
+                return null;
+            }
+            if (dependentModuleRevision == null) {
+                dependentModule = moduleBuildersByRevision.lastEntry().getValue();
+            } else {
+                dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
+            }
+        }
+        return dependentModule;
+    }
+
+    /**
+     * Find module from context based on prefix.
+     *
+     * @param context
+     *            schema context
+     * @param currentModule
+     *            current module
+     * @param prefix
+     *            current prefix used to reference dependent module
+     * @param line
+     *            current line in yang model
+     * @return module based on given prefix if found in context, null otherwise
+     */
+    public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
+            final String prefix, final int line) {
+        TreeMap<Date, Module> modulesByRevision = new TreeMap<Date, Module>();
+
+        Date dependentModuleRevision = null;
+
+        final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
+        if (dependentModuleImport == null) {
+            throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
+        }
+        final String dependentModuleName = dependentModuleImport.getModuleName();
+        dependentModuleRevision = dependentModuleImport.getRevision();
+
+        for (Module contextModule : context.getModules()) {
+            if (contextModule.getName().equals(dependentModuleName)) {
+                Date revision = contextModule.getRevision();
+                if (revision == null) {
+                    revision = new Date(0L);
+                }
+                modulesByRevision.put(revision, contextModule);
+                break;
+            }
+        }
+
+        Module result = null;
+        if (dependentModuleRevision == null) {
+            result = modulesByRevision.get(modulesByRevision.firstKey());
+        } else {
+            result = modulesByRevision.get(dependentModuleRevision);
+        }
+
+        return result;
+    }
+
+    /**
+     * Find grouping by name.
+     *
+     * @param groupings
+     *            collection of grouping builders to search
+     * @param name
+     *            name of grouping
+     * @return grouping with given name if present in collection, null otherwise
+     */
+    public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
+        for (GroupingBuilder grouping : groupings) {
+            if (grouping.getQName().getLocalName().equals(name)) {
+                return grouping;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find grouping by name.
+     *
+     * @param groupings
+     *            collection of grouping definitions to search
+     * @param name
+     *            name of grouping
+     * @return grouping with given name if present in collection, null otherwise
+     */
+    public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
+        for (GroupingDefinition grouping : groupings) {
+            if (grouping.getQName().getLocalName().equals(name)) {
+                return grouping;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Search types for type with given name.
+     *
+     * @param types
+     *            types to search
+     * @param name
+     *            name of type
+     * @return type with given name if present in collection, null otherwise
+     */
+    public static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
+        for (TypeDefinitionBuilder td : types) {
+            if (td.getQName().getLocalName().equals(name)) {
+                return td;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find type by name.
+     *
+     * @param types
+     *            collection of types
+     * @param typeName
+     *            type name
+     * @return type with given name if it is present in collection, null
+     *         otherwise
+     */
+    public static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
+        for (TypeDefinition<?> type : types) {
+            if (type.getQName().getLocalName().equals(typeName)) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parse uses path.
+     *
+     * @param usesPath
+     *            as String
+     * @return SchemaPath from given String
+     */
+    public static SchemaPath parseUsesPath(final String usesPath) {
+        final boolean absolute = usesPath.startsWith("/");
+        final String[] splittedPath = usesPath.split("/");
+        final List<QName> path = new ArrayList<QName>();
+        QName name;
+        for (String pathElement : splittedPath) {
+            if (pathElement.length() > 0) {
+                final String[] splittedElement = pathElement.split(":");
+                if (splittedElement.length == 1) {
+                    name = new QName(null, null, null, splittedElement[0]);
+                } else {
+                    name = new QName(null, null, splittedElement[0], splittedElement[1]);
+                }
+                path.add(name);
+            }
+        }
+        return new SchemaPath(path, absolute);
+    }
+
+    /**
+     * Check if node is present in refine nodes.
+     *
+     * @param nodeQName
+     *            qname of node
+     * @param refineNodes
+     *            collections of refined nodes
+     * @return true, if node with given qname was found, false otherwise
+     */
+    public static SchemaNodeBuilder getRefined(QName nodeQName, List<SchemaNodeBuilder> refineNodes) {
+        for (SchemaNodeBuilder rn : refineNodes) {
+            if (rn.getQName().equals(nodeQName)) {
+                return rn;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Pull restriction from type and add them to constraints.
+     *
+     * @param type
+     * @param constraints
+     */
+    public static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
+        if (type instanceof DecimalTypeDefinition) {
+            constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
+            constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
+        } else if (type instanceof IntegerTypeDefinition) {
+            constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
+        } else if (type instanceof StringTypeDefinition) {
+            constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
+            constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
+        } else if (type instanceof BinaryTypeDefinition) {
+            constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
+        }
+    }
+
+    /**
+     * Find node in grouping by name.
+     *
+     * @param grouping
+     *            grouping to search
+     * @param refineNodeName
+     *            name of node
+     * @return builder of node with given name if present in grouping, null
+     *         otherwise
+     */
+    public static Builder findRefineTargetBuilder(final GroupingBuilder grouping, final String refineNodeName) {
+        // search child nodes
+        Builder result = grouping.getDataChildByName(refineNodeName);
+        // search groupings
+        if (result == null) {
+            Set<GroupingBuilder> grps = grouping.getGroupingBuilders();
+            for (GroupingBuilder gr : grps) {
+                if (gr.getQName().getLocalName().equals(refineNodeName)) {
+                    result = gr;
+                    break;
+                }
+            }
+        }
+        // search typedefs
+        if (result == null) {
+            Set<TypeDefinitionBuilder> typedefs = grouping.getTypeDefinitionBuilders();
+            for (TypeDefinitionBuilder typedef : typedefs) {
+                if (typedef.getQName().getLocalName().equals(refineNodeName)) {
+                    result = typedef;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Find node in grouping by name.
+     *
+     * @param builder
+     *            grouping to search
+     * @param refineNodeName
+     *            name of node
+     * @return node with given name if present in grouping, null otherwise
+     */
+    public static Object findRefineTargetNode(final GroupingDefinition builder, final String refineNodeName) {
+        Object result = builder.getDataChildByName(refineNodeName);
+        if (result == null) {
+            Set<GroupingDefinition> grps = builder.getGroupings();
+            for (GroupingDefinition gr : grps) {
+                if (gr.getQName().getLocalName().equals(refineNodeName)) {
+                    result = gr;
+                    break;
+                }
+            }
+        }
+        if (result == null) {
+            Set<TypeDefinition<?>> typedefs = builder.getTypeDefinitions();
+            for (TypeDefinition<?> typedef : typedefs) {
+                if (typedef.getQName().getLocalName().equals(refineNodeName)) {
+                    result = typedef;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Add all augment's child nodes to given target.
+     *
+     * @param augment
+     *            builder of augment statement
+     * @param target
+     *            augmentation target node
+     */
+    public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
+        boolean usesAugment = augment.getParent() instanceof UsesNodeBuilder;
+        for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
+            builder.setAugmenting(true);
+            if (usesAugment) {
+                if (builder instanceof GroupingMember) {
+                    ((GroupingMember) builder).setAddedByUses(true);
+                }
+            }
+            correctAugmentChildPath(builder, target.getPath());
+            target.addChildNode(builder);
+        }
+    }
+
+    /**
+     * Add all augment's child nodes to given target.
+     *
+     * @param augment
+     *            builder of augment statement
+     * @param target
+     *            augmentation target choice node
+     */
+    public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
+        boolean usesAugment = augment.getParent() instanceof UsesNodeBuilder;
+        for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
+            builder.setAugmenting(true);
+            if (usesAugment) {
+                if (builder instanceof GroupingMember) {
+                    ((GroupingMember) builder).setAddedByUses(true);
+                }
+            }
+            correctAugmentChildPath(builder, target.getPath());
+            target.addCase(builder);
+        }
+    }
+
+    private static void correctAugmentChildPath(final DataSchemaNodeBuilder childNode, final SchemaPath parentSchemaPath) {
+        // set correct path
+        List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
+        targetNodePath.add(childNode.getQName());
+        childNode.setPath(new SchemaPath(targetNodePath, true));
+
+        // set correct path for all child nodes
+        if (childNode instanceof DataNodeContainerBuilder) {
+            DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) childNode;
+            for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
+                correctAugmentChildPath(child, childNode.getPath());
+            }
+        }
+
+        // set correct path for all cases
+        if (childNode instanceof ChoiceBuilder) {
+            ChoiceBuilder choiceBuilder = (ChoiceBuilder) childNode;
+            for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
+                correctAugmentChildPath(choiceCaseBuilder, childNode.getPath());
+            }
+        }
+
+        // if node can contains type, correct path for this type too
+        if (childNode instanceof TypeAwareBuilder) {
+            TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) childNode;
+            correctTypeAwareNodePath(nodeBuilder, parentSchemaPath);
+        }
+    }
+
+    /**
+     * Repair schema path of node type.
+     *
+     * @param node
+     *            node which contains type statement
+     * @param parentSchemaPath
+     *            schema path of parent node
+     */
+    private static void correctTypeAwareNodePath(final TypeAwareBuilder node, final SchemaPath parentSchemaPath) {
+        final QName nodeBuilderQName = node.getQName();
+        final TypeDefinition<?> nodeType = node.getType();
+
+        Integer fd = null;
+        List<LengthConstraint> lengths = null;
+        List<PatternConstraint> patterns = null;
+        List<RangeConstraint> ranges = null;
+
+        if (nodeType != null) {
+            if (nodeType instanceof ExtendedType) {
+                ExtendedType et = (ExtendedType) nodeType;
+                if (nodeType.getQName().getLocalName().equals(nodeType.getBaseType().getQName().getLocalName())) {
+                    fd = et.getFractionDigits();
+                    lengths = et.getLengths();
+                    patterns = et.getPatterns();
+                    ranges = et.getRanges();
+                    if (!hasConstraints(fd, lengths, patterns, ranges)) {
+                        return;
+                    }
+                }
+            }
+            TypeDefinition<?> newType = createCorrectTypeDefinition(parentSchemaPath, nodeBuilderQName, nodeType);
+            node.setType(newType);
+        } else {
+            TypeDefinitionBuilder nodeBuilderTypedef = node.getTypedef();
+
+            fd = nodeBuilderTypedef.getFractionDigits();
+            lengths = nodeBuilderTypedef.getLengths();
+            patterns = nodeBuilderTypedef.getPatterns();
+            ranges = nodeBuilderTypedef.getRanges();
+
+            String tdbTypeName = nodeBuilderTypedef.getQName().getLocalName();
+            String baseTypeName = null;
+            if (nodeBuilderTypedef.getType() == null) {
+                baseTypeName = nodeBuilderTypedef.getTypedef().getQName().getLocalName();
+            } else {
+                baseTypeName = nodeBuilderTypedef.getType().getQName().getLocalName();
+            }
+            if (!(tdbTypeName.equals(baseTypeName))) {
+                return;
+            }
+
+            if (!hasConstraints(fd, lengths, patterns, ranges)) {
+                return;
+            }
+
+            SchemaPath newSchemaPath = createNewSchemaPath(nodeBuilderTypedef.getPath(), nodeBuilderQName,
+                    nodeBuilderTypedef.getQName());
+            nodeBuilderTypedef.setPath(newSchemaPath);
+        }
+    }
+
+    /**
+     * Check if there are some constraints.
+     *
+     * @param fd
+     *            fraction digits
+     * @param lengths
+     *            length constraints
+     * @param patterns
+     *            pattern constraints
+     * @param ranges
+     *            range constraints
+     * @return true, if any of constraints are present, false otherwise
+     */
+    private static boolean hasConstraints(final Integer fd, final List<LengthConstraint> lengths,
+            final List<PatternConstraint> patterns, final List<RangeConstraint> ranges) {
+        if (fd == null && (lengths == null || lengths.isEmpty()) && (patterns == null || patterns.isEmpty())
+                && (ranges == null || ranges.isEmpty())) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private static TypeDefinition<?> createCorrectTypeDefinition(SchemaPath parentSchemaPath, QName nodeQName,
+            TypeDefinition<?> nodeType) {
+        TypeDefinition<?> result = null;
+
+        if (nodeType != null) {
+            QName nodeTypeQName = nodeType.getQName();
+            SchemaPath newSchemaPath = createNewSchemaPath(parentSchemaPath, nodeQName, nodeTypeQName);
+
+            if (nodeType instanceof BinaryTypeDefinition) {
+                BinaryTypeDefinition binType = (BinaryTypeDefinition) nodeType;
+
+                // List<Byte> bytes = (List<Byte>) binType.getDefaultValue();
+                // workaround to get rid of 'Unchecked cast' warning
+                List<Byte> bytes = new ArrayList<Byte>();
+                Object defaultValue = binType.getDefaultValue();
+                if (defaultValue instanceof List) {
+                    for (Object o : List.class.cast(defaultValue)) {
+                        if (o instanceof Byte) {
+                            bytes.add((Byte) o);
+                        }
+                    }
+                }
+                result = new BinaryType(newSchemaPath, bytes);
+            } else if (nodeType instanceof BitsTypeDefinition) {
+                BitsTypeDefinition bitsType = (BitsTypeDefinition) nodeType;
+                result = new BitsType(newSchemaPath, bitsType.getBits());
+            } else if (nodeType instanceof BooleanTypeDefinition) {
+                result = new BooleanType(newSchemaPath);
+            } else if (nodeType instanceof DecimalTypeDefinition) {
+                DecimalTypeDefinition decimalType = (DecimalTypeDefinition) nodeType;
+                result = new Decimal64(newSchemaPath, decimalType.getFractionDigits());
+            } else if (nodeType instanceof EmptyTypeDefinition) {
+                result = new EmptyType(newSchemaPath);
+            } else if (nodeType instanceof EnumTypeDefinition) {
+                EnumTypeDefinition enumType = (EnumTypeDefinition) nodeType;
+                result = new EnumerationType(newSchemaPath, (EnumPair) enumType.getDefaultValue(), enumType.getValues());
+            } else if (nodeType instanceof IdentityrefTypeDefinition) {
+                IdentityrefTypeDefinition idrefType = (IdentityrefTypeDefinition) nodeType;
+                result = new IdentityrefType(idrefType.getIdentity(), newSchemaPath);
+            } else if (nodeType instanceof InstanceIdentifierTypeDefinition) {
+                InstanceIdentifierTypeDefinition instIdType = (InstanceIdentifierTypeDefinition) nodeType;
+                return new InstanceIdentifier(newSchemaPath, instIdType.getPathStatement(),
+                        instIdType.requireInstance());
+            } else if (nodeType instanceof StringTypeDefinition) {
+                result = createNewStringType(parentSchemaPath, nodeQName, (StringTypeDefinition) nodeType);
+            } else if (nodeType instanceof IntegerTypeDefinition) {
+                result = createNewIntType(parentSchemaPath, nodeQName, (IntegerTypeDefinition) nodeType);
+            } else if (nodeType instanceof UnsignedIntegerTypeDefinition) {
+                result = createNewUintType(parentSchemaPath, nodeQName, (UnsignedIntegerTypeDefinition) nodeType);
+            } else if (nodeType instanceof LeafrefTypeDefinition) {
+                result = new Leafref(newSchemaPath, ((LeafrefTypeDefinition) nodeType).getPathStatement());
+            } else if (nodeType instanceof UnionTypeDefinition) {
+                UnionTypeDefinition unionType = (UnionTypeDefinition) nodeType;
+                return new UnionType(newSchemaPath, unionType.getTypes());
+            } else if (nodeType instanceof ExtendedType) {
+                ExtendedType extType = (ExtendedType) nodeType;
+                result = createNewExtendedType(extType, newSchemaPath);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Create new ExtendedType based on given type and with schema path.
+     *
+     * @param newPath
+     *            schema path for new type
+     * @param oldType
+     *            type based
+     * @return
+     */
+    private static ExtendedType createNewExtendedType(final ExtendedType oldType, final SchemaPath newPath) {
+        QName qname = oldType.getQName();
+        TypeDefinition<?> baseType = oldType.getBaseType();
+        String desc = oldType.getDescription();
+        String ref = oldType.getReference();
+        ExtendedType.Builder builder = new ExtendedType.Builder(qname, baseType, desc, ref, newPath);
+        builder.status(oldType.getStatus());
+        builder.lengths(oldType.getLengths());
+        builder.patterns(oldType.getPatterns());
+        builder.ranges(oldType.getRanges());
+        builder.fractionDigits(oldType.getFractionDigits());
+        builder.unknownSchemaNodes(oldType.getUnknownSchemaNodes());
+        return builder.build();
+    }
+
+    private static StringTypeDefinition createNewStringType(final SchemaPath schemaPath, final QName nodeQName,
+            final StringTypeDefinition nodeType) {
+        final List<QName> path = schemaPath.getPath();
+        final List<QName> newPath = new ArrayList<QName>(path);
+        newPath.add(nodeQName);
+        newPath.add(nodeType.getQName());
+        final SchemaPath newSchemaPath = new SchemaPath(newPath, schemaPath.isAbsolute());
+        return new StringType(newSchemaPath);
+    }
+
+    private static IntegerTypeDefinition createNewIntType(final SchemaPath schemaPath, final QName nodeQName,
+            final IntegerTypeDefinition type) {
+        final QName typeQName = type.getQName();
+        final SchemaPath newSchemaPath = createNewSchemaPath(schemaPath, nodeQName, typeQName);
+        final String localName = typeQName.getLocalName();
+
+        if ("int8".equals(localName)) {
+            return new Int8(newSchemaPath);
+        } else if ("int16".equals(localName)) {
+            return new Int16(newSchemaPath);
+        } else if ("int32".equals(localName)) {
+            return new Int32(newSchemaPath);
+        } else if ("int64".equals(localName)) {
+            return new Int64(newSchemaPath);
+        } else {
+            return null;
+        }
+    }
+
+    private static UnsignedIntegerTypeDefinition createNewUintType(final SchemaPath schemaPath, final QName nodeQName,
+            final UnsignedIntegerTypeDefinition type) {
+        final QName typeQName = type.getQName();
+        final SchemaPath newSchemaPath = createNewSchemaPath(schemaPath, nodeQName, typeQName);
+        final String localName = typeQName.getLocalName();
+
+        if ("uint8".equals(localName)) {
+            return new Uint8(newSchemaPath);
+        } else if ("uint16".equals(localName)) {
+            return new Uint16(newSchemaPath);
+        } else if ("uint32".equals(localName)) {
+            return new Uint32(newSchemaPath);
+        } else if ("uint64".equals(localName)) {
+            return new Uint64(newSchemaPath);
+        } else {
+            return null;
+        }
+    }
+
+    private static SchemaPath createNewSchemaPath(final SchemaPath schemaPath, final QName currentQName,
+            final QName qname) {
+        List<QName> newPath = new ArrayList<QName>(schemaPath.getPath());
+        newPath.add(currentQName);
+        newPath.add(qname);
+        return new SchemaPath(newPath, schemaPath.isAbsolute());
+    }
+
+    /**
+     * Create LeafSchemaNodeBuilder from given LeafSchemaNode.
+     *
+     * @param leaf
+     *            leaf from which to create builder
+     * @param line
+     *            line in module
+     * @return builder object from leaf
+     */
+    public static LeafSchemaNodeBuilder createLeafBuilder(LeafSchemaNode leaf, String moduleName, int line) {
+        final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(moduleName, line, leaf.getQName(),
+                leaf.getPath());
+        convertDataSchemaNode(leaf, builder);
+        builder.setConfiguration(leaf.isConfiguration());
+        final TypeDefinition<?> type = leaf.getType();
+        builder.setType(type);
+        builder.setPath(leaf.getPath());
+        builder.setUnknownNodes(leaf.getUnknownSchemaNodes());
+        builder.setDefaultStr(leaf.getDefault());
+        builder.setUnits(leaf.getUnits());
+        return builder;
+    }
+
+    public static ContainerSchemaNodeBuilder createContainer(ContainerSchemaNode container, String moduleName, int line) {
+        final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(moduleName, line,
+                container.getQName(), container.getPath());
+        convertDataSchemaNode(container, builder);
+        builder.setConfiguration(container.isConfiguration());
+        builder.setUnknownNodes(container.getUnknownSchemaNodes());
+        builder.setChildNodes(container.getChildNodes());
+        builder.setGroupings(container.getGroupings());
+        builder.setTypedefs(container.getTypeDefinitions());
+        builder.setAugmentations(container.getAvailableAugmentations());
+        builder.setUsesnodes(container.getUses());
+        builder.setPresence(container.isPresenceContainer());
+        return builder;
+    }
+
+    public static ListSchemaNodeBuilder createList(ListSchemaNode list, String moduleName, int line) {
+        ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(moduleName, line, list.getQName(), list.getPath());
+        convertDataSchemaNode(list, builder);
+        builder.setConfiguration(list.isConfiguration());
+        builder.setUnknownNodes(list.getUnknownSchemaNodes());
+        builder.setTypedefs(list.getTypeDefinitions());
+        builder.setChildNodes(list.getChildNodes());
+        builder.setGroupings(list.getGroupings());
+        builder.setAugmentations(list.getAvailableAugmentations());
+        builder.setUsesnodes(list.getUses());
+        builder.setUserOrdered(builder.isUserOrdered());
+        return builder;
+    }
+
+    public static LeafListSchemaNodeBuilder createLeafList(LeafListSchemaNode leafList, String moduleName, int line) {
+        final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(moduleName, line, leafList.getQName(),
+                leafList.getPath());
+        convertDataSchemaNode(leafList, builder);
+        builder.setConfiguration(leafList.isConfiguration());
+        builder.setType(leafList.getType());
+        builder.setUnknownNodes(leafList.getUnknownSchemaNodes());
+        builder.setUserOrdered(leafList.isUserOrdered());
+        return builder;
+    }
+
+    public static ChoiceBuilder createChoice(ChoiceNode choice, String moduleName, int line) {
+        final ChoiceBuilder builder = new ChoiceBuilder(moduleName, line, choice.getQName());
+        convertDataSchemaNode(choice, builder);
+        builder.setConfiguration(choice.isConfiguration());
+        builder.setCases(choice.getCases());
+        builder.setUnknownNodes(choice.getUnknownSchemaNodes());
+        builder.setDefaultCase(choice.getDefaultCase());
+        return builder;
+    }
+
+    public static AnyXmlBuilder createAnyXml(AnyXmlSchemaNode anyxml, String moduleName, int line) {
+        final AnyXmlBuilder builder = new AnyXmlBuilder(moduleName, line, anyxml.getQName(), anyxml.getPath());
+        convertDataSchemaNode(anyxml, builder);
+        builder.setConfiguration(anyxml.isConfiguration());
+        builder.setUnknownNodes(anyxml.getUnknownSchemaNodes());
+        return builder;
+    }
+
+    public static GroupingBuilder createGrouping(GroupingDefinition grouping, String moduleName, int line) {
+        final GroupingBuilderImpl builder = new GroupingBuilderImpl(moduleName, line, grouping.getQName());
+        builder.setPath(grouping.getPath());
+        builder.setChildNodes(grouping.getChildNodes());
+        builder.setGroupings(grouping.getGroupings());
+        builder.setTypedefs(grouping.getTypeDefinitions());
+        builder.setUsesnodes(grouping.getUses());
+        builder.setUnknownNodes(grouping.getUnknownSchemaNodes());
+        builder.setDescription(grouping.getDescription());
+        builder.setReference(grouping.getReference());
+        builder.setStatus(grouping.getStatus());
+        return builder;
+    }
+
+    public static TypeDefinitionBuilder createTypedef(ExtendedType typedef, String moduleName, int line) {
+        final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(moduleName, line, typedef.getQName());
+        builder.setPath(typedef.getPath());
+        builder.setDefaultValue(typedef.getDefaultValue());
+        builder.setUnits(typedef.getUnits());
+        builder.setDescription(typedef.getDescription());
+        builder.setReference(typedef.getReference());
+        builder.setStatus(typedef.getStatus());
+        builder.setRanges(typedef.getRanges());
+        builder.setLengths(typedef.getLengths());
+        builder.setPatterns(typedef.getPatterns());
+        builder.setFractionDigits(typedef.getFractionDigits());
+        final TypeDefinition<?> type = typedef.getBaseType();
+        builder.setType(type);
+        builder.setUnits(typedef.getUnits());
+        builder.setUnknownNodes(typedef.getUnknownSchemaNodes());
+        return builder;
+    }
+
+    public static UnknownSchemaNodeBuilder createUnknownSchemaNode(UnknownSchemaNode unknownNode, String moduleName,
+            int line) {
+        final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(moduleName, line, unknownNode.getQName());
+        builder.setPath(unknownNode.getPath());
+        builder.setUnknownNodes(unknownNode.getUnknownSchemaNodes());
+        builder.setDescription(unknownNode.getDescription());
+        builder.setReference(unknownNode.getReference());
+        builder.setStatus(unknownNode.getStatus());
+        builder.setAddedByUses(unknownNode.isAddedByUses());
+        builder.setNodeType(unknownNode.getNodeType());
+        builder.setNodeParameter(unknownNode.getNodeParameter());
+        return builder;
+    }
+
+    /**
+     * Set DataSchemaNode arguments to builder object
+     *
+     * @param node
+     *            node from which arguments should be read
+     * @param builder
+     *            builder to which arguments should be set
+     */
+    private static void convertDataSchemaNode(DataSchemaNode node, DataSchemaNodeBuilder builder) {
+        builder.setPath(node.getPath());
+        builder.setDescription(node.getDescription());
+        builder.setReference(node.getReference());
+        builder.setStatus(node.getStatus());
+        builder.setAugmenting(node.isAugmenting());
+        copyConstraintsFromDefinition(node.getConstraints(), builder.getConstraints());
+    }
+
+    /**
+     * Copy constraints from constraints definition to constraints builder.
+     *
+     * @param nodeConstraints
+     *            definition from which constraints will be copied
+     * @param constraints
+     *            builder to which constraints will be added
+     */
+    private static void copyConstraintsFromDefinition(final ConstraintDefinition nodeConstraints,
+            final ConstraintsBuilder constraints) {
+        final RevisionAwareXPath when = nodeConstraints.getWhenCondition();
+        final Set<MustDefinition> must = nodeConstraints.getMustConstraints();
+
+        if (when != null) {
+            constraints.addWhenCondition(when.toString());
+        }
+        if (must != null) {
+            for (MustDefinition md : must) {
+                constraints.addMustDefinition(md);
+            }
+        }
+        constraints.setMandatory(nodeConstraints.isMandatory());
+        constraints.setMinElements(nodeConstraints.getMinElements());
+        constraints.setMaxElements(nodeConstraints.getMaxElements());
+    }
+
+    public static void processAugmentationOnContext(final AugmentationSchemaBuilder augmentBuilder,
+            final List<QName> path, final ModuleBuilder module, final String prefix, final int line,
+            final SchemaContext context) {
+        final Module dependentModule = findModuleFromContext(context, module, prefix, line);
+        if (dependentModule == null) {
+            throw new YangParseException(module.getName(), line, "Failed to find referenced module with prefix "
+                    + prefix + ".");
+        }
+        SchemaNode node = dependentModule.getDataChildByName(path.get(0).getLocalName());
+        if (node == null) {
+            Set<NotificationDefinition> notifications = dependentModule.getNotifications();
+            for (NotificationDefinition ntf : notifications) {
+                if (ntf.getQName().getLocalName().equals(path.get(0).getLocalName())) {
+                    node = ntf;
+                    break;
+                }
+            }
+        }
+        if (node == null) {
+            return;
+        }
+
+        for (int i = 1; i < path.size(); i++) {
+            if (node instanceof DataNodeContainer) {
+                DataNodeContainer ref = (DataNodeContainer) node;
+                node = ref.getDataChildByName(path.get(i).getLocalName());
+            }
+        }
+        if (node == null) {
+            return;
+        }
+
+        if (node instanceof ContainerSchemaNodeImpl) {
+            // includes container, input and output statement
+            ContainerSchemaNodeImpl c = (ContainerSchemaNodeImpl) node;
+            ContainerSchemaNodeBuilder cb = c.toBuilder();
+            fillAugmentTarget(augmentBuilder, cb);
+            ((AugmentationTargetBuilder) cb).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = cb.getPath();
+            cb.rebuild();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        } else if (node instanceof ListSchemaNodeImpl) {
+            ListSchemaNodeImpl l = (ListSchemaNodeImpl) node;
+            ListSchemaNodeBuilder lb = l.toBuilder();
+            fillAugmentTarget(augmentBuilder, lb);
+            ((AugmentationTargetBuilder) lb).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = lb.getPath();
+            lb.rebuild();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        } else if (node instanceof ChoiceNodeImpl) {
+            ChoiceNodeImpl ch = (ChoiceNodeImpl) node;
+            ChoiceBuilder chb = ch.toBuilder();
+            fillAugmentTarget(augmentBuilder, chb);
+            ((AugmentationTargetBuilder) chb).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = chb.getPath();
+            chb.rebuild();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        } else if (node instanceof ChoiceCaseNodeImpl) {
+            ChoiceCaseNodeImpl chc = (ChoiceCaseNodeImpl) node;
+            ChoiceCaseBuilder chcb = chc.toBuilder();
+            fillAugmentTarget(augmentBuilder, chcb);
+            ((AugmentationTargetBuilder) chcb).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = chcb.getPath();
+            chcb.rebuild();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        } else if (node instanceof NotificationDefinitionImpl) {
+            NotificationDefinitionImpl nd = (NotificationDefinitionImpl) node;
+            NotificationBuilder nb = nd.toBuilder();
+            fillAugmentTarget(augmentBuilder, nb);
+            ((AugmentationTargetBuilder) nb).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = nb.getPath();
+            nb.rebuild();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        } else {
+            throw new YangParseException(module.getName(), line, "Target of type " + node.getClass()
+                    + " cannot be augmented.");
+        }
+    }
+
+    public static void processAugmentation(final AugmentationSchemaBuilder augmentBuilder, final List<QName> path,
+            final ModuleBuilder module, final ModuleBuilder dependentModuleBuilder) {
+        DataSchemaNodeBuilder currentParent = null;
+        for (DataSchemaNodeBuilder child : dependentModuleBuilder.getChildNodeBuilders()) {
+            final QName childQName = child.getQName();
+            if (childQName.getLocalName().equals(path.get(0).getLocalName())) {
+                currentParent = child;
+                break;
+            }
+        }
+
+        if (currentParent == null) {
+            return;
+        }
+
+        for (int i = 1; i < path.size(); i++) {
+            final QName currentQName = path.get(i);
+            DataSchemaNodeBuilder newParent = null;
+            if (currentParent instanceof DataNodeContainerBuilder) {
+                for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent).getChildNodeBuilders()) {
+                    final QName childQName = child.getQName();
+                    if (childQName.getLocalName().equals(currentQName.getLocalName())) {
+                        newParent = child;
+                        break;
+                    }
+                }
+            } else if (currentParent instanceof ChoiceBuilder) {
+                for (ChoiceCaseBuilder caseBuilder : ((ChoiceBuilder) currentParent).getCases()) {
+                    final QName caseQName = caseBuilder.getQName();
+                    if (caseQName.getLocalName().equals(currentQName.getLocalName())) {
+                        newParent = caseBuilder;
+                        break;
+                    }
+                }
+            }
+
+            if (newParent == null) {
+                break; // node not found, quit search
+            } else {
+                currentParent = newParent;
+            }
+        }
+
+        final String currentName = currentParent.getQName().getLocalName();
+        final String lastAugmentPathElementName = path.get(path.size() - 1).getLocalName();
+        if (currentName.equals(lastAugmentPathElementName)) {
+
+            if (currentParent instanceof ChoiceBuilder) {
+                fillAugmentTarget(augmentBuilder, (ChoiceBuilder) currentParent);
+            } else {
+                fillAugmentTarget(augmentBuilder, (DataNodeContainerBuilder) currentParent);
+            }
+            ((AugmentationTargetBuilder) currentParent).addAugmentation(augmentBuilder);
+            SchemaPath oldPath = currentParent.getPath();
+            augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
+            augmentBuilder.setResolved(true);
+            module.augmentResolved();
+        }
+    }
+
+    /**
+     * Create new type builder based on old type with new base type.
+     *
+     * @param newBaseType
+     *            new base type builder
+     * @param oldExtendedType
+     *            old type
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @param line
+     *            current line in module
+     * @return new type builder based on old type with new base type
+     */
+    public static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
+            final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder module, final int line) {
+        final TypeConstraints tc = new TypeConstraints(module.getName(), line);
+        tc.addFractionDigits(oldExtendedType.getFractionDigits());
+        tc.addLengths(oldExtendedType.getLengths());
+        tc.addPatterns(oldExtendedType.getPatterns());
+        tc.addRanges(oldExtendedType.getRanges());
+
+        final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
+        final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
+                oldExtendedType.getQName());
+        newType.setTypedef(newBaseType);
+        newType.setPath(oldExtendedType.getPath());
+        newType.setDescription(oldExtendedType.getDescription());
+        newType.setReference(oldExtendedType.getReference());
+        newType.setStatus(oldExtendedType.getStatus());
+        newType.setLengths(constraints.getLength());
+        newType.setPatterns(constraints.getPatterns());
+        newType.setRanges(constraints.getRange());
+        newType.setFractionDigits(constraints.getFractionDigits());
+        newType.setUnits(oldExtendedType.getUnits());
+        newType.setDefaultValue(oldExtendedType.getDefaultValue());
+        newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
+        return newType;
+    }
+
+    /**
+     * Create new type builder based on old type with new base type.
+     *
+     * @param newBaseType
+     *            new base type
+     * @param oldExtendedType
+     *            old type
+     * @param modules
+     *            all loaded modules
+     * @param module
+     *            current module
+     * @param line
+     *            current line in module
+     * @return new type builder based on old type with new base type
+     */
+    public static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
+            final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
+        final TypeConstraints tc = new TypeConstraints(module.getName(), line);
+
+        final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
+        final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
+                oldExtendedType.getQName());
+        newType.setType(newBaseType);
+        newType.setPath(oldExtendedType.getPath());
+        newType.setDescription(oldExtendedType.getDescription());
+        newType.setReference(oldExtendedType.getReference());
+        newType.setStatus(oldExtendedType.getStatus());
+        newType.setLengths(constraints.getLength());
+        newType.setPatterns(constraints.getPatterns());
+        newType.setRanges(constraints.getRange());
+        newType.setFractionDigits(constraints.getFractionDigits());
+        newType.setUnits(oldExtendedType.getUnits());
+        newType.setDefaultValue(oldExtendedType.getDefaultValue());
+        newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
+        return newType;
+    }
+
+    /**
+     * Pull restrictions from type and add them to constraints.
+     *
+     * @param typeToResolve
+     *            type from which constraints will be read
+     * @param constraints
+     *            constraints object to which constraints will be added
+     * @return constraints contstraints object containing constraints from given
+     *         type
+     */
+    private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
+            final TypeConstraints constraints) {
+        // union type cannot be restricted
+        if (typeToResolve instanceof UnionTypeDefinition) {
+            return constraints;
+        }
+        if (typeToResolve instanceof ExtendedType) {
+            ExtendedType extType = (ExtendedType) typeToResolve;
+            constraints.addFractionDigits(extType.getFractionDigits());
+            constraints.addLengths(extType.getLengths());
+            constraints.addPatterns(extType.getPatterns());
+            constraints.addRanges(extType.getRanges());
+            return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
+        } else {
+            mergeConstraints(typeToResolve, constraints);
+            return constraints;
+        }
+    }
+
+    public static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
+            final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+            final ModuleBuilder builder, final SchemaContext context) {
+
+        // union and identityref types cannot be restricted
+        if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
+            return constraints;
+        }
+
+        if (nodeToResolve instanceof TypeDefinitionBuilder) {
+            TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
+            constraints.addFractionDigits(typedefToResolve.getFractionDigits());
+            constraints.addLengths(typedefToResolve.getLengths());
+            constraints.addPatterns(typedefToResolve.getPatterns());
+            constraints.addRanges(typedefToResolve.getRanges());
+        }
+
+        TypeDefinition<?> type = nodeToResolve.getType();
+        if (type == null) {
+            return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
+        } else {
+            QName qname = type.getQName();
+            if (type instanceof UnknownType) {
+                ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder, qname.getPrefix(),
+                        nodeToResolve.getLine());
+                if (dependentModuleBuilder == null) {
+                    if (context == null) {
+                        throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
+                                "Failed to resolved type constraints.");
+                    }
+                    Module dm = findModuleFromContext(context, builder, qname.getPrefix(), nodeToResolve.getLine());
+                    TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
+                    if (t instanceof ExtendedType) {
+                        ExtendedType extType = (ExtendedType) t;
+                        constraints.addFractionDigits(extType.getFractionDigits());
+                        constraints.addLengths(extType.getLengths());
+                        constraints.addPatterns(extType.getPatterns());
+                        constraints.addRanges(extType.getRanges());
+                        return constraints;
+                    } else {
+                        mergeConstraints(t, constraints);
+                        return constraints;
+                    }
+                } else {
+                    TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
+                            qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
+                    return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
+                }
+            } else if (type instanceof ExtendedType) {
+                ExtendedType extType = (ExtendedType) type;
+                constraints.addFractionDigits(extType.getFractionDigits());
+                constraints.addLengths(extType.getLengths());
+                constraints.addPatterns(extType.getPatterns());
+                constraints.addRanges(extType.getRanges());
+
+                TypeDefinition<?> base = extType.getBaseType();
+                if (base instanceof UnknownType) {
+                    ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, base.getQName()
+                            .getPrefix(), nodeToResolve.getLine());
+                    TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
+                            .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
+                    return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
+                } else {
+                    // it has to be base yang type
+                    mergeConstraints(type, constraints);
+                    return constraints;
+                }
+            } else {
+                // it is base yang type
+                mergeConstraints(type, constraints);
+                return constraints;
+            }
+        }
+    }
+
+    /**
+     * Search for type definition builder by name.
+     *
+     * @param dirtyNodeSchemaPath
+     *            schema path of node which contains unresolved type
+     * @param dependentModule
+     *            module which should contains referenced type
+     * @param typeName
+     *            name of type definition
+     * @param currentModuleName
+     *            name of current module
+     * @param line
+     *            current line in yang model
+     * @return
+     */
+    public static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
+            final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
+
+        TypeDefinitionBuilder result = null;
+
+        Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
+        result = findTypedefBuilderByName(typedefs, typeName);
+        if (result != null) {
+            return result;
+        }
+
+        Builder parent = nodeToResolve.getParent();
+        while (parent != null) {
+            if (parent instanceof DataNodeContainerBuilder) {
+                typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
+            } else if (parent instanceof RpcDefinitionBuilder) {
+                typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
+            }
+            result = findTypedefBuilderByName(typedefs, typeName);
+            if (result == null) {
+                parent = parent.getParent();
+            } else {
+                break;
+            }
+        }
+
+        if (result == null) {
+            throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");
+        }
+        return result;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineHolder.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineHolder.java
new file mode 100644 (file)
index 0000000..9e57d80
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.parser.builder.api.AbstractBuilder;
+
+public final class RefineHolder extends AbstractBuilder {
+    private final String name;
+    private String defaultStr;
+    private String description;
+    private String reference;
+    private Boolean config;
+    private Boolean mandatory;
+    private Boolean presence;
+    private MustDefinition must;
+    private Integer minElements;
+    private Integer maxElements;
+
+    public RefineHolder(final String moduleName, final int line, final String name) {
+        super(moduleName, line);
+        this.name = name;
+    }
+
+    public String getDefaultStr() {
+        return defaultStr;
+    }
+
+    public void setDefaultStr(final String defaultStr) {
+        this.defaultStr = defaultStr;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    public String getReference() {
+        return reference;
+    }
+
+    public void setReference(final String reference) {
+        this.reference = reference;
+    }
+
+    public Boolean isConfiguration() {
+        return config;
+    }
+
+    public void setConfiguration(final Boolean config) {
+        this.config = config;
+    }
+
+    public Boolean isMandatory() {
+        return mandatory;
+    }
+
+    public void setMandatory(Boolean mandatory) {
+        this.mandatory = mandatory;
+    }
+
+    public Boolean isPresence() {
+        return presence;
+    }
+
+    public void setPresence(Boolean presence) {
+        this.presence = presence;
+    }
+
+    public MustDefinition getMust() {
+        return must;
+    }
+
+    public void setMust(MustDefinition must) {
+        this.must = must;
+    }
+
+    public Integer getMinElements() {
+        return minElements;
+    }
+
+    public void setMinElements(Integer minElements) {
+        this.minElements = minElements;
+    }
+
+    public Integer getMaxElements() {
+        return maxElements;
+    }
+
+    public void setMaxElements(Integer maxElements) {
+        this.maxElements = maxElements;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Object build() {
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((addedUnknownNodes == null) ? 0 : addedUnknownNodes.hashCode());
+        result = prime * result + ((config == null) ? 0 : config.hashCode());
+        result = prime * result + ((defaultStr == null) ? 0 : defaultStr.hashCode());
+        result = prime * result + ((description == null) ? 0 : description.hashCode());
+        result = prime * result + ((mandatory == null) ? 0 : mandatory.hashCode());
+        result = prime * result + ((maxElements == null) ? 0 : maxElements.hashCode());
+        result = prime * result + ((minElements == null) ? 0 : minElements.hashCode());
+        result = prime * result + ((must == null) ? 0 : must.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((parent == null) ? 0 : parent.hashCode());
+        result = prime * result + ((presence == null) ? 0 : presence.hashCode());
+        result = prime * result + ((reference == null) ? 0 : reference.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        RefineHolder other = (RefineHolder) obj;
+        if (addedUnknownNodes == null) {
+            if (other.addedUnknownNodes != null)
+                return false;
+        } else if (!addedUnknownNodes.equals(other.addedUnknownNodes))
+            return false;
+        if (config == null) {
+            if (other.config != null)
+                return false;
+        } else if (!config.equals(other.config))
+            return false;
+        if (defaultStr == null) {
+            if (other.defaultStr != null)
+                return false;
+        } else if (!defaultStr.equals(other.defaultStr))
+            return false;
+        if (description == null) {
+            if (other.description != null)
+                return false;
+        } else if (!description.equals(other.description))
+            return false;
+        if (mandatory == null) {
+            if (other.mandatory != null)
+                return false;
+        } else if (!mandatory.equals(other.mandatory))
+            return false;
+        if (maxElements == null) {
+            if (other.maxElements != null)
+                return false;
+        } else if (!maxElements.equals(other.maxElements))
+            return false;
+        if (minElements == null) {
+            if (other.minElements != null)
+                return false;
+        } else if (!minElements.equals(other.minElements))
+            return false;
+        if (must == null) {
+            if (other.must != null)
+                return false;
+        } else if (!must.equals(other.must))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (parent == null) {
+            if (other.parent != null)
+                return false;
+        } else if (!parent.equals(other.parent))
+            return false;
+        if (presence == null) {
+            if (other.presence != null)
+                return false;
+        } else if (!presence.equals(other.presence))
+            return false;
+        if (reference == null) {
+            if (other.reference != null)
+                return false;
+        } else if (!reference.equals(other.reference))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "refine " + name;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineUtils.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineUtils.java
new file mode 100644 (file)
index 0000000..11d00cc
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import static org.opendaylight.controller.yang.parser.util.ParserUtils.*;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
+import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
+import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
+
+/**
+ * Utility class with helper methods to perform operations tied to refine
+ * process.
+ */
+public class RefineUtils {
+
+    private RefineUtils() {
+    }
+
+    /**
+     * Find original builder of node to refine and return copy of this builder.
+     * <p>
+     * We must create and use a copy of builder to preserve original builder
+     * state, because this object will be refined (modified) and later added to
+     * {@link UsesNodeBuilder}.
+     * </p>
+     *
+     * @param targetGrouping
+     *            builder of grouping which should contains node to refine
+     * @param refine
+     *            refine object containing informations about refine
+     * @param moduleName
+     *            current module name
+     * @return
+     */
+    public static SchemaNodeBuilder getRefineNodeFromGroupingBuilder(final GroupingBuilder targetGrouping,
+            final RefineHolder refine, final String moduleName) {
+        Builder result = null;
+        final Builder lookedUpBuilder = findRefineTargetBuilder(targetGrouping, refine.getName());
+        if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
+            result = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
+            result = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
+            result = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
+            result = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof ChoiceBuilder) {
+            result = new ChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
+            result = new AnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof GroupingBuilder) {
+            result = new GroupingBuilderImpl((GroupingBuilder) lookedUpBuilder);
+        } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
+            result = new TypeDefinitionBuilderImpl((TypeDefinitionBuilder) lookedUpBuilder);
+        } else {
+            throw new YangParseException(moduleName, refine.getLine(), "Target '" + refine.getName()
+                    + "' can not be refined");
+        }
+        return (SchemaNodeBuilder) result;
+    }
+
+    /**
+     * Create builder object from refine target node.
+     *
+     * @param grouping
+     *            grouping which should contains node to refine
+     * @param refine
+     *            refine object containing informations about refine
+     * @return
+     */
+    public static SchemaNodeBuilder getRefineNodeFromGroupingDefinition(final GroupingDefinition grouping,
+            final RefineHolder refine) {
+        final String moduleName = refine.getModuleName();
+        final int line = refine.getLine();
+        SchemaNodeBuilder result = null;
+        final Object lookedUpNode = findRefineTargetNode(grouping, refine.getName());
+        if (lookedUpNode instanceof LeafSchemaNode) {
+            result = createLeafBuilder((LeafSchemaNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof ContainerSchemaNode) {
+            result = createContainer((ContainerSchemaNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof ListSchemaNode) {
+            result = createList((ListSchemaNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof LeafListSchemaNode) {
+            result = createLeafList((LeafListSchemaNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof ChoiceNode) {
+            result = createChoice((ChoiceNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof AnyXmlSchemaNode) {
+            result = createAnyXml((AnyXmlSchemaNode) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof GroupingDefinition) {
+            result = createGrouping((GroupingDefinition) lookedUpNode, moduleName, line);
+        } else if (lookedUpNode instanceof TypeDefinition) {
+            result = createTypedef((ExtendedType) lookedUpNode, moduleName, line);
+        } else {
+            throw new YangParseException(moduleName, line, "Target '" + refine.getName() + "' can not be refined");
+        }
+        return result;
+    }
+
+    public static void refineLeaf(LeafSchemaNodeBuilder leaf, RefineHolder refine) {
+        String defaultStr = refine.getDefaultStr();
+        Boolean mandatory = refine.isMandatory();
+        MustDefinition must = refine.getMust();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (defaultStr != null && !("".equals(defaultStr))) {
+            leaf.setDefaultStr(defaultStr);
+        }
+        if (mandatory != null) {
+            leaf.getConstraints().setMandatory(mandatory);
+        }
+        if (must != null) {
+            leaf.getConstraints().addMustDefinition(must);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                leaf.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    public static void refineContainer(ContainerSchemaNodeBuilder container, RefineHolder refine, int line) {
+        Boolean presence = refine.isPresence();
+        MustDefinition must = refine.getMust();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (presence != null) {
+            container.setPresence(presence);
+        }
+        if (must != null) {
+            container.getConstraints().addMustDefinition(must);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                container.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    public static void refineList(ListSchemaNodeBuilder list, RefineHolder refine, int line) {
+        MustDefinition must = refine.getMust();
+        Integer min = refine.getMinElements();
+        Integer max = refine.getMaxElements();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (must != null) {
+            list.getConstraints().addMustDefinition(must);
+        }
+        if (min != null) {
+            list.getConstraints().setMinElements(min);
+        }
+        if (max != null) {
+            list.getConstraints().setMaxElements(max);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                list.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    public static void refineLeafList(LeafListSchemaNodeBuilder leafList, RefineHolder refine, int line) {
+        MustDefinition must = refine.getMust();
+        Integer min = refine.getMinElements();
+        Integer max = refine.getMaxElements();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (must != null) {
+            leafList.getConstraints().addMustDefinition(must);
+        }
+        if (min != null) {
+            leafList.getConstraints().setMinElements(min);
+        }
+        if (max != null) {
+            leafList.getConstraints().setMaxElements(max);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                leafList.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    public static void refineChoice(ChoiceBuilder choice, RefineHolder refine, int line) {
+        String defaultStr = refine.getDefaultStr();
+        Boolean mandatory = refine.isMandatory();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (defaultStr != null) {
+            choice.setDefaultCase(defaultStr);
+        }
+        if (mandatory != null) {
+            choice.getConstraints().setMandatory(mandatory);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                choice.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    public static void refineAnyxml(AnyXmlBuilder anyXml, RefineHolder refine, int line) {
+        Boolean mandatory = refine.isMandatory();
+        MustDefinition must = refine.getMust();
+        List<UnknownSchemaNodeBuilder> unknownNodes = refine.getUnknownNodeBuilders();
+
+        if (mandatory != null) {
+            anyXml.getConstraints().setMandatory(mandatory);
+        }
+        if (must != null) {
+            anyXml.getConstraints().addMustDefinition(must);
+        }
+        if (unknownNodes != null) {
+            for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
+                anyXml.addUnknownNodeBuilder(unknown);
+            }
+        }
+    }
+
+    /**
+     * Check if refine can be performed on given node.
+     *
+     * @param node
+     *            node to refine
+     * @param refine
+     *            refine object containing information about refine process
+     */
+    public static void checkRefine(SchemaNodeBuilder node, RefineHolder refine) {
+        String moduleName = refine.getModuleName();
+        int line = refine.getLine();
+        String name = node.getQName().getLocalName();
+
+        String defaultStr = refine.getDefaultStr();
+        Boolean mandatory = refine.isMandatory();
+        Boolean presence = refine.isPresence();
+        MustDefinition must = refine.getMust();
+        Integer min = refine.getMinElements();
+        Integer max = refine.getMaxElements();
+
+        if (node instanceof AnyXmlBuilder) {
+            checkRefineDefault(node, defaultStr, moduleName, line);
+            checkRefinePresence(node, presence, moduleName, line);
+            checkRefineMinMax(name, min, max, moduleName, line);
+        } else if (node instanceof ChoiceBuilder) {
+            checkRefinePresence(node, presence, moduleName, line);
+            checkRefineMust(node, must, moduleName, line);
+            checkRefineMinMax(name, min, max, moduleName, line);
+        } else if (node instanceof ContainerSchemaNodeBuilder) {
+            checkRefineDefault(node, defaultStr, moduleName, line);
+            checkRefineMandatory(node, mandatory, moduleName, line);
+            checkRefineMust(node, must, moduleName, line);
+            checkRefineMinMax(name, min, max, moduleName, line);
+        } else if (node instanceof LeafSchemaNodeBuilder) {
+            checkRefinePresence(node, presence, moduleName, line);
+            checkRefineMinMax(name, min, max, moduleName, line);
+        } else if (node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder) {
+            checkRefineDefault(node, defaultStr, moduleName, line);
+            checkRefinePresence(node, presence, moduleName, line);
+            checkRefineMandatory(node, mandatory, moduleName, line);
+        } else if (node instanceof GroupingBuilder || node instanceof TypeDefinitionBuilder
+                || node instanceof UsesNodeBuilder) {
+            checkRefineDefault(node, defaultStr, moduleName, line);
+            checkRefinePresence(node, presence, moduleName, line);
+            checkRefineMandatory(node, mandatory, moduleName, line);
+            checkRefineMust(node, must, moduleName, line);
+            checkRefineMinMax(name, min, max, moduleName, line);
+        }
+    }
+
+    private static void checkRefineDefault(SchemaNodeBuilder node, String defaultStr, String moduleName, int line) {
+        if (defaultStr != null) {
+            throw new YangParseException(moduleName, line, "Can not refine 'default' for '"
+                    + node.getQName().getLocalName() + "'.");
+        }
+    }
+
+    private static void checkRefineMandatory(SchemaNodeBuilder node, Boolean mandatory, String moduleName, int line) {
+        if (mandatory != null) {
+            throw new YangParseException(moduleName, line, "Can not refine 'mandatory' for '"
+                    + node.getQName().getLocalName() + "'.");
+        }
+    }
+
+    private static void checkRefinePresence(SchemaNodeBuilder node, Boolean presence, String moduleName, int line) {
+        if (presence != null) {
+            throw new YangParseException(moduleName, line, "Can not refine 'presence' for '"
+                    + node.getQName().getLocalName() + "'.");
+        }
+    }
+
+    private static void checkRefineMust(SchemaNodeBuilder node, MustDefinition must, String moduleName, int line) {
+        if (must != null) {
+            throw new YangParseException(moduleName, line, "Can not refine 'must' for '"
+                    + node.getQName().getLocalName() + "'.");
+        }
+    }
+
+    private static void checkRefineMinMax(String refineTargetName, Integer min, Integer max, String moduleName, int line) {
+        if (min != null || max != null) {
+            throw new YangParseException(moduleName, line, "Can not refine 'min-elements' or 'max-elements' for '"
+                    + refineTargetName + "'.");
+        }
+    }
+
+    /**
+     * Perform refine operation of following parameters:
+     * <ul>
+     * <li>description</li>
+     * <li>reference</li>
+     * <li>config</li>
+     * </ul>
+     *
+     * These parameters may be refined for any node.
+     *
+     * @param node
+     *            node to refine
+     * @param refine
+     *            refine object containing information about refine process
+     */
+    public static void refineDefault(final Builder node, final RefineHolder refine) {
+        final String moduleName = refine.getModuleName();
+        final int line = refine.getLine();
+        Class<? extends Builder> cls = node.getClass();
+
+        String description = refine.getDescription();
+        if (description != null) {
+            try {
+                Method method = cls.getDeclaredMethod("setDescription", String.class);
+                method.invoke(node, description);
+            } catch (Exception e) {
+                throw new YangParseException(moduleName, line, "Cannot refine description in " + cls.getName(), e);
+            }
+        }
+
+        String reference = refine.getReference();
+        if (reference != null) {
+            try {
+                Method method = cls.getDeclaredMethod("setReference", String.class);
+                method.invoke(node, reference);
+            } catch (Exception e) {
+                throw new YangParseException(moduleName, line, "Cannot refine reference in " + cls.getName(), e);
+            }
+        }
+
+        Boolean config = refine.isConfiguration();
+        if (config != null) {
+            try {
+                Method method = cls.getDeclaredMethod("setConfiguration", Boolean.class);
+                method.invoke(node, config);
+            } catch (Exception e) {
+                throw new YangParseException(moduleName, line, "Cannot refine config in " + cls.getName(), e);
+            }
+        }
+    }
+
+    /**
+     * Perform refine operation on given node.
+     *
+     * @param nodeToRefine
+     *            builder of node to refine
+     * @param refine
+     *            refine object containing information about refine process
+     * @param line
+     *            current line in yang model
+     */
+    public static void performRefine(SchemaNodeBuilder nodeToRefine, RefineHolder refine, int line) {
+        checkRefine(nodeToRefine, refine);
+        refineDefault(nodeToRefine, refine);
+        if (nodeToRefine instanceof LeafSchemaNodeBuilder) {
+            refineLeaf((LeafSchemaNodeBuilder) nodeToRefine, refine);
+        } else if (nodeToRefine instanceof ContainerSchemaNodeBuilder) {
+            refineContainer((ContainerSchemaNodeBuilder) nodeToRefine, refine, line);
+        } else if (nodeToRefine instanceof ListSchemaNodeBuilder) {
+            refineList((ListSchemaNodeBuilder) nodeToRefine, refine, line);
+        } else if (nodeToRefine instanceof LeafListSchemaNodeBuilder) {
+            refineLeafList((LeafListSchemaNodeBuilder) nodeToRefine, refine, line);
+        } else if (nodeToRefine instanceof ChoiceBuilder) {
+            refineChoice((ChoiceBuilder) nodeToRefine, refine, line);
+        } else if (nodeToRefine instanceof AnyXmlBuilder) {
+            refineAnyxml((AnyXmlBuilder) nodeToRefine, refine, line);
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TopologicalSort.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TopologicalSort.java
new file mode 100644 (file)
index 0000000..2ea289a
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Utility class that provides topological sort
+ */
+public final class TopologicalSort {
+
+    /**
+     * Topological sort of dependent nodes in acyclic graphs.
+     *
+     * @return Sorted {@link List} of {@link Node}s. Order: Nodes with no
+     *         dependencies starting.
+     * @throws IllegalStateException
+     *             when cycle is present in the graph
+     */
+    public static List<Node> sort(Set<Node> nodes) {
+        List<Node> sortedNodes = Lists.newArrayList();
+
+        Set<Node> dependentNodes = getDependentNodes(nodes);
+
+        while (!dependentNodes.isEmpty()) {
+            Node n = dependentNodes.iterator().next();
+            dependentNodes.remove(n);
+
+            sortedNodes.add(n);
+
+            for (Edge e : n.getInEdges()) {
+                Node m = e.getFrom();
+                m.getOutEdges().remove(e);
+
+                if (m.getOutEdges().isEmpty()) {
+                    dependentNodes.add(m);
+                }
+            }
+        }
+
+        detectCycles(nodes);
+
+        return sortedNodes;
+    }
+
+    private static Set<Node> getDependentNodes(Set<Node> nodes) {
+        Set<Node> S = Sets.newHashSet();
+        for (Node n : nodes) {
+            if (n.getOutEdges().size() == 0) {
+                S.add(n);
+            }
+        }
+        return S;
+    }
+
+    private static void detectCycles(Set<Node> nodes) {
+        // Detect cycles
+        boolean cycle = false;
+        Node cycledNode = null;
+
+        for (Node n : nodes) {
+            if (!n.getOutEdges().isEmpty()) {
+                cycle = true;
+                cycledNode = n;
+                break;
+            }
+        }
+        Preconditions.checkState(cycle == false,
+                "Cycle detected in graph around node: " + cycledNode);
+    }
+
+    /**
+     * Interface for nodes in graph that can be sorted topologically
+     */
+    public static interface Node {
+        Set<Edge> getInEdges();
+
+        Set<Edge> getOutEdges();
+    }
+
+    /**
+     * Interface for edges in graph that can be sorted topologically
+     */
+    public static interface Edge {
+        Node getFrom();
+
+        Node getTo();
+    }
+
+    /**
+     * Basic Node implementation.
+     */
+    public static class NodeImpl implements Node {
+        private final Set<Edge> inEdges;
+        private final Set<Edge> outEdges;
+
+        @Override
+        public Set<Edge> getInEdges() {
+            return inEdges;
+        }
+
+        @Override
+        public Set<Edge> getOutEdges() {
+            return outEdges;
+        }
+
+        public void addEdge(Node to) {
+            Edge e = new EdgeImpl(this, to);
+            outEdges.add(e);
+            to.getInEdges().add(e);
+        }
+
+        public NodeImpl() {
+            inEdges = Sets.newHashSet();
+            outEdges = Sets.newHashSet();
+        }
+    }
+
+    /**
+     * Basic Edge implementation
+     */
+    public static class EdgeImpl implements Edge {
+        private final Node from;
+        private final Node to;
+
+        @Override
+        public Node getFrom() {
+            return from;
+        }
+
+        @Override
+        public Node getTo() {
+            return to;
+        }
+
+        public EdgeImpl(Node from, Node to) {
+            this.from = from;
+            this.to = to;
+
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((from == null) ? 0 : from.hashCode());
+            result = prime * result + ((to == null) ? 0 : to.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            EdgeImpl other = (EdgeImpl) obj;
+            if (from == null) {
+                if (other.from != null)
+                    return false;
+            } else if (!from.equals(other.from))
+                return false;
+            if (to == null) {
+                if (other.to != null)
+                    return false;
+            } else if (!to.equals(other.to))
+                return false;
+            return true;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TypeConstraints.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TypeConstraints.java
new file mode 100644 (file)
index 0000000..08422c8
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.BaseConstraints;
+
+/**
+ * Holder object for holding YANG type constraints.
+ */
+public final class TypeConstraints {
+    private final String moduleName;
+    private final int line;
+    private final List<List<RangeConstraint>> ranges = new ArrayList<List<RangeConstraint>>();
+    private final List<List<LengthConstraint>> lengths = new ArrayList<List<LengthConstraint>>();
+    private final List<List<PatternConstraint>> patterns = new ArrayList<List<PatternConstraint>>();
+    private final List<Integer> fractionDigits = new ArrayList<Integer>();
+
+    public TypeConstraints(final String moduleName, final int line) {
+        this.moduleName = moduleName;
+        this.line = line;
+    }
+
+    List<List<RangeConstraint>> getAllRanges() {
+        return ranges;
+    }
+
+    public List<RangeConstraint> getRange() {
+        if (ranges.size() < 2) {
+            return Collections.emptyList();
+        }
+
+        final List<RangeConstraint> resolved = ranges.get(0);
+        RangeConstraint firstRange = resolved.get(0);
+        RangeConstraint lastRange = resolved.get(resolved.size() - 1);
+        Number min = firstRange.getMin();
+        Number max = lastRange.getMax();
+
+        if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
+            if (ranges.size() > 1) {
+                validateRange(resolved);
+            }
+            return resolved;
+        }
+
+        if (firstRange.equals(lastRange)) {
+            if (min instanceof UnknownBoundaryNumber) {
+                min = resolveMinRange(min);
+            }
+            if (max instanceof UnknownBoundaryNumber) {
+                max = resolveMaxRange(max);
+            }
+            firstRange = BaseConstraints.rangeConstraint(min, max, firstRange.getDescription(),
+                    firstRange.getReference());
+            resolved.set(0, firstRange);
+            lastRange = BaseConstraints.rangeConstraint(min, max, lastRange.getDescription(), lastRange.getReference());
+            resolved.set(resolved.size() - 1, lastRange);
+        } else {
+            if (min instanceof UnknownBoundaryNumber) {
+                min = resolveMinRange(min);
+                firstRange = BaseConstraints.rangeConstraint(min, firstRange.getMax(), firstRange.getDescription(),
+                        firstRange.getReference());
+                resolved.set(0, firstRange);
+            }
+            if (max instanceof UnknownBoundaryNumber) {
+                max = resolveMaxRange(max);
+                lastRange = BaseConstraints.rangeConstraint(lastRange.getMin(), max, lastRange.getDescription(),
+                        lastRange.getReference());
+                resolved.set(resolved.size() - 1, lastRange);
+            }
+        }
+        if (this.ranges.size() > 1) {
+            validateRange(resolved);
+        }
+        return resolved;
+    }
+
+    private Number resolveMinRange(Number min) {
+        int i = 1;
+        while (min instanceof UnknownBoundaryNumber) {
+            final List<RangeConstraint> act = ranges.get(i);
+            min = act.get(0).getMin();
+            i++;
+        }
+        return min;
+    }
+
+    private Number resolveMaxRange(Number max) {
+        int i = 1;
+        while (max instanceof UnknownBoundaryNumber) {
+            final List<RangeConstraint> act = ranges.get(i);
+            max = act.get(act.size() - 1).getMax();
+            i++;
+        }
+        return max;
+    }
+
+    public void addRanges(final List<RangeConstraint> ranges) {
+        if (ranges != null && !(ranges.isEmpty())) {
+            this.ranges.add(ranges);
+        }
+    }
+
+    public List<List<LengthConstraint>> getAllLengths() {
+        return lengths;
+    }
+
+    public List<LengthConstraint> getLength() {
+        if (lengths.size() < 2) {
+            return Collections.emptyList();
+        }
+
+        final List<LengthConstraint> resolved = lengths.get(0);
+        LengthConstraint firstLength = resolved.get(0);
+        LengthConstraint lastLength = resolved.get(resolved.size() - 1);
+        Number min = firstLength.getMin();
+        Number max = lastLength.getMax();
+
+        if (!(min instanceof UnknownBoundaryNumber) && !(max instanceof UnknownBoundaryNumber)) {
+            if (lengths.size() > 1) {
+                validateLength(resolved);
+            }
+            return resolved;
+        }
+
+        if (firstLength.equals(lastLength)) {
+            if (min instanceof UnknownBoundaryNumber) {
+                min = resolveMinLength(min);
+            }
+            if (max instanceof UnknownBoundaryNumber) {
+                max = resolveMaxLength(max);
+            }
+            firstLength = BaseConstraints.lengthConstraint(min, max, firstLength.getDescription(),
+                    firstLength.getReference());
+            resolved.set(0, firstLength);
+            lastLength = BaseConstraints.lengthConstraint(min, max, lastLength.getDescription(),
+                    lastLength.getReference());
+            resolved.set(resolved.size() - 1, lastLength);
+        } else {
+            if (min instanceof UnknownBoundaryNumber) {
+                min = resolveMinLength(min);
+                firstLength = BaseConstraints.lengthConstraint(min, firstLength.getMax(), firstLength.getDescription(),
+                        firstLength.getReference());
+                resolved.set(0, firstLength);
+            }
+            if (max instanceof UnknownBoundaryNumber) {
+                max = resolveMaxLength(max);
+                lastLength = BaseConstraints.lengthConstraint(lastLength.getMin(), max, lastLength.getDescription(),
+                        lastLength.getReference());
+                resolved.set(resolved.size() - 1, lastLength);
+            }
+        }
+
+        if (lengths.size() > 1) {
+            validateLength(resolved);
+        }
+        return resolved;
+    }
+
+    private Number resolveMinLength(Number min) {
+        int i = 1;
+        while (min instanceof UnknownBoundaryNumber) {
+            final List<LengthConstraint> act = lengths.get(i);
+            min = act.get(0).getMin();
+            i++;
+        }
+        return min;
+    }
+
+    private Number resolveMaxLength(Number max) {
+        int i = 1;
+        while (max instanceof UnknownBoundaryNumber) {
+            final List<LengthConstraint> act = lengths.get(i);
+            max = act.get(act.size() - 1).getMax();
+            i++;
+        }
+        return max;
+    }
+
+    public void addLengths(final List<LengthConstraint> lengths) {
+        if (lengths != null && !(lengths.isEmpty())) {
+            this.lengths.add(lengths);
+        }
+    }
+
+    public List<PatternConstraint> getPatterns() {
+        if(patterns.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return patterns.get(0);
+    }
+
+    public void addPatterns(final List<PatternConstraint> patterns) {
+        this.patterns.add(patterns);
+    }
+
+    public Integer getFractionDigits() {
+        if (fractionDigits.isEmpty()) {
+            return null;
+        }
+        return fractionDigits.get(0);
+    }
+
+    public void addFractionDigits(final Integer fractionDigits) {
+        this.fractionDigits.add(fractionDigits);
+    }
+
+    public void validateConstraints() {
+        validateLength();
+        validateRange();
+    }
+
+    private void validateRange() {
+        if (ranges.size() < 2) {
+            return;
+        }
+        List<RangeConstraint> typeRange = getRange();
+
+        for (RangeConstraint range : typeRange) {
+            if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
+                throw new YangParseException(moduleName, line, "Unresolved range constraints");
+            }
+            final long min = range.getMin().longValue();
+            final long max = range.getMax().longValue();
+
+            List<RangeConstraint> parentRanges = ranges.get(1);
+            boolean check = false;
+            for (RangeConstraint r : parentRanges) {
+                Number parentMinNumber = r.getMin();
+                if (parentMinNumber instanceof UnknownBoundaryNumber) {
+                    parentMinNumber = resolveMinRange(parentMinNumber);
+                }
+                long parentMin = parentMinNumber.longValue();
+
+                Number parentMaxNumber = r.getMax();
+                if (parentMaxNumber instanceof UnknownBoundaryNumber) {
+                    parentMaxNumber = resolveMaxRange(parentMaxNumber);
+                }
+                long parentMax = parentMaxNumber.longValue();
+
+                if (parentMin <= min && parentMax >= max) {
+                    check = true;
+                    break;
+                }
+            }
+            if (!check) {
+                throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
+                        + "> (parent: " + parentRanges + ").");
+            }
+        }
+    }
+
+    private void validateRange(List<RangeConstraint> typeRange) {
+        if (ranges.size() < 2) {
+            return;
+        }
+
+        for (RangeConstraint range : typeRange) {
+            if (range.getMin() instanceof UnknownBoundaryNumber || range.getMax() instanceof UnknownBoundaryNumber) {
+                throw new YangParseException(moduleName, line, "Unresolved range constraints");
+            }
+            final long min = range.getMin().longValue();
+            final long max = range.getMax().longValue();
+
+            List<RangeConstraint> parentRanges = ranges.get(1);
+            boolean check = false;
+            for (RangeConstraint r : parentRanges) {
+                Number parentMinNumber = r.getMin();
+                if (parentMinNumber instanceof UnknownBoundaryNumber) {
+                    parentMinNumber = resolveMinRange(parentMinNumber);
+                }
+                long parentMin = parentMinNumber.longValue();
+
+                Number parentMaxNumber = r.getMax();
+                if (parentMaxNumber instanceof UnknownBoundaryNumber) {
+                    parentMaxNumber = resolveMaxRange(parentMaxNumber);
+                }
+                long parentMax = parentMaxNumber.longValue();
+
+                if (parentMin <= min && parentMax >= max) {
+                    check = true;
+                    break;
+                }
+            }
+            if (!check) {
+                throw new YangParseException(moduleName, line, "Invalid range constraint: <" + min + ", " + max
+                        + "> (parent: " + parentRanges + ").");
+            }
+        }
+    }
+
+    private void validateLength() {
+        if (lengths.size() < 2) {
+            return;
+        }
+        List<LengthConstraint> typeLength = getLength();
+
+        for (LengthConstraint length : typeLength) {
+            if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
+                throw new YangParseException(moduleName, line, "Unresolved length constraints");
+            }
+            final long min = length.getMin().longValue();
+            final long max = length.getMax().longValue();
+
+            List<LengthConstraint> parentLengths = lengths.get(1);
+            boolean check = false;
+            for (LengthConstraint lc : parentLengths) {
+                Number parentMinNumber = lc.getMin();
+                if (parentMinNumber instanceof UnknownBoundaryNumber) {
+                    parentMinNumber = resolveMinLength(parentMinNumber);
+                }
+                long parentMin = parentMinNumber.longValue();
+
+                Number parentMaxNumber = lc.getMax();
+                if (parentMaxNumber instanceof UnknownBoundaryNumber) {
+                    parentMaxNumber = resolveMaxLength(parentMaxNumber);
+                }
+                long parentMax = parentMaxNumber.longValue();
+
+                if (parentMin <= min && parentMax >= max) {
+                    check = true;
+                    break;
+                }
+            }
+            if (!check) {
+                throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
+                        + "> (parent: " + parentLengths + ").");
+            }
+        }
+    }
+
+    private void validateLength(List<LengthConstraint> typeLength) {
+        if (lengths.size() < 2) {
+            return;
+        }
+
+        for (LengthConstraint length : typeLength) {
+            if (length.getMin() instanceof UnknownBoundaryNumber || length.getMax() instanceof UnknownBoundaryNumber) {
+                throw new YangParseException(moduleName, line, "Unresolved length constraints");
+            }
+            final long min = length.getMin().longValue();
+            final long max = length.getMax().longValue();
+
+            List<LengthConstraint> parentLengths = lengths.get(1);
+            boolean check = false;
+            for (LengthConstraint lc : parentLengths) {
+                Number parentMinNumber = lc.getMin();
+                if (parentMinNumber instanceof UnknownBoundaryNumber) {
+                    parentMinNumber = resolveMinLength(parentMinNumber);
+                }
+                long parentMin = parentMinNumber.longValue();
+
+                Number parentMaxNumber = lc.getMax();
+                if (parentMaxNumber instanceof UnknownBoundaryNumber) {
+                    parentMaxNumber = resolveMaxLength(parentMaxNumber);
+                }
+                long parentMax = parentMaxNumber.longValue();
+
+                if (parentMin <= min && parentMax >= max) {
+                    check = true;
+                    break;
+                }
+            }
+            if (!check) {
+                throw new YangParseException(moduleName, line, "Invalid length constraint: <" + min + ", " + max
+                        + "> (parent: " + parentLengths + ").");
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/UnknownBoundaryNumber.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/UnknownBoundaryNumber.java
new file mode 100644 (file)
index 0000000..c095bba
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+/**
+ * Marker object representing special 'min' or 'max' values in YANG.
+ */
+final class UnknownBoundaryNumber extends Number {
+    private static final long serialVersionUID = 1464861684686434869L;
+
+    private final String value;
+
+    UnknownBoundaryNumber(final String value) {
+        this.value = value;
+    }
+
+    @Override
+    public int intValue() {
+        return 0;
+    }
+
+    @Override
+    public long longValue() {
+        return 0;
+    }
+
+    @Override
+    public float floatValue() {
+        return 0;
+    }
+
+    @Override
+    public double doubleValue() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangParseException.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangParseException.java
new file mode 100644 (file)
index 0000000..6939261
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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/eplv10.html
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+public class YangParseException extends RuntimeException {
+    private static final long serialVersionUID = 1239548963471793178L;
+
+    public YangParseException(final String errorMsg) {
+        super(errorMsg);
+    }
+
+    public YangParseException(final String errorMsg, final Exception exception) {
+        super(errorMsg, exception);
+    }
+
+    public YangParseException(final String moduleName, final int line,
+            final String errorMsg) {
+        super("Error in module '" + moduleName + "' at line " + line + ": "
+                + errorMsg);
+    }
+
+    public YangParseException(final String moduleName, final int line,
+            final String errorMsg, final Exception exception) {
+        super("Error in module '" + moduleName + "' at line " + line + ": "
+                + errorMsg, exception);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangValidationException.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangValidationException.java
new file mode 100644 (file)
index 0000000..0706926
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+/**
+ * Unchecked exception thrown if yang definition is not valid according to
+ * {@link YangModelBasicValidationListener}
+ */
+public final class YangValidationException extends RuntimeException {
+
+    private static final long serialVersionUID = 7414330400390825381L;
+
+    public YangValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public YangValidationException(String message) {
+        super(message);
+    }
+
+}
\ No newline at end of file
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/BasicValidations.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/BasicValidations.java
new file mode 100644 (file)
index 0000000..762b910
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * 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/eplv10.html
+ */
+package org.opendaylight.controller.yang.validator;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
+import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Reusable checks of basic constraints on yang statements
+ */
+final class BasicValidations {
+
+    static final String SUPPORTED_YANG_VERSION = "1";
+
+    static void checkNotPresentBoth(ParseTree parent,
+            Class<? extends ParseTree> childType1,
+            Class<? extends ParseTree> childType2) {
+        if (BasicValidations.checkPresentChildOfTypeSafe(parent, childType1,
+                true)
+                && BasicValidations.checkPresentChildOfTypeSafe(parent,
+                        childType2, false))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) Both %s and %s statement present in %s:%s",
+                                    ValidationUtil.getRootParentName(parent),
+                                    ValidationUtil
+                                            .getSimpleStatementName(childType1),
+                                    ValidationUtil
+                                            .getSimpleStatementName(childType2),
+                                    ValidationUtil
+                                            .getSimpleStatementName(parent
+                                                    .getClass()),
+                                    ValidationUtil.getName(parent)));
+    }
+
+    static void checkOnlyPermittedValues(ParseTree ctx,
+            Set<String> permittedValues) {
+        String mandatory = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        if (!permittedValues.contains(mandatory))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) %s:%s, illegal value for %s statement, only permitted:%s",
+                                    rootParentName, ValidationUtil
+                                            .getSimpleStatementName(ctx
+                                                    .getClass()), mandatory,
+                                    ValidationUtil.getSimpleStatementName(ctx
+                                            .getClass()), permittedValues));
+    }
+
+    static void checkUniquenessInNamespace(ParseTree stmt, Set<String> uniques) {
+        String name = ValidationUtil.getName(stmt);
+        String rootParentName = ValidationUtil.getRootParentName(stmt);
+
+        if (uniques.contains(name))
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In (sub)module:%s) %s:%s not unique in (sub)module",
+                    rootParentName,
+                    ValidationUtil.getSimpleStatementName(stmt.getClass()),
+                    name));
+        uniques.add(name);
+    }
+
+    /**
+     * Check if only one module or submodule is present in session(one yang
+     * file)
+     */
+    static void checkOnlyOneModulePresent(String moduleName, String globalId) {
+        if (globalId != null)
+            ValidationUtil.ex(ValidationUtil
+                    .f("Multiple (sub)modules per file"));
+    }
+
+    static void checkPresentYangVersion(ParseTree ctx, String moduleName) {
+        if (!checkPresentChildOfTypeSafe(ctx, Yang_version_stmtContext.class,
+                true))
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("Yang version statement not present in module:%s, Validating as yang version:%s",
+                                    moduleName, SUPPORTED_YANG_VERSION));
+    }
+
+    static void checkDateFormat(ParseTree stmt, DateFormat format) {
+        try {
+            format.parse(ValidationUtil.getName(stmt));
+        } catch (ParseException e) {
+            String exceptionMessage = ValidationUtil
+                    .f("(In (sub)module:%s) %s:%s, invalid date format expected date format is:%s",
+                            ValidationUtil.getRootParentName(stmt),
+                            ValidationUtil.getSimpleStatementName(stmt
+                                    .getClass()), ValidationUtil.getName(stmt),
+                            YangParserListenerImpl.simpleDateFormat
+                                    .format(new Date()));
+            ValidationUtil.ex(exceptionMessage);
+        }
+    }
+
+    static Pattern identifierPattern = Pattern
+            .compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
+
+    static void checkIdentifier(ParseTree statement) {
+        checkIdentifierInternal(statement, ValidationUtil.getName(statement));
+    }
+
+    static void checkIdentifierInternal(ParseTree statement, String name) {
+        if (!identifierPattern.matcher(name).matches()) {
+
+            String message = ValidationUtil
+                    .f("%s statement identifier:%s is not in required format:%s",
+                            ValidationUtil.getSimpleStatementName(statement
+                                    .getClass()), name, identifierPattern
+                                    .toString());
+            String parent = ValidationUtil.getRootParentName(statement);
+            message = parent.equals(name) ? message : ValidationUtil.f(
+                    "(In (sub)module:%s) %s", parent, message);
+
+            if(statement instanceof ParserRuleContext) {
+                message = "Error on line "+ ((ParserRuleContext)statement).getStart().getLine() + ": "+ message;
+            }
+
+            ValidationUtil.ex(message);
+        }
+    }
+
+    static Pattern prefixedIdentifierPattern = Pattern.compile("(.+):(.+)");
+
+    static void checkPrefixedIdentifier(ParseTree statement) {
+        checkPrefixedIdentifierInternal(statement,
+                ValidationUtil.getName(statement));
+    }
+
+    private static void checkPrefixedIdentifierInternal(ParseTree statement,
+            String id) {
+        Matcher matcher = prefixedIdentifierPattern.matcher(id);
+
+        if (matcher.matches()) {
+            try {
+                // check prefix
+                checkIdentifierInternal(statement, matcher.group(1));
+                // check ID
+                checkIdentifierInternal(statement, matcher.group(2));
+            } catch (YangValidationException e) {
+                ValidationUtil.ex(ValidationUtil.f(
+                        "Prefixed id:%s not in required format, details:%s",
+                        id, e.getMessage()));
+            }
+        } else
+            checkIdentifierInternal(statement, id);
+    }
+
+    static void checkSchemaNodeIdentifier(ParseTree statement) {
+        String id = ValidationUtil.getName(statement);
+
+        try {
+            for (String oneOfId : id.split("/")) {
+                if (oneOfId.isEmpty())
+                    continue;
+                checkPrefixedIdentifierInternal(statement, oneOfId);
+            }
+        } catch (YangValidationException e) {
+            ValidationUtil.ex(ValidationUtil.f(
+                    "Schema node id:%s not in required format, details:%s", id,
+                    e.getMessage()));
+        }
+    }
+
+    private static interface MessageProvider {
+        String getMessage();
+    }
+
+    static void checkPresentChildOfTypeInternal(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildType,
+            MessageProvider message, boolean atMostOne) {
+        if (!checkPresentChildOfTypeSafe(parent, expectedChildType, atMostOne)) {
+            String str = atMostOne ? "(Expected exactly one statement) "
+                    + message.getMessage() : message.getMessage();
+            ValidationUtil.ex(str);
+        }
+    }
+
+    static void checkPresentChildOfType(final ParseTree parent,
+            final Class<? extends ParseTree> expectedChildType,
+            boolean atMostOne) {
+
+        // Construct message in checkPresentChildOfTypeInternal only if
+        // validaiton fails, not in advance
+        MessageProvider message = new MessageProvider() {
+
+            @Override
+            public String getMessage() {
+                String message = ValidationUtil
+                        .f("Missing %s statement in %s:%s", ValidationUtil
+                                .getSimpleStatementName(expectedChildType),
+                                ValidationUtil.getSimpleStatementName(parent
+                                        .getClass()), ValidationUtil
+                                        .getName(parent));
+
+                String root = ValidationUtil.getRootParentName(parent);
+                message = parent.equals(ValidationUtil
+                        .getRootParentName(parent)) ? message : ValidationUtil
+                        .f("(In (sub)module:%s) %s", root, message);
+                return message;
+            }
+        };
+
+        Set<Class<? extends ParseTree>> expectedChildTypeSet = Sets
+                .newHashSet();
+        expectedChildTypeSet.add(expectedChildType);
+
+        checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message,
+                atMostOne);
+    }
+
+    static void checkPresentChildOfTypes(final ParseTree parent,
+            final Set<Class<? extends ParseTree>> expectedChildTypes,
+            boolean atMostOne) {
+
+        // Construct message in checkPresentChildOfTypeInternal only if
+        // validaiton fails, not in advance
+        MessageProvider message = new MessageProvider() {
+
+            @Override
+            public String getMessage() {
+                StringBuilder childTypes = new StringBuilder();
+                String orStr = " OR ";
+                for (Class<? extends ParseTree> type : expectedChildTypes) {
+                    childTypes.append(ValidationUtil
+                            .getSimpleStatementName(type));
+                    childTypes.append(orStr);
+                }
+
+                String message = ValidationUtil
+                        .f("Missing %s statement in %s:%s", childTypes
+                                .toString(), ValidationUtil
+                                .getSimpleStatementName(parent.getClass()),
+                                ValidationUtil.getName(parent));
+
+                String root = ValidationUtil.getRootParentName(parent);
+                message = parent.equals(ValidationUtil
+                        .getRootParentName(parent)) ? message : ValidationUtil
+                        .f("(In (sub)module:%s) %s", root, message);
+
+                return message;
+            }
+        };
+
+        checkPresentChildOfTypeInternal(parent, expectedChildTypes, message,
+                atMostOne);
+    }
+
+    static boolean checkPresentChildOfTypeSafe(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildType, boolean atMostOne) {
+
+        int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
+                parent, expectedChildType);
+
+        return atMostOne ? foundChildrenOfType == 1 ? true : false
+                : foundChildrenOfType != 0 ? true : false;
+    }
+
+    static boolean checkPresentChildOfTypeSafe(ParseTree parent,
+            Class<? extends ParseTree> expectedChildType, boolean atMostOne) {
+
+        int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType(
+                parent, expectedChildType);
+
+        return atMostOne ? foundChildrenOfType == 1 ? true : false
+                : foundChildrenOfType != 0 ? true : false;
+    }
+
+    static List<String> getAndCheckUniqueKeys(ParseTree ctx) {
+        String key = ValidationUtil.getName(ctx);
+        ParseTree parent = ctx.getParent();
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        List<String> keyList = ValidationUtil.listKeysFromId(key);
+        Set<String> duplicates = ValidationUtil.getDuplicates(keyList);
+
+        if (duplicates.size() != 0)
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In (sub)module:%s) %s:%s, %s:%s contains duplicates:%s",
+                    rootParentName,
+                    ValidationUtil.getSimpleStatementName(parent.getClass()),
+                    ValidationUtil.getName(parent),
+                    ValidationUtil.getSimpleStatementName(ctx.getClass()), key,
+                    duplicates));
+        return keyList;
+    }
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/ValidationUtil.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/ValidationUtil.java
new file mode 100644 (file)
index 0000000..cb5af9f
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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/eplv10.html
+ */
+package org.opendaylight.controller.yang.validator;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.yang.parser.util.ParserListenerUtils;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+/**
+ * Validation utilities
+ */
+final class ValidationUtil {
+
+    static void ex(String message) {
+        throw new YangValidationException(message);
+    }
+
+    static Set<String> getDuplicates(Collection<String> keyList) {
+        Set<String> all = new HashSet<String>();
+        Set<String> duplicates = new HashSet<String>();
+
+        for (String key : keyList) {
+            if (!all.add(key))
+                duplicates.add(key);
+        }
+        return duplicates;
+    }
+
+    static List<String> listKeysFromId(String keys) {
+        return Arrays.asList(keys.split(" "));
+    }
+
+    static String getRootParentName(ParseTree ctx) {
+        ParseTree root = getRootParent(ctx);
+        return ValidationUtil.getName(root);
+    }
+
+    private static ParseTree getRootParent(ParseTree ctx) {
+        ParseTree root = ctx;
+        while (root.getParent() != null) {
+            if (root.getClass().equals(Module_stmtContext.class)
+                    || root.getClass().equals(Submodule_stmtContext.class))
+                break;
+            root = root.getParent();
+        }
+        return root;
+    }
+
+    static String getName(ParseTree child) {
+        return ParserListenerUtils.stringFromNode(child);
+    }
+
+    static String f(String base, Object... args) {
+        return String.format(base, args);
+    }
+
+    /**
+     * Get simple name from statement class e.g. Module from Module_stmt_context
+     */
+    static String getSimpleStatementName(
+            Class<? extends ParseTree> typeOfStatement) {
+
+        String className = typeOfStatement.getSimpleName();
+        int lastIndexOf = className.indexOf('$');
+        className = lastIndexOf == -1 ? className : className
+                .substring(lastIndexOf + 1);
+        int indexOfStmt = className.indexOf("_stmt");
+        int index = indexOfStmt == -1 ? className.indexOf("_arg") : indexOfStmt;
+        return className.substring(0, index).replace('_', '-');
+    }
+
+    static int countPresentChildrenOfType(ParseTree parent,
+            Set<Class<? extends ParseTree>> expectedChildTypes) {
+        int foundChildrenOfType = 0;
+
+        for (Class<? extends ParseTree> type : expectedChildTypes) {
+            foundChildrenOfType += countPresentChildrenOfType(parent, type);
+        }
+        return foundChildrenOfType;
+    }
+
+    static int countPresentChildrenOfType(ParseTree parent,
+            Class<? extends ParseTree> expectedChildType) {
+        int foundChildrenOfType = 0;
+
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            ParseTree child = parent.getChild(i);
+            if (expectedChildType.isInstance(child))
+                foundChildrenOfType++;
+        }
+        return foundChildrenOfType;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidationListener.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidationListener.java
new file mode 100644 (file)
index 0000000..7f270fe
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Set;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Anyxml_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Case_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Choice_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Extension_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Feature_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Grouping_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Identity_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.If_feature_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_list_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Notification_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Rpc_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Typedef_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Unique_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Uses_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener;
+import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Validation listener that validates yang statements according to RFC-6020.
+ * This validator expects only one module or submodule per file and performs
+ * only basic validation where context from all yang models is not present.
+ */
+final class YangModelBasicValidationListener extends YangParserBaseListener {
+
+    private static final Logger logger = LoggerFactory
+            .getLogger(YangModelBasicValidationListener.class);
+
+    private final Set<String> uniquePrefixes;
+    private final Set<String> uniqueImports;
+    private final Set<String> uniqueIncludes;
+
+    private String globalModuleId;
+
+    YangModelBasicValidationListener() {
+        super();
+        uniquePrefixes = Sets.newHashSet();
+        uniqueImports = Sets.newHashSet();
+        uniqueIncludes = Sets.newHashSet();
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Header statements present(mandatory prefix and namespace statements
+     * are in header)</li>
+     * <li>Only one module or submodule per file</li>
+     * </ol>
+     */
+    @Override
+    public void enterModule_stmt(Module_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Module_header_stmtsContext.class, true);
+
+        String moduleName = ValidationUtil.getName(ctx);
+        BasicValidations.checkOnlyOneModulePresent(moduleName, globalModuleId);
+        globalModuleId = moduleName;
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Header statements present(mandatory belongs-to statement is in
+     * header)</li>
+     * <li>Only one module or submodule per file</li>
+     * </ol>
+     */
+    @Override
+    public void enterSubmodule_stmt(Submodule_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Submodule_header_stmtsContext.class, true);
+
+        String submoduleName = ValidationUtil.getName(ctx);
+        BasicValidations.checkOnlyOneModulePresent(submoduleName,
+                globalModuleId);
+        globalModuleId = submoduleName;
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>One Belongs-to statement present</li>
+     * </ol>
+     */
+    @Override
+    public void enterSubmodule_header_stmts(Submodule_header_stmtsContext ctx) {
+        BasicValidations.checkPresentChildOfType(ctx,
+                Belongs_to_stmtContext.class, true);
+
+        // check Yang version present, if not log
+        try {
+            BasicValidations.checkPresentYangVersion(ctx,
+                    ValidationUtil.getRootParentName(ctx));
+        } catch (Exception e) {
+            logger.debug(e.getMessage());
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>One Namespace statement present</li>
+     * <li>One Prefix statement present</li>
+     * </ol>
+     */
+    @Override
+    public void enterModule_header_stmts(Module_header_stmtsContext ctx) {
+        String moduleName = ValidationUtil.getRootParentName(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx,
+                Namespace_stmtContext.class, true);
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+
+        // check Yang version present, if not log
+        try {
+            BasicValidations.checkPresentYangVersion(ctx, moduleName);
+        } catch (Exception e) {
+            logger.debug(e.getMessage());
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Date is in valid format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRevision_stmt(Revision_stmtContext ctx) {
+        BasicValidations.checkDateFormat(ctx,
+                YangParserListenerImpl.simpleDateFormat);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One Prefix statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Namespace string can be parsed as URI</li>
+     * </ol>
+     */
+    @Override
+    public void enterNamespace_stmt(Namespace_stmtContext ctx) {
+        String namespaceName = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+
+        try {
+            new URI(namespaceName);
+        } catch (URISyntaxException e) {
+            ValidationUtil.ex(ValidationUtil.f(
+                    "(In module:%s) Namespace:%s cannot be parsed as URI",
+                    rootParentName, namespaceName));
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every import(identified by identifier) within a module/submodule is
+     * present only once</li>
+     * <li>One prefix statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterImport_stmt(Import_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports);
+
+        BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class,
+                true);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Date is in valid format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRevision_date_stmt(Revision_date_stmtContext ctx) {
+        BasicValidations.checkDateFormat(ctx,
+                YangParserListenerImpl.simpleDateFormat);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every include(identified by identifier) within a module/submodule is
+     * present only once</li>
+     * </ol>
+     */
+    @Override
+    public void enterInclude_stmt(Include_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Yang-version is specified as 1</li>
+     * </ol>
+     */
+    @Override
+    public void enterYang_version_stmt(YangParser.Yang_version_stmtContext ctx) {
+        String version = ValidationUtil.getName(ctx);
+        String rootParentName = ValidationUtil.getRootParentName(ctx);
+        if (!version.equals(BasicValidations.SUPPORTED_YANG_VERSION)) {
+            ValidationUtil
+                    .ex(ValidationUtil
+                            .f("(In (sub)module:%s) Unsupported yang version:%s, supported version:%s",
+                                    rootParentName, version,
+                                    BasicValidations.SUPPORTED_YANG_VERSION));
+        }
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Every prefix(identified by identifier) within a module/submodule is
+     * presented only once</li>
+     * </ol>
+     */
+    @Override
+    public void enterPrefix_stmt(Prefix_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterTypedef_stmt(Typedef_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterType_stmt(Type_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterContainer_stmt(Container_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * <li>Default statement must not be present if mandatory statement is</li>
+     * </ol>
+     */
+    @Override
+    public void enterLeaf_stmt(Leaf_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+
+        BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
+                Default_stmtContext.class);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>One type statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) {
+
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class,
+                true);
+    }
+
+    private static final Set<String> permittedOrderByArgs = Sets.newHashSet(
+            "system", "user");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: system, user</li>
+     * </ol>
+     */
+    @Override
+    public void enterOrdered_by_arg(Ordered_by_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedOrderByArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterList_stmt(List_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+        // TODO check: "if config==true then key must be present" could be
+        // performed
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>No duplicate keys</li>
+     * </ol>
+     */
+    @Override
+    public void enterKey_stmt(Key_stmtContext ctx) {
+        BasicValidations.getAndCheckUniqueKeys(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <liNo duplicate uniques</li>
+     * </ol>
+     */
+    @Override
+    public void enterUnique_stmt(Unique_stmtContext ctx) {
+        BasicValidations.getAndCheckUniqueKeys(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * <li>Default statement must not be present if mandatory statement is</li>
+     * </ol>
+     */
+    @Override
+    public void enterChoice_stmt(Choice_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+        BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class,
+                Default_stmtContext.class);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterCase_stmt(Case_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    private static final Set<String> permittedBooleanArgs = Sets.newHashSet(
+            "true", "false");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterMandatory_arg(Mandatory_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterAnyxml_stmt(Anyxml_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterGrouping_stmt(Grouping_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterUses_stmt(Uses_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRefine_stmt(Refine_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterRpc_stmt(Rpc_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterNotification_stmt(Notification_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Schema Node Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterAugment_stmt(Augment_stmtContext ctx) {
+        BasicValidations.checkSchemaNodeIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterIdentity_stmt(Identity_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterBase_stmt(Base_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterYin_element_arg(Yin_element_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterExtension_stmt(Extension_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterArgument_stmt(Argument_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterFeature_stmt(Feature_stmtContext ctx) {
+        BasicValidations.checkIdentifier(ctx);
+
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>(Prefix):Identifier is in required format</li>
+     * </ol>
+     */
+    @Override
+    public void enterIf_feature_stmt(If_feature_stmtContext ctx) {
+        BasicValidations.checkPrefixedIdentifier(ctx);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Schema Node Identifier is in required format</li>
+     * <li>At least one deviate-* statement child</li>
+     * </ol>
+     */
+    @Override
+    public void enterDeviation_stmt(Deviation_stmtContext ctx) {
+        BasicValidations.checkSchemaNodeIdentifier(ctx);
+
+        Set<Class<? extends ParseTree>> types = Sets.newHashSet();
+        types.add(Deviate_add_stmtContext.class);
+        types.add(Deviate_add_stmtContext.class);
+        BasicValidations.checkPresentChildOfTypes(ctx, types, false);
+    }
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: true, false</li>
+     * </ol>
+     */
+    @Override
+    public void enterConfig_arg(Config_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs);
+    }
+
+    private static final Set<String> permittedStatusArgs = Sets.newHashSet(
+            "current", "deprecated", "obsolete");
+
+    /**
+     * Constraints:
+     * <ol>
+     * <li>Value must be one of: "current", "deprecated", "obsolete"</li>
+     * </ol>
+     */
+    @Override
+    public void enterStatus_arg(Status_argContext ctx) {
+        BasicValidations.checkOnlyPermittedValues(ctx, permittedStatusArgs);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidator.java b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidator.java
new file mode 100644 (file)
index 0000000..ac00bc1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import java.util.List;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+/**
+ * Exposed basic yang validation.
+ *
+ * Every file is validated using {@link YangModelBasicValidationListener}.
+ */
+public final class YangModelBasicValidator {
+
+    private final ParseTreeWalker walker;
+
+    public YangModelBasicValidator(ParseTreeWalker walker) {
+        this.walker = walker;
+    }
+
+    public YangModelBasicValidator() {
+        this.walker = new ParseTreeWalker();
+    }
+
+    public void validate(List<ParseTree> trees) {
+        for (int i = 0; i < trees.size(); i++) {
+            try {
+                final YangModelBasicValidationListener yangModelParser = new YangModelBasicValidationListener();
+                walker.walk(yangModelParser, trees.get(i));
+            } catch (YangValidationException e) {
+                // wrap exception to add information about which file failed
+                throw new YangValidationException(
+                        "Yang validation failed for file" + e);
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/AugmentTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/AugmentTest.java
new file mode 100644 (file)
index 0000000..d6f6356
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.Leafref;
+
+import com.google.common.collect.Lists;
+
+public class AugmentTest {
+
+    private final URI types1NS = URI.create("urn:simple.nodes.test");
+    private final URI types2NS = URI.create("urn:simple.types.test");
+    private final URI types3NS = URI.create("urn:custom.nodes.test");
+    private Date types1Rev;
+    private Date types2Rev;
+    private Date types3Rev;
+    private final String t1 = "n";
+    private final String t2 = "t";
+    private final String t3 = "c";
+    private QName q0;
+    private QName q1;
+    private QName q2;
+
+    private final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+    private Set<Module> modules;
+
+    @Before
+    public void init() throws FileNotFoundException, ParseException {
+        types1Rev = simpleDateFormat.parse("2013-02-27");
+        types2Rev = simpleDateFormat.parse("2013-07-03");
+        types3Rev = simpleDateFormat.parse("2013-02-27");
+
+        q0 = new QName(types2NS, types2Rev, t2, "interfaces");
+        q1 = new QName(types2NS, types2Rev, t2, "ifEntry");
+        q2 = new QName(types3NS, types3Rev, t3, "augment-holder");
+
+        modules = TestUtils.loadModules(getClass().getResource("/model").getPath());
+        assertEquals(3, modules.size());
+    }
+
+    @Test
+    public void testAugmentParsing() {
+        SchemaPath expectedPath = null;
+        QName[] qnames = null;
+
+        // testfile1
+        Module module1 = TestUtils.findModule(modules, "nodes");
+        Set<AugmentationSchema> augmentations = module1.getAugmentations();
+        assertEquals(1, augmentations.size());
+        AugmentationSchema augment = augmentations.iterator().next();
+
+        Set<DataSchemaNode> augmentChildren = augment.getChildNodes();
+        assertEquals(5, augmentChildren.size());
+        for(DataSchemaNode dsn : augmentChildren) {
+            assertTrue(dsn.isAugmenting());
+        }
+
+        LeafSchemaNode ds0ChannelNumber = (LeafSchemaNode) augment.getDataChildByName("ds0ChannelNumber");
+        LeafSchemaNode interfaceId = (LeafSchemaNode) augment.getDataChildByName("interface-id");
+        LeafSchemaNode myType = (LeafSchemaNode) augment.getDataChildByName("my-type");
+        ContainerSchemaNode schemas = (ContainerSchemaNode) augment.getDataChildByName("schemas");
+        ChoiceNode odl = (ChoiceNode)augment.getDataChildByName("odl");
+
+        assertNotNull(ds0ChannelNumber);
+        assertNotNull(interfaceId);
+        assertNotNull(myType);
+        assertNotNull(schemas);
+        assertNotNull(odl);
+
+        qnames = new QName[4];
+        qnames[0] = q0;
+        qnames[1] = q1;
+        qnames[2] = q2;
+
+        // leaf ds0ChannelNumber
+        qnames[3] = new QName(types1NS, types1Rev, t1, "ds0ChannelNumber");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, ds0ChannelNumber.getPath());
+
+        // leaf interface-id
+        qnames[3] = new QName(types1NS, types1Rev, t1, "interface-id");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, interfaceId.getPath());
+
+        // leaf my-type
+        qnames[3] = new QName(types1NS, types1Rev, t1, "my-type");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, myType.getPath());
+
+        // container schemas
+        qnames[3] = new QName(types1NS, types1Rev, t1, "schemas");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, schemas.getPath());
+
+        // choice odl
+        qnames[3] = new QName(types1NS, types1Rev, t1, "odl");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, odl.getPath());
+
+
+        // testfile3
+        Module module3 = TestUtils.findModule(modules, "custom");
+        augmentations = module3.getAugmentations();
+        assertEquals(3, augmentations.size());
+        AugmentationSchema augment1 = null;
+        AugmentationSchema augment2 = null;
+        AugmentationSchema augment3 = null;
+        for (AugmentationSchema as : augmentations) {
+            if("if:ifType='ds0'".equals(as.getWhenCondition().toString())) {
+                augment1 = as;
+            } else if("if:ifType='ds2'".equals(as.getWhenCondition().toString())) {
+                augment2 = as;
+            } else if ("if:leafType='ds1'".equals(as.getWhenCondition().toString())) {
+                augment3 = as;
+            }
+        }
+        assertNotNull(augment1);
+        assertNotNull(augment2);
+        assertNotNull(augment3);
+
+        assertEquals(1, augment1.getChildNodes().size());
+        ContainerSchemaNode augmentHolder = (ContainerSchemaNode) augment1.getDataChildByName("augment-holder");
+        assertTrue(augmentHolder.isAugmenting());
+
+        assertEquals(1, augment2.getChildNodes().size());
+        ContainerSchemaNode augmentHolder2 = (ContainerSchemaNode) augment2.getDataChildByName("augment-holder2");
+        assertTrue(augmentHolder2.isAugmenting());
+
+        assertEquals(1, augment3.getChildNodes().size());
+        LeafSchemaNode linkleaf = (LeafSchemaNode) augment3.getDataChildByName("linkleaf");
+        assertTrue(linkleaf.isAugmenting());
+    }
+
+    @Test
+    public void testAugmentResolving() throws ParseException {
+        SchemaPath expectedPath = null;
+        QName[] qnames = null;
+
+        Module module2 = TestUtils.findModule(modules, "types");
+        ContainerSchemaNode interfaces = (ContainerSchemaNode) module2.getDataChildByName("interfaces");
+        ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+        ContainerSchemaNode augmentedContainer = (ContainerSchemaNode) ifEntry.getDataChildByName("augment-holder");
+
+        // testfile1.yang
+        // augment "/data:interfaces/data:ifEntry/t3:augment-holder"
+        LeafSchemaNode ds0ChannelNumber = (LeafSchemaNode) augmentedContainer.getDataChildByName("ds0ChannelNumber");
+        LeafSchemaNode interfaceId = (LeafSchemaNode) augmentedContainer.getDataChildByName("interface-id");
+        LeafSchemaNode myType = (LeafSchemaNode) augmentedContainer.getDataChildByName("my-type");
+        ContainerSchemaNode schemas = (ContainerSchemaNode) augmentedContainer.getDataChildByName("schemas");
+        ChoiceNode odl = (ChoiceNode)augmentedContainer.getDataChildByName("odl");
+
+        assertNotNull(ds0ChannelNumber);
+        assertNotNull(interfaceId);
+        assertNotNull(myType);
+        assertNotNull(schemas);
+        assertNotNull(odl);
+
+        qnames = new QName[4];
+        qnames[0] = q0;
+        qnames[1] = q1;
+        qnames[2] = q2;
+
+        // leaf ds0ChannelNumber
+        qnames[3] = new QName(types1NS, types1Rev, t1, "ds0ChannelNumber");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, ds0ChannelNumber.getPath());
+
+        // leaf interface-id
+        qnames[3] = new QName(types1NS, types1Rev, t1, "interface-id");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, interfaceId.getPath());
+
+        // leaf my-type
+        qnames[3] = new QName(types1NS, types1Rev, t1, "my-type");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, myType.getPath());
+
+        // container schemas
+        qnames[3] = new QName(types1NS, types1Rev, t1, "schemas");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, schemas.getPath());
+
+        // choice odl
+        qnames[3] = new QName(types1NS, types1Rev, t1, "odl");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, odl.getPath());
+
+        // testfile3.yang
+        // augment "/data:interfaces/data:ifEntry/t3:augment-holder/t1:schemas"
+        LeafSchemaNode linkleaf = (LeafSchemaNode) schemas.getDataChildByName("linkleaf");
+        assertNotNull(linkleaf);
+
+        qnames = new QName[5];
+        qnames[0] = q0;
+        qnames[1] = q1;
+        qnames[2] = q2;
+        qnames[3] = new QName(types1NS, types1Rev, t1, "schemas");
+        qnames[4] = new QName(types3NS, types3Rev, t3, "linkleaf");
+        expectedPath = new SchemaPath(Arrays.asList(qnames), true);
+        assertEquals(expectedPath, linkleaf.getPath());
+    }
+
+    @Test
+    public void testAugmentChoice() throws ParseException {
+        SchemaPath expectedPath = null;
+        QName[] qnames = null;
+
+        Module module2 = TestUtils.findModule(modules, "types");
+        ContainerSchemaNode interfaces = (ContainerSchemaNode) module2.getDataChildByName("interfaces");
+        ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+        ContainerSchemaNode augmentedContainer = (ContainerSchemaNode) ifEntry.getDataChildByName("augment-holder");
+
+        // testfile1.yang
+        // augment "/data:interfaces/data:ifEntry/t3:augment-holder"
+        ChoiceNode odl = (ChoiceNode)augmentedContainer.getDataChildByName("odl");
+        assertNotNull(odl);
+        Set<ChoiceCaseNode> cases = odl.getCases();
+        assertEquals(4, cases.size());
+
+        ChoiceCaseNode id = null;
+        ChoiceCaseNode node1 = null;
+        ChoiceCaseNode node2 = null;
+        ChoiceCaseNode node3 = null;
+
+        for(ChoiceCaseNode ccn : cases) {
+            if("id".equals(ccn.getQName().getLocalName())) {
+                id = ccn;
+            } else if("node1".equals(ccn.getQName().getLocalName())) {
+                node1 = ccn;
+            } else if("node2".equals(ccn.getQName().getLocalName())) {
+                node2 = ccn;
+            } else if("node3".equals(ccn.getQName().getLocalName())) {
+                node3 = ccn;
+            }
+        }
+
+        assertNotNull(id);
+        assertNotNull(node1);
+        assertNotNull(node2);
+        assertNotNull(node3);
+
+        qnames = new QName[5];
+        qnames[0] = q0;
+        qnames[1] = q1;
+        qnames[2] = q2;
+        qnames[3] = new QName(types1NS, types1Rev, t1, "odl");
+
+        // case id
+        qnames[4] = new QName(types1NS, types1Rev, t1, "id");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, id.getPath());
+        Set<DataSchemaNode> idChildren = id.getChildNodes();
+        assertEquals(1, idChildren.size());
+
+        // case node1
+        qnames[4] = new QName(types1NS, types1Rev, t1, "node1");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, node1.getPath());
+        Set<DataSchemaNode> node1Children = node1.getChildNodes();
+        assertTrue(node1Children.isEmpty());
+
+        // case node2
+        qnames[4] = new QName(types1NS, types1Rev, t1, "node2");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, node2.getPath());
+        Set<DataSchemaNode> node2Children = node2.getChildNodes();
+        assertTrue(node2Children.isEmpty());
+
+        // case node3
+        qnames[4] = new QName(types1NS, types1Rev, t1, "node3");
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, node3.getPath());
+        Set<DataSchemaNode> node3Children = node3.getChildNodes();
+        assertEquals(1, node3Children.size());
+
+        // test cases
+        qnames = new QName[6];
+        qnames[0] = q0;
+        qnames[1] = q1;
+        qnames[2] = q2;
+        qnames[3] = new QName(types1NS, types1Rev, t1, "odl");
+
+        // case id child
+        qnames[4] = new QName(types1NS, types1Rev, t1, "id");
+        qnames[5] = new QName(types1NS, types1Rev, t1, "id");
+        LeafSchemaNode caseIdChild = (LeafSchemaNode)idChildren.iterator().next();
+        assertNotNull(caseIdChild);
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, caseIdChild.getPath());
+
+        // case node3 child
+        qnames[4] = new QName(types1NS, types1Rev, t1, "node3");
+        qnames[5] = new QName(types1NS, types1Rev, t1, "node3");
+        ContainerSchemaNode caseNode3Child = (ContainerSchemaNode)node3Children.iterator().next();
+        assertNotNull(caseNode3Child);
+        expectedPath = new SchemaPath(Lists.newArrayList(qnames), true);
+        assertEquals(expectedPath, caseNode3Child.getPath());
+    }
+
+    @Test
+    public void testAugmentNodesTypeSchemaPath() throws Exception {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        Set<AugmentationSchema> augments = testModule.getAugmentations();
+        assertEquals(1, augments.size());
+        AugmentationSchema augment = augments.iterator().next();
+
+        LeafSchemaNode ifcId = (LeafSchemaNode) augment.getDataChildByName("interface-id");
+        Leafref ifcIdType = (Leafref) ifcId.getType();
+        SchemaPath ifcIdTypeSchemaPath = ifcIdType.getPath();
+        List<QName> ifcIdTypePath = ifcIdTypeSchemaPath.getPath();
+
+        Date expectedDate = simpleDateFormat.parse("2013-02-27");
+
+        QName q3 = new QName(types1NS, expectedDate, "data", "interface-id");
+        assertEquals(q0, ifcIdTypePath.get(0));
+        assertEquals(q1, ifcIdTypePath.get(1));
+        assertEquals(q2, ifcIdTypePath.get(2));
+        assertEquals(q3, ifcIdTypePath.get(3));
+
+        LeafSchemaNode myType = (LeafSchemaNode) augment.getDataChildByName("my-type");
+        ExtendedType leafType = (ExtendedType) myType.getType();
+
+        testModule = TestUtils.findModule(modules, "types");
+        TypeDefinition<?> typedef = TestUtils.findTypedef(testModule.getTypeDefinitions(), "int32-ext2");
+
+        assertEquals(typedef, leafType);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/GroupingTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/GroupingTest.java
new file mode 100644 (file)
index 0000000..e62fdb6
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+
+public class GroupingTest {
+    private Set<Module> modules;
+
+    @Before
+    public void init() throws FileNotFoundException {
+        modules = TestUtils.loadModules(getClass().getResource("/model").getPath());
+        assertEquals(3, modules.size());
+    }
+
+    @Test
+    public void testRefine() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+
+        ContainerSchemaNode peer = (ContainerSchemaNode) testModule.getDataChildByName("peer");
+        ContainerSchemaNode destination = (ContainerSchemaNode) peer.getDataChildByName("destination");
+        Set<UsesNode> usesNodes = destination.getUses();
+        assertEquals(1, usesNodes.size());
+        UsesNode usesNode = usesNodes.iterator().next();
+        Map<SchemaPath, SchemaNode> refines = usesNode.getRefines();
+        assertEquals(5, refines.size());
+
+        LeafSchemaNode refineLeaf = null;
+        ContainerSchemaNode refineContainer = null;
+        ListSchemaNode refineList = null;
+        GroupingDefinition refineGrouping = null;
+        TypeDefinition<?> typedef = null;
+        for (Map.Entry<SchemaPath, SchemaNode> entry : refines.entrySet()) {
+            SchemaNode value = entry.getValue();
+            if (value instanceof LeafSchemaNode) {
+                refineLeaf = (LeafSchemaNode) value;
+            } else if (value instanceof ContainerSchemaNode) {
+                refineContainer = (ContainerSchemaNode) value;
+            } else if (value instanceof ListSchemaNode) {
+                refineList = (ListSchemaNode) value;
+            } else if (value instanceof GroupingDefinition) {
+                refineGrouping = (GroupingDefinition) value;
+            } else if (value instanceof TypeDefinition<?>) {
+                typedef = (TypeDefinition<?>) value;
+            }
+        }
+
+        // leaf address
+        assertNotNull(refineLeaf);
+        assertEquals("address", refineLeaf.getQName().getLocalName());
+        assertEquals("IP address of target node", refineLeaf.getDescription());
+        assertEquals("address reference added by refine", refineLeaf.getReference());
+        assertFalse(refineLeaf.isConfiguration());
+        assertTrue(refineLeaf.getConstraints().isMandatory());
+        Set<MustDefinition> leafMustConstraints = refineLeaf.getConstraints().getMustConstraints();
+        assertEquals(1, leafMustConstraints.size());
+        MustDefinition leafMust = leafMustConstraints.iterator().next();
+        assertEquals("\"ifType != 'ethernet' or (ifType = 'ethernet' and ifMTU = 1500)\"", leafMust.toString());
+
+        // container port
+        assertNotNull(refineContainer);
+        Set<MustDefinition> mustConstraints = refineContainer.getConstraints().getMustConstraints();
+        assertTrue(mustConstraints.isEmpty());
+        assertEquals("description of port defined by refine", refineContainer.getDescription());
+        assertEquals("port reference added by refine", refineContainer.getReference());
+        assertFalse(refineContainer.isConfiguration());
+        assertTrue(refineContainer.isPresenceContainer());
+
+        // list addresses
+        assertNotNull(refineList);
+        assertEquals("description of addresses defined by refine", refineList.getDescription());
+        assertEquals("addresses reference added by refine", refineList.getReference());
+        assertFalse(refineList.isConfiguration());
+        assertEquals(2, (int) refineList.getConstraints().getMinElements());
+        assertEquals(12, (int) refineList.getConstraints().getMaxElements());
+
+        // grouping target-inner
+        assertNotNull(refineGrouping);
+        Set<DataSchemaNode> refineGroupingChildren = refineGrouping.getChildNodes();
+        assertEquals(1, refineGroupingChildren.size());
+        LeafSchemaNode refineGroupingLeaf = (LeafSchemaNode) refineGroupingChildren.iterator().next();
+        assertEquals("inner-grouping-id", refineGroupingLeaf.getQName().getLocalName());
+        assertEquals("new target-inner grouping description", refineGrouping.getDescription());
+
+        // typedef group-type
+        assertNotNull(typedef);
+        assertEquals("new group-type description", typedef.getDescription());
+        assertEquals("new group-type reference", typedef.getReference());
+        assertTrue(typedef.getBaseType() instanceof ExtendedType);
+    }
+
+    @Test
+    public void testGrouping() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+        Set<GroupingDefinition> groupings = testModule.getGroupings();
+        assertEquals(1, groupings.size());
+        GroupingDefinition grouping = groupings.iterator().next();
+        Set<DataSchemaNode> children = grouping.getChildNodes();
+        assertEquals(5, children.size());
+    }
+
+    @Test
+    public void testUses() {
+        // suffix _u = added by uses
+        // suffix _g = defined in grouping
+
+        Module testModule = TestUtils.findModule(modules, "custom");
+
+        // get grouping
+        Set<GroupingDefinition> groupings = testModule.getGroupings();
+        assertEquals(1, groupings.size());
+        GroupingDefinition grouping = groupings.iterator().next();
+
+        testModule = TestUtils.findModule(modules, "nodes");
+
+        // get node containing uses
+        ContainerSchemaNode peer = (ContainerSchemaNode) testModule.getDataChildByName("peer");
+        ContainerSchemaNode destination = (ContainerSchemaNode) peer.getDataChildByName("destination");
+
+        // check uses
+        Set<UsesNode> uses = destination.getUses();
+        assertEquals(1, uses.size());
+
+        // check uses process
+        AnyXmlSchemaNode data_u = (AnyXmlSchemaNode) destination.getDataChildByName("data");
+        assertNotNull(data_u);
+        assertTrue(data_u.isAddedByUses());
+
+        AnyXmlSchemaNode data_g = (AnyXmlSchemaNode) grouping.getDataChildByName("data");
+        assertNotNull(data_g);
+        assertFalse(data_g.isAddedByUses());
+        assertFalse(data_u.equals(data_g));
+
+        ChoiceNode how_u = (ChoiceNode) destination.getDataChildByName("how");
+        assertNotNull(how_u);
+        assertTrue(how_u.isAddedByUses());
+
+        ChoiceNode how_g = (ChoiceNode) grouping.getDataChildByName("how");
+        assertNotNull(how_g);
+        assertFalse(how_g.isAddedByUses());
+        assertFalse(how_u.equals(how_g));
+
+        LeafSchemaNode address_u = (LeafSchemaNode) destination.getDataChildByName("address");
+        assertNotNull(address_u);
+        assertEquals("1.2.3.4", address_u.getDefault());
+        assertEquals("IP address of target node", address_u.getDescription());
+        assertEquals("address reference added by refine", address_u.getReference());
+        assertFalse(address_u.isConfiguration());
+        assertTrue(address_u.isAddedByUses());
+
+        LeafSchemaNode address_g = (LeafSchemaNode) grouping.getDataChildByName("address");
+        assertNotNull(address_g);
+        assertFalse(address_g.isAddedByUses());
+        assertNull(address_g.getDefault());
+        assertEquals("Target IP address", address_g.getDescription());
+        assertNull(address_g.getReference());
+        assertTrue(address_g.isConfiguration());
+        assertFalse(address_u.equals(address_g));
+
+        ContainerSchemaNode port_u = (ContainerSchemaNode) destination.getDataChildByName("port");
+        assertNotNull(port_u);
+        assertTrue(port_u.isAddedByUses());
+
+        ContainerSchemaNode port_g = (ContainerSchemaNode) grouping.getDataChildByName("port");
+        assertNotNull(port_g);
+        assertFalse(port_g.isAddedByUses());
+        assertFalse(port_u.equals(port_g));
+
+        ListSchemaNode addresses_u = (ListSchemaNode) destination.getDataChildByName("addresses");
+        assertNotNull(addresses_u);
+        assertTrue(addresses_u.isAddedByUses());
+
+        ListSchemaNode addresses_g = (ListSchemaNode) grouping.getDataChildByName("addresses");
+        assertNotNull(addresses_g);
+        assertFalse(addresses_g.isAddedByUses());
+        assertFalse(addresses_u.equals(addresses_g));
+
+        // grouping defined by 'uses'
+        Set<GroupingDefinition> groupings_u = destination.getGroupings();
+        assertEquals(1, groupings_u.size());
+        GroupingDefinition grouping_u = groupings_u.iterator().next();
+        assertTrue(grouping_u.isAddedByUses());
+
+        // grouping defined in 'grouping' node
+        Set<GroupingDefinition> groupings_g = grouping.getGroupings();
+        assertEquals(1, groupings_g.size());
+        GroupingDefinition grouping_g = groupings_g.iterator().next();
+        assertFalse(grouping_g.isAddedByUses());
+        assertFalse(grouping_u.equals(grouping_g));
+
+        List<UnknownSchemaNode> nodes_u = destination.getUnknownSchemaNodes();
+        assertEquals(1, nodes_u.size());
+        UnknownSchemaNode node_u = nodes_u.get(0);
+        assertTrue(node_u.isAddedByUses());
+
+        List<UnknownSchemaNode> nodes_g = grouping.getUnknownSchemaNodes();
+        assertEquals(1, nodes_g.size());
+        UnknownSchemaNode node_g = nodes_g.get(0);
+        assertFalse(node_g.isAddedByUses());
+        assertFalse(node_u.equals(node_g));
+    }
+
+    @Test
+    public void testUsesUnderModule() {
+        // suffix _u = added by uses
+        // suffix _g = defined in grouping
+
+        Module testModule = TestUtils.findModule(modules, "custom");
+
+        // get grouping
+        Set<GroupingDefinition> groupings = testModule.getGroupings();
+        assertEquals(1, groupings.size());
+        GroupingDefinition grouping = groupings.iterator().next();
+
+        // get node containing uses
+        Module destination = TestUtils.findModule(modules, "nodes");
+
+        // check uses
+        Set<UsesNode> uses = destination.getUses();
+        assertEquals(1, uses.size());
+
+        // check uses process
+        AnyXmlSchemaNode data_u = (AnyXmlSchemaNode) destination.getDataChildByName("data");
+        assertNotNull(data_u);
+        assertTrue(data_u.isAddedByUses());
+
+        AnyXmlSchemaNode data_g = (AnyXmlSchemaNode) grouping.getDataChildByName("data");
+        assertNotNull(data_g);
+        assertFalse(data_g.isAddedByUses());
+        assertFalse(data_u.equals(data_g));
+
+        ChoiceNode how_u = (ChoiceNode) destination.getDataChildByName("how");
+        assertNotNull(how_u);
+        assertTrue(how_u.isAddedByUses());
+
+        ChoiceNode how_g = (ChoiceNode) grouping.getDataChildByName("how");
+        assertNotNull(how_g);
+        assertFalse(how_g.isAddedByUses());
+        assertFalse(how_u.equals(how_g));
+
+        LeafSchemaNode address_u = (LeafSchemaNode) destination.getDataChildByName("address");
+        assertNotNull(address_u);
+        assertNull(address_u.getDefault());
+        assertEquals("Target IP address", address_u.getDescription());
+        assertNull(address_u.getReference());
+        assertTrue(address_u.isConfiguration());
+        assertTrue(address_u.isAddedByUses());
+
+        LeafSchemaNode address_g = (LeafSchemaNode) grouping.getDataChildByName("address");
+        assertNotNull(address_g);
+        assertFalse(address_g.isAddedByUses());
+        assertNull(address_g.getDefault());
+        assertEquals("Target IP address", address_g.getDescription());
+        assertNull(address_g.getReference());
+        assertTrue(address_g.isConfiguration());
+        assertFalse(address_u.equals(address_g));
+
+        ContainerSchemaNode port_u = (ContainerSchemaNode) destination.getDataChildByName("port");
+        assertNotNull(port_u);
+        assertTrue(port_u.isAddedByUses());
+
+        ContainerSchemaNode port_g = (ContainerSchemaNode) grouping.getDataChildByName("port");
+        assertNotNull(port_g);
+        assertFalse(port_g.isAddedByUses());
+        assertFalse(port_u.equals(port_g));
+
+        ListSchemaNode addresses_u = (ListSchemaNode) destination.getDataChildByName("addresses");
+        assertNotNull(addresses_u);
+        assertTrue(addresses_u.isAddedByUses());
+
+        ListSchemaNode addresses_g = (ListSchemaNode) grouping.getDataChildByName("addresses");
+        assertNotNull(addresses_g);
+        assertFalse(addresses_g.isAddedByUses());
+        assertFalse(addresses_u.equals(addresses_g));
+
+        // grouping defined by 'uses'
+        Set<GroupingDefinition> groupings_u = destination.getGroupings();
+        assertEquals(1, groupings_u.size());
+        GroupingDefinition grouping_u = groupings_u.iterator().next();
+        assertTrue(grouping_u.isAddedByUses());
+
+        // grouping defined in 'grouping' node
+        Set<GroupingDefinition> groupings_g = grouping.getGroupings();
+        assertEquals(1, groupings_g.size());
+        GroupingDefinition grouping_g = groupings_g.iterator().next();
+        assertFalse(grouping_g.isAddedByUses());
+        assertFalse(grouping_u.equals(grouping_g));
+
+        List<UnknownSchemaNode> nodes_u = destination.getUnknownSchemaNodes();
+        assertEquals(1, nodes_u.size());
+        UnknownSchemaNode node_u = nodes_u.get(0);
+        assertTrue(node_u.isAddedByUses());
+
+        List<UnknownSchemaNode> nodes_g = grouping.getUnknownSchemaNodes();
+        assertEquals(1, nodes_g.size());
+        UnknownSchemaNode node_g = nodes_g.get(0);
+        assertFalse(node_g.isAddedByUses());
+        assertFalse(node_u.equals(node_g));
+
+        UsesNode un = uses.iterator().next();
+        Set<AugmentationSchema> usesAugments = un.getAugmentations();
+        assertEquals(1, usesAugments.size());
+        AugmentationSchema augment = usesAugments.iterator().next();
+        assertEquals("inner augment", augment.getDescription());
+        Set<DataSchemaNode> children = augment.getChildNodes();
+        assertEquals(1, children.size());
+        DataSchemaNode leaf = children.iterator().next();
+        assertTrue(leaf instanceof LeafSchemaNode);
+        assertEquals("name", leaf.getQName().getLocalName());
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TestUtils.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TestUtils.java
new file mode 100644 (file)
index 0000000..fed8cde
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
+
+final class TestUtils {
+
+    private TestUtils() {
+    }
+
+    public static Set<Module> loadModules(String resourceDirectory) throws FileNotFoundException {
+        YangModelParser parser = new YangParserImpl();
+        final File testDir = new File(resourceDirectory);
+        final String[] fileList = testDir.list();
+        final List<File> testFiles = new ArrayList<File>();
+        if(fileList == null) {
+            throw new FileNotFoundException(resourceDirectory);
+        }
+        for (int i = 0; i < fileList.length; i++) {
+            String fileName = fileList[i];
+            testFiles.add(new File(testDir, fileName));
+        }
+        return parser.parseYangModels(testFiles);
+    }
+
+    public static Set<Module> loadModules(List<InputStream> input) throws IOException {
+        final YangModelParser parser = new YangParserImpl();
+        final Set<Module> modules = new HashSet<Module>(
+                parser.parseYangModelsFromStreams(input));
+        for(InputStream stream : input) {
+            stream.close();
+        }
+        return modules;
+    }
+
+    public static Module loadModule(final InputStream stream) throws
+            IOException {
+        final YangModelParser parser = new YangParserImpl();
+        final List<InputStream> input = Collections.singletonList(stream);
+        final Set<Module> modules = new HashSet<Module>(
+                parser.parseYangModelsFromStreams(input));
+        stream.close();
+        return modules.iterator().next();
+    }
+
+    public static Module loadModuleWithContext(final InputStream stream, final SchemaContext context) throws IOException {
+        final YangModelParser parser = new YangParserImpl();
+        final List<InputStream> input = Collections.singletonList(stream);
+        final Set<Module> modules = new HashSet<Module>(parser.parseYangModelsFromStreams(input, context));
+        stream.close();
+        return modules.iterator().next();
+    }
+
+    public static Set<Module> loadModulesWithContext(final List<InputStream> input, final SchemaContext context) throws IOException {
+        final YangModelParser parser = new YangParserImpl();
+        final Set<Module> modules = new HashSet<Module>(parser.parseYangModelsFromStreams(input, context));
+        for(InputStream is : input) {
+            if(is != null) {
+                is.close();
+            }
+        }
+        return modules;
+    }
+
+    public static Module findModule(Set<Module> modules, String moduleName) {
+        Module result = null;
+        for (Module module : modules) {
+            if (module.getName().equals(moduleName)) {
+                result = module;
+                break;
+            }
+        }
+        return result;
+    }
+
+    public static ModuleImport findImport(Set<ModuleImport> imports,
+            String prefix) {
+        ModuleImport result = null;
+        for (ModuleImport moduleImport : imports) {
+            if (moduleImport.getPrefix().equals(prefix)) {
+                result = moduleImport;
+                break;
+            }
+        }
+        return result;
+    }
+
+    public static TypeDefinition<?> findTypedef(
+            Set<TypeDefinition<?>> typedefs, String name) {
+        TypeDefinition<?> result = null;
+        for (TypeDefinition<?> td : typedefs) {
+            if (td.getQName().getLocalName().equals(name)) {
+                result = td;
+                break;
+            }
+        }
+        return result;
+    }
+
+    public static SchemaPath createPath(boolean absolute, URI namespace,
+            Date revision, String prefix, String... names) {
+        List<QName> path = new ArrayList<QName>();
+        for (String name : names) {
+            path.add(new QName(namespace, revision, prefix, name));
+        }
+        return new SchemaPath(path, absolute);
+    }
+
+    public static Date createDate(String date) {
+        Date result;
+        final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            result = simpleDateFormat.parse(date);
+        } catch (ParseException e) {
+            result = null;
+        }
+        return result;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TypesResolutionTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TypesResolutionTest.java
new file mode 100644 (file)
index 0000000..d9f256c
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
+import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.controller.yang.model.util.BitsType;
+import org.opendaylight.controller.yang.model.util.EnumerationType;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.IdentityrefType;
+import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
+import org.opendaylight.controller.yang.model.util.UnionType;
+
+public class TypesResolutionTest {
+    private Set<Module> testedModules;
+
+    @Before
+    public void init() throws FileNotFoundException {
+        testedModules = TestUtils.loadModules(getClass().getResource("/types").getPath());
+    }
+
+    @Test
+    public void testIPVersion() {
+        Module tested = TestUtils.findModule(testedModules, "ietf-inet-types");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        assertEquals(14, typedefs.size());
+
+        TypeDefinition<?> type = TestUtils.findTypedef(typedefs, "ip-version");
+        assertTrue(type.getDescription().contains("This value represents the version of the IP protocol."));
+        assertTrue(type.getReference().contains("RFC 2460: Internet Protocol, Version 6 (IPv6) Specification"));
+
+        EnumerationType enumType = (EnumerationType) type.getBaseType();
+        List<EnumPair> values = enumType.getValues();
+        assertEquals(3, values.size());
+
+        EnumPair value0 = values.get(0);
+        assertEquals("unknown", value0.getName());
+        assertEquals(0, (int) value0.getValue());
+        assertEquals("An unknown or unspecified version of the Internet protocol.", value0.getDescription());
+
+        EnumPair value1 = values.get(1);
+        assertEquals("ipv4", value1.getName());
+        assertEquals(1, (int) value1.getValue());
+        assertEquals("The IPv4 protocol as defined in RFC 791.", value1.getDescription());
+
+        EnumPair value2 = values.get(2);
+        assertEquals("ipv6", value2.getName());
+        assertEquals(2, (int) value2.getValue());
+        assertEquals("The IPv6 protocol as defined in RFC 2460.", value2.getDescription());
+    }
+
+    @Test
+    public void testEnumeration() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+
+        TypeDefinition<?> type = TestUtils.findTypedef(typedefs, "ip-version");
+        EnumerationType enumType = (EnumerationType) type.getBaseType();
+        List<EnumPair> values = enumType.getValues();
+        assertEquals(4, values.size());
+
+        EnumPair value0 = values.get(0);
+        assertEquals("unknown", value0.getName());
+        assertEquals(0, (int) value0.getValue());
+        assertEquals("An unknown or unspecified version of the Internet protocol.", value0.getDescription());
+
+        EnumPair value1 = values.get(1);
+        assertEquals("ipv4", value1.getName());
+        assertEquals(19, (int) value1.getValue());
+        assertEquals("The IPv4 protocol as defined in RFC 791.", value1.getDescription());
+
+        EnumPair value2 = values.get(2);
+        assertEquals("ipv6", value2.getName());
+        assertEquals(7, (int) value2.getValue());
+        assertEquals("The IPv6 protocol as defined in RFC 2460.", value2.getDescription());
+
+        EnumPair value3 = values.get(3);
+        assertEquals("default", value3.getName());
+        assertEquals(20, (int) value3.getValue());
+        assertEquals("default ip", value3.getDescription());
+    }
+
+    @Test
+    public void testIpAddress() {
+        Module tested = TestUtils.findModule(testedModules, "ietf-inet-types");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        TypeDefinition<?> type = TestUtils.findTypedef(typedefs, "ip-address");
+        UnionType baseType = (UnionType) type.getBaseType();
+        List<TypeDefinition<?>> unionTypes = baseType.getTypes();
+
+        ExtendedType ipv4 = (ExtendedType) unionTypes.get(0);
+        assertTrue(ipv4.getBaseType() instanceof StringTypeDefinition);
+        String expectedPattern = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}"
+                + "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" + "(%[\\p{N}\\p{L}]+)?";
+        assertEquals(expectedPattern, ipv4.getPatterns().get(0).getRegularExpression());
+
+        TypeDefinition<?> ipv4Address = TestUtils.findTypedef(typedefs, "ipv4-address");
+        assertEquals(ipv4Address, ipv4);
+
+        ExtendedType ipv6 = (ExtendedType) unionTypes.get(1);
+        assertTrue(ipv6.getBaseType() instanceof StringTypeDefinition);
+        List<PatternConstraint> ipv6Patterns = ipv6.getPatterns();
+        expectedPattern = "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}"
+                + "((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|" + "(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}"
+                + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))" + "(%[\\p{N}\\p{L}]+)?";
+        assertEquals(expectedPattern, ipv6Patterns.get(0).getRegularExpression());
+
+        TypeDefinition<?> ipv6Address = TestUtils.findTypedef(typedefs, "ipv6-address");
+        assertEquals(ipv6Address, ipv6);
+
+        expectedPattern = "(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|" + "((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)"
+                + "(%.+)?";
+        assertEquals(expectedPattern, ipv6Patterns.get(1).getRegularExpression());
+    }
+
+    @Test
+    public void testDomainName() {
+        Module tested = TestUtils.findModule(testedModules, "ietf-inet-types");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        ExtendedType type = (ExtendedType) TestUtils.findTypedef(typedefs, "domain-name");
+        assertTrue(type.getBaseType() instanceof StringTypeDefinition);
+        List<PatternConstraint> patterns = type.getPatterns();
+        assertEquals(1, patterns.size());
+        String expectedPattern = "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*"
+                + "([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)" + "|\\.";
+        assertEquals(expectedPattern, patterns.get(0).getRegularExpression());
+
+        List<LengthConstraint> lengths = type.getLengths();
+        assertEquals(1, lengths.size());
+        LengthConstraint length = type.getLengths().get(0);
+        assertEquals(1L, length.getMin());
+        assertEquals(253L, length.getMax());
+    }
+
+    @Test
+    public void testInstanceIdentifier1() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        LeafSchemaNode leaf = (LeafSchemaNode) tested.getDataChildByName("inst-id-leaf1");
+        InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType();
+        assertFalse(leafType.requireInstance());
+    }
+
+    @Test
+    public void testInstanceIdentifier2() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        LeafSchemaNode leaf = (LeafSchemaNode) tested.getDataChildByName("inst-id-leaf2");
+        InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType();
+        assertTrue(leafType.requireInstance());
+    }
+
+    @Test
+    public void testIdentity() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        Set<IdentitySchemaNode> identities = tested.getIdentities();
+        IdentitySchemaNode testedIdentity = null;
+        for (IdentitySchemaNode id : identities) {
+            if (id.getQName().getLocalName().equals("crypto-alg")) {
+                testedIdentity = id;
+                IdentitySchemaNode baseIdentity = id.getBaseIdentity();
+                assertEquals("crypto-base", baseIdentity.getQName().getLocalName());
+                assertNull(baseIdentity.getBaseIdentity());
+            }
+        }
+        assertNotNull(testedIdentity);
+    }
+
+    @Test
+    public void testBitsType1() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        LeafSchemaNode leaf = (LeafSchemaNode) tested.getDataChildByName("mybits");
+        BitsType leafType = (BitsType) leaf.getType();
+        List<Bit> bits = leafType.getBits();
+        assertEquals(3, bits.size());
+
+        Bit bit1 = bits.get(0);
+        assertEquals("disable-nagle", bit1.getName());
+        assertEquals(0L, (long) bit1.getPosition());
+
+        Bit bit2 = bits.get(1);
+        assertEquals("auto-sense-speed", bit2.getName());
+        assertEquals(1L, (long) bit2.getPosition());
+
+        Bit bit3 = bits.get(2);
+        assertEquals("10-Mb-only", bit3.getName());
+        assertEquals(2L, (long) bit3.getPosition());
+    }
+
+    @Test
+    public void testBitsType2() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        TypeDefinition<?> testedType = TestUtils.findTypedef(typedefs, "access-operations-type");
+
+        BitsType bitsType = (BitsType) testedType.getBaseType();
+        List<Bit> bits = bitsType.getBits();
+        assertEquals(5, bits.size());
+
+        Bit bit0 = bits.get(0);
+        assertEquals(0L, (long) bit0.getPosition());
+
+        Bit bit1 = bits.get(1);
+        assertEquals(500L, (long) bit1.getPosition());
+
+        Bit bit2 = bits.get(2);
+        assertEquals(501L, (long) bit2.getPosition());
+
+        Bit bit3 = bits.get(3);
+        assertEquals(365L, (long) bit3.getPosition());
+
+        Bit bit4 = bits.get(4);
+        assertEquals(502L, (long) bit4.getPosition());
+    }
+
+    @Test
+    public void testIanaTimezones() {
+        Module tested = TestUtils.findModule(testedModules, "iana-timezones");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        TypeDefinition<?> testedType = TestUtils.findTypedef(typedefs, "iana-timezone");
+
+        String expectedDesc = "A timezone location as defined by the IANA timezone";
+        assertTrue(testedType.getDescription().contains(expectedDesc));
+        assertNull(testedType.getReference());
+        assertEquals(Status.CURRENT, testedType.getStatus());
+
+        QName testedTypeQName = testedType.getQName();
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:iana-timezones"), testedTypeQName.getNamespace());
+        assertEquals(TestUtils.createDate("2012-07-09"), testedTypeQName.getRevision());
+        assertEquals("ianatz", testedTypeQName.getPrefix());
+        assertEquals("iana-timezone", testedTypeQName.getLocalName());
+
+        EnumerationType enumType = (EnumerationType) testedType.getBaseType();
+        List<EnumPair> values = enumType.getValues();
+        assertEquals(415, values.size()); // 0-414
+
+        EnumPair enum168 = values.get(168);
+        assertEquals("America/Danmarkshavn", enum168.getName());
+        assertEquals(168, (int) enum168.getValue());
+        assertEquals("east coast, north of Scoresbysund", enum168.getDescription());
+
+        EnumPair enum374 = values.get(374);
+        assertEquals("America/Indiana/Winamac", enum374.getName());
+        assertEquals(374, (int) enum374.getValue());
+        assertEquals("Eastern Time - Indiana - Pulaski County", enum374.getDescription());
+    }
+
+    @Test
+    public void testObjectId128() {
+        Module tested = TestUtils.findModule(testedModules, "ietf-yang-types");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        ExtendedType testedType = (ExtendedType) TestUtils.findTypedef(typedefs, "object-identifier-128");
+
+        List<PatternConstraint> patterns = testedType.getPatterns();
+        assertEquals(1, patterns.size());
+        PatternConstraint pattern = patterns.get(0);
+        assertEquals("\\d*(\\.\\d*){1,127}", pattern.getRegularExpression());
+
+        QName testedTypeQName = testedType.getQName();
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:ietf-yang-types"), testedTypeQName.getNamespace());
+        assertEquals(TestUtils.createDate("2010-09-24"), testedTypeQName.getRevision());
+        assertEquals("yang", testedTypeQName.getPrefix());
+        assertEquals("object-identifier-128", testedTypeQName.getLocalName());
+
+        ExtendedType testedTypeBase = (ExtendedType) testedType.getBaseType();
+        patterns = testedTypeBase.getPatterns();
+        assertEquals(1, patterns.size());
+
+        pattern = patterns.get(0);
+        assertEquals("(([0-1](\\.[1-3]?[0-9]))|(2\\.(0|([1-9]\\d*))))(\\.(0|([1-9]\\d*)))*",
+                pattern.getRegularExpression());
+
+        QName testedTypeBaseQName = testedTypeBase.getQName();
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:ietf-yang-types"), testedTypeBaseQName.getNamespace());
+        assertEquals(TestUtils.createDate("2010-09-24"), testedTypeBaseQName.getRevision());
+        assertEquals("yang", testedTypeBaseQName.getPrefix());
+        assertEquals("object-identifier", testedTypeBaseQName.getLocalName());
+    }
+
+    @Test
+    public void testIdentityref() {
+        Module tested = TestUtils.findModule(testedModules, "custom-types-test");
+        Set<TypeDefinition<?>> typedefs = tested.getTypeDefinitions();
+        TypeDefinition<?> testedType = TestUtils.findTypedef(typedefs, "service-type-ref");
+        IdentityrefType baseType = (IdentityrefType) testedType.getBaseType();
+        QName identity = baseType.getIdentity();
+        assertEquals(URI.create("urn:custom.types.demo"), identity.getNamespace());
+        assertEquals(TestUtils.createDate("2012-04-16"), identity.getRevision());
+        assertEquals("iit", identity.getPrefix());
+        assertEquals("service-type", identity.getLocalName());
+
+        LeafSchemaNode type = (LeafSchemaNode)tested.getDataChildByName("type");
+        assertNotNull(type);
+        TypeDefinition<?> leafType = type.getType();
+        assertEquals(testedType, leafType);
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserNegativeTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserNegativeTest.java
new file mode 100644 (file)
index 0000000..0f5a82f
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.opendaylight.controller.yang.parser.util.YangParseException;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+public class YangParserNegativeTest {
+
+    @Test
+    public void testInvalidImport() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource("/negative-scenario/testfile1.yang")
+                    .getPath())) {
+                TestUtils.loadModule(stream);
+                fail("ValidationException should by thrown");
+            }
+        } catch (YangValidationException e) {
+            assertTrue(e.getMessage().contains("Not existing module imported"));
+        }
+    }
+
+    @Test
+    public void testTypeNotFound() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource("/negative-scenario/testfile2.yang")
+                    .getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            assertEquals(e.getMessage(), "Error in module 'test2' at line 24: Referenced type 'int-ext' not found.");
+        }
+    }
+
+    @Test
+    public void testInvalidAugmentTarget() throws IOException {
+        try {
+            final List<InputStream> streams = new ArrayList<>(2);
+            try (InputStream testFile0 = new FileInputStream(getClass()
+                    .getResource("/negative-scenario/testfile0.yang").getPath())) {
+                streams.add(testFile0);
+                try (InputStream testFile3 = new FileInputStream(getClass().getResource(
+                        "/negative-scenario/testfile3.yang").getPath())) {
+                    streams.add(testFile3);
+                    assertEquals("Expected loaded files count is 2", 2, streams.size());
+                    TestUtils.loadModules(streams);
+                    fail("YangParseException should by thrown");
+                }
+            }
+        } catch (YangParseException e) {
+            assertTrue(e.getMessage().contains("Failed to resolve augments in module 'test3'."));
+        }
+    }
+
+    @Test
+    public void testInvalidRefine() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource("/negative-scenario/testfile4.yang")
+                    .getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            assertTrue(e.getMessage().contains("Can not refine 'presence' for 'node'."));
+        }
+    }
+
+    @Test
+    public void testInvalidLength() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource("/negative-scenario/testfile5.yang")
+                    .getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            assertTrue(e.getMessage().contains("Invalid length constraint: <4, 10>"));
+        }
+    }
+
+    @Test
+    public void testInvalidRange() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource("/negative-scenario/testfile6.yang")
+                    .getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            assertTrue(e.getMessage().contains("Invalid range constraint: <5, 20>"));
+        }
+    }
+
+    @Test
+    public void testDuplicateContainer() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/container.yang").getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'container' at line 10: Can not add 'container foo': node with same name already declared at line 6";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDuplicateContainerList() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/container-list.yang").getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'container-list' at line 10: Can not add 'list foo': node with same name already declared at line 6";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDuplicateContainerLeaf() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/container-leaf.yang").getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'container-leaf' at line 10: Can not add 'leaf foo': node with same name already declared at line 6";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDuplicateTypedef() throws IOException {
+        try {
+            try (InputStream stream = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/typedef.yang").getPath())) {
+                TestUtils.loadModule(stream);
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'typedef' at line 10: typedef with same name 'int-ext' already declared at line 6";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDuplicityInAugmentTarget1() throws Exception {
+        try {
+            try (InputStream stream1 = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/augment0.yang").getPath());
+                    InputStream stream2 = new FileInputStream(getClass().getResource(
+                            "/negative-scenario/duplicity/augment1.yang").getPath())) {
+                TestUtils.loadModules(Arrays.asList(stream1, stream2));
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'augment1' at line 11: Can not add 'leaf id' to 'container bar' in module 'augment0': node with same name already declared at line 9";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+    @Test
+    public void testDuplicityInAugmentTarget2() throws Exception {
+        try {
+            try (InputStream stream1 = new FileInputStream(getClass().getResource(
+                    "/negative-scenario/duplicity/augment0.yang").getPath());
+                    InputStream stream2 = new FileInputStream(getClass().getResource(
+                            "/negative-scenario/duplicity/augment2.yang").getPath())) {
+                TestUtils.loadModules(Arrays.asList(stream1, stream2));
+                fail("YangParseException should by thrown");
+            }
+        } catch (YangParseException e) {
+            String expected = "Error in module 'augment2' at line 11: Can not add 'anyxml delta' to node 'choice-ext' in module 'augment0': case with same name already declared at line 18";
+            assertEquals(expected, e.getMessage());
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserTest.java
new file mode 100644 (file)
index 0000000..bc0ccbd
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.AugmentationSchema;
+import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.Deviation;
+import org.opendaylight.controller.yang.model.api.Deviation.Deviate;
+import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
+import org.opendaylight.controller.yang.model.api.FeatureDefinition;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.model.api.NotificationDefinition;
+import org.opendaylight.controller.yang.model.api.RpcDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.Status;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
+import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.Decimal64;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+import org.opendaylight.controller.yang.model.util.Int16;
+import org.opendaylight.controller.yang.model.util.Int32;
+import org.opendaylight.controller.yang.model.util.StringType;
+import org.opendaylight.controller.yang.model.util.Uint32;
+import org.opendaylight.controller.yang.model.util.UnionType;
+
+public class YangParserTest {
+
+    private final URI nodesNS = URI.create("urn:simple.nodes.test");
+    private final URI typesNS = URI.create("urn:simple.types.test");
+    private final URI customNS = URI.create("urn:custom.nodes.test");
+    private Date nodesRev;
+    private Date typesRev;
+    private Date customRev;
+
+    private final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+    private Set<Module> modules;
+
+    @Before
+    public void init() throws FileNotFoundException, ParseException {
+        nodesRev = simpleDateFormat.parse("2013-02-27");
+        typesRev = simpleDateFormat.parse("2013-07-03");
+        customRev = simpleDateFormat.parse("2013-02-27");
+
+        modules = TestUtils.loadModules(getClass().getResource("/model").getPath());
+        assertEquals(3, modules.size());
+    }
+
+    @Test
+    public void testHeaders() throws ParseException {
+        Module test = TestUtils.findModule(modules, "nodes");
+
+        assertEquals("nodes", test.getName());
+        assertEquals("1", test.getYangVersion());
+        assertEquals(nodesNS, test.getNamespace());
+        assertEquals("n", test.getPrefix());
+
+        Set<ModuleImport> imports = test.getImports();
+        assertEquals(2, imports.size());
+
+        ModuleImport import2 = TestUtils.findImport(imports, "t");
+        assertEquals("types", import2.getModuleName());
+        assertEquals(typesRev, import2.getRevision());
+
+        ModuleImport import3 = TestUtils.findImport(imports, "c");
+        assertEquals("custom", import3.getModuleName());
+        assertEquals(customRev, import3.getRevision());
+
+        assertEquals("opendaylight", test.getOrganization());
+        assertEquals("http://www.opendaylight.org/", test.getContact());
+        Date expectedRevision = TestUtils.createDate("2013-02-27");
+        assertEquals(expectedRevision, test.getRevision());
+        assertEquals(" WILL BE DEFINED LATER", test.getReference());
+    }
+
+    @Test
+    public void testOrderingTypedef() {
+        Module test = TestUtils.findModule(modules, "types");
+        Set<TypeDefinition<?>> typedefs = test.getTypeDefinitions();
+        String[] expectedOrder = new String[] { "int32-ext1", "int32-ext2", "my-decimal-type", "my-union",
+                "my-union-ext", "nested-union2", "string-ext1", "string-ext2", "string-ext3", "string-ext4" };
+        String[] actualOrder = new String[typedefs.size()];
+
+        int i = 0;
+        for (TypeDefinition<?> type : typedefs) {
+            actualOrder[i] = type.getQName().getLocalName();
+            i++;
+        }
+        assertArrayEquals(expectedOrder, actualOrder);
+    }
+
+    @Test
+    public void testOrderingChildNodes() {
+        Module test = TestUtils.findModule(modules, "nodes");
+        AugmentationSchema augment1 = null;
+        for (AugmentationSchema as : test.getAugmentations()) {
+            if ("if:ifType='ds0'".equals(as.getWhenCondition().toString())) {
+                augment1 = as;
+                break;
+            }
+        }
+        assertNotNull(augment1);
+
+        String[] expectedOrder = new String[] { "ds0ChannelNumber", "interface-id", "my-type", "odl", "schemas" };
+        String[] actualOrder = new String[expectedOrder.length];
+
+        int i = 0;
+        for (DataSchemaNode augmentChild : augment1.getChildNodes()) {
+            actualOrder[i] = augmentChild.getQName().getLocalName();
+            i++;
+        }
+
+        assertArrayEquals(expectedOrder, actualOrder);
+    }
+
+    @Test
+    public void testOrderingNestedChildNodes1() {
+        Module test = TestUtils.findModule(modules, "nodes");
+
+        Set<DataSchemaNode> childNodes = test.getChildNodes();
+        String[] expectedOrder = new String[] { "address", "addresses", "custom-union-leaf", "data", "datas",
+                "decimal-leaf", "decimal-leaf2", "ext", "how", "int32-leaf", "length-leaf", "mycont", "peer", "port",
+                "string-leaf", "transfer", "union-leaf" };
+        String[] actualOrder = new String[childNodes.size()];
+
+        int i = 0;
+        for (DataSchemaNode child : childNodes) {
+            actualOrder[i] = child.getQName().getLocalName();
+            i++;
+        }
+        assertArrayEquals(expectedOrder, actualOrder);
+    }
+
+    @Test
+    public void testOrderingNestedChildNodes2() {
+        Module test = TestUtils.findModule(modules, "custom");
+        Set<GroupingDefinition> groupings = test.getGroupings();
+        assertEquals(1, groupings.size());
+        GroupingDefinition target = groupings.iterator().next();
+
+        Set<DataSchemaNode> childNodes = target.getChildNodes();
+        String[] expectedOrder = new String[] { "address", "addresses", "data", "how", "port" };
+        String[] actualOrder = new String[childNodes.size()];
+
+        int i = 0;
+        for (DataSchemaNode child : childNodes) {
+            actualOrder[i] = child.getQName().getLocalName();
+            i++;
+        }
+        assertArrayEquals(expectedOrder, actualOrder);
+    }
+
+    @Test
+    public void testParseContainer() {
+        Module test = TestUtils.findModule(modules, "types");
+        URI expectedNamespace = URI.create("urn:simple.types.test");
+        String expectedPrefix = "t";
+
+        ContainerSchemaNode interfaces = (ContainerSchemaNode) test.getDataChildByName("interfaces");
+        // test SchemaNode args
+        QName expectedQName = new QName(expectedNamespace, typesRev, expectedPrefix, "interfaces");
+        assertEquals(expectedQName, interfaces.getQName());
+        SchemaPath expectedPath = TestUtils.createPath(true, expectedNamespace, typesRev, expectedPrefix, "interfaces");
+        assertEquals(expectedPath, interfaces.getPath());
+        assertNull(interfaces.getDescription());
+        assertNull(interfaces.getReference());
+        assertEquals(Status.CURRENT, interfaces.getStatus());
+        assertEquals(0, interfaces.getUnknownSchemaNodes().size());
+        // test DataSchemaNode args
+        assertFalse(interfaces.isAugmenting());
+        assertTrue(interfaces.isConfiguration());
+        ConstraintDefinition constraints = interfaces.getConstraints();
+        assertNull(constraints.getWhenCondition());
+        assertEquals(0, constraints.getMustConstraints().size());
+        assertFalse(constraints.isMandatory());
+        assertNull(constraints.getMinElements());
+        assertNull(constraints.getMaxElements());
+        // test AugmentationTarget args
+        assertEquals(0, interfaces.getAvailableAugmentations().size());
+        // test ContainerSchemaNode args
+        assertFalse(interfaces.isPresenceContainer());
+        // test DataNodeContainer args
+        assertEquals(0, interfaces.getTypeDefinitions().size());
+        assertEquals(1, interfaces.getChildNodes().size());
+        assertEquals(1, interfaces.getGroupings().size());
+        assertEquals(0, interfaces.getUses().size());
+
+        ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+        assertNotNull(ifEntry);
+    }
+
+    @Test
+    public void testParseList() {
+        Module test = TestUtils.findModule(modules, "types");
+        URI expectedNamespace = URI.create("urn:simple.types.test");
+        String expectedPrefix = "t";
+
+        ContainerSchemaNode interfaces = (ContainerSchemaNode) test.getDataChildByName("interfaces");
+
+        ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+        // test SchemaNode args
+        QName expectedQName = new QName(expectedNamespace, typesRev, expectedPrefix, "ifEntry");
+        assertEquals(expectedQName, ifEntry.getQName());
+        SchemaPath expectedPath = TestUtils.createPath(true, expectedNamespace, typesRev, expectedPrefix, "interfaces",
+                "ifEntry");
+        assertEquals(expectedPath, ifEntry.getPath());
+        assertNull(ifEntry.getDescription());
+        assertNull(ifEntry.getReference());
+        assertEquals(Status.CURRENT, ifEntry.getStatus());
+        assertEquals(0, ifEntry.getUnknownSchemaNodes().size());
+        // test DataSchemaNode args
+        assertFalse(ifEntry.isAugmenting());
+        assertTrue(ifEntry.isConfiguration());
+        ConstraintDefinition constraints = ifEntry.getConstraints();
+        assertNull(constraints.getWhenCondition());
+        assertEquals(0, constraints.getMustConstraints().size());
+        assertFalse(constraints.isMandatory());
+        assertEquals(1, (int) constraints.getMinElements());
+        assertEquals(11, (int) constraints.getMaxElements());
+        // test AugmentationTarget args
+        Set<AugmentationSchema> availableAugmentations = ifEntry.getAvailableAugmentations();
+        assertEquals(2, availableAugmentations.size());
+        // test ListSchemaNode args
+        List<QName> expectedKey = new ArrayList<QName>();
+        expectedKey.add(new QName(expectedNamespace, typesRev, expectedPrefix, "ifIndex"));
+        assertEquals(expectedKey, ifEntry.getKeyDefinition());
+        assertFalse(ifEntry.isUserOrdered());
+        // test DataNodeContainer args
+        assertEquals(0, ifEntry.getTypeDefinitions().size());
+        assertEquals(4, ifEntry.getChildNodes().size());
+        assertEquals(0, ifEntry.getGroupings().size());
+        assertEquals(0, ifEntry.getUses().size());
+
+        LeafSchemaNode ifIndex = (LeafSchemaNode) ifEntry.getDataChildByName("ifIndex");
+        assertTrue(ifIndex.getType() instanceof Uint32);
+        LeafSchemaNode ifMtu = (LeafSchemaNode) ifEntry.getDataChildByName("ifMtu");
+        assertTrue(ifMtu.getType() instanceof Int32);
+    }
+
+    @Test
+    public void testTypedefRangesResolving() throws ParseException {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode int32Leaf = (LeafSchemaNode) testModule.getDataChildByName("int32-leaf");
+
+        ExtendedType leafType = (ExtendedType) int32Leaf.getType();
+        QName leafTypeQName = leafType.getQName();
+        assertEquals("int32-ext2", leafTypeQName.getLocalName());
+        assertEquals("n", leafTypeQName.getPrefix());
+        assertEquals(nodesNS, leafTypeQName.getNamespace());
+        assertEquals(nodesRev, leafTypeQName.getRevision());
+        assertNull(leafType.getUnits());
+        assertNull(leafType.getDefaultValue());
+        assertTrue(leafType.getLengths().isEmpty());
+        assertTrue(leafType.getPatterns().isEmpty());
+        List<RangeConstraint> ranges = leafType.getRanges();
+        assertEquals(1, ranges.size());
+        RangeConstraint range = ranges.get(0);
+        assertEquals(12L, range.getMin());
+        assertEquals(20L, range.getMax());
+
+        ExtendedType baseType = (ExtendedType) leafType.getBaseType();
+        QName baseTypeQName = baseType.getQName();
+        assertEquals("int32-ext2", baseTypeQName.getLocalName());
+        assertEquals("t", baseTypeQName.getPrefix());
+        assertEquals(typesNS, baseTypeQName.getNamespace());
+        assertEquals(typesRev, baseTypeQName.getRevision());
+        assertEquals("mile", baseType.getUnits());
+        assertEquals("11", baseType.getDefaultValue());
+        assertTrue(leafType.getLengths().isEmpty());
+        assertTrue(leafType.getPatterns().isEmpty());
+        List<RangeConstraint> baseTypeRanges = baseType.getRanges();
+        assertEquals(2, baseTypeRanges.size());
+        RangeConstraint baseTypeRange1 = baseTypeRanges.get(0);
+        assertEquals(3L, baseTypeRange1.getMin());
+        assertEquals(9L, baseTypeRange1.getMax());
+        RangeConstraint baseTypeRange2 = baseTypeRanges.get(1);
+        assertEquals(11L, baseTypeRange2.getMin());
+        assertEquals(20L, baseTypeRange2.getMax());
+
+        ExtendedType base = (ExtendedType) baseType.getBaseType();
+        QName baseQName = base.getQName();
+        assertEquals("int32-ext1", baseQName.getLocalName());
+        assertEquals("t", baseQName.getPrefix());
+        assertEquals(typesNS, baseQName.getNamespace());
+        assertEquals(typesRev, baseQName.getRevision());
+        assertNull(base.getUnits());
+        assertNull(base.getDefaultValue());
+        assertTrue(leafType.getLengths().isEmpty());
+        assertTrue(leafType.getPatterns().isEmpty());
+        List<RangeConstraint> baseRanges = base.getRanges();
+        assertEquals(1, baseRanges.size());
+        RangeConstraint baseRange = baseRanges.get(0);
+        assertEquals(2L, baseRange.getMin());
+        assertEquals(20L, baseRange.getMax());
+
+        assertTrue(base.getBaseType() instanceof Int32);
+    }
+
+    @Test
+    public void testTypedefPatternsResolving() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode stringleaf = (LeafSchemaNode) testModule.getDataChildByName("string-leaf");
+
+        ExtendedType type = (ExtendedType) stringleaf.getType();
+        QName typeQName = type.getQName();
+        assertEquals("string-ext4", typeQName.getLocalName());
+        assertEquals("t", typeQName.getPrefix());
+        assertEquals(typesNS, typeQName.getNamespace());
+        assertEquals(typesRev, typeQName.getRevision());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        List<PatternConstraint> patterns = type.getPatterns();
+        assertEquals(1, patterns.size());
+        PatternConstraint pattern = patterns.iterator().next();
+        assertEquals("[e-z]*", pattern.getRegularExpression());
+        assertTrue(type.getLengths().isEmpty());
+        assertTrue(type.getRanges().isEmpty());
+
+        ExtendedType baseType1 = (ExtendedType) type.getBaseType();
+        QName baseType1QName = baseType1.getQName();
+        assertEquals("string-ext3", baseType1QName.getLocalName());
+        assertEquals("t", baseType1QName.getPrefix());
+        assertEquals(typesNS, baseType1QName.getNamespace());
+        assertEquals(typesRev, baseType1QName.getRevision());
+        assertNull(baseType1.getUnits());
+        assertNull(baseType1.getDefaultValue());
+        patterns = baseType1.getPatterns();
+        assertEquals(1, patterns.size());
+        pattern = patterns.iterator().next();
+        assertEquals("[b-u]*", pattern.getRegularExpression());
+        assertTrue(baseType1.getLengths().isEmpty());
+        assertTrue(baseType1.getRanges().isEmpty());
+
+        ExtendedType baseType2 = (ExtendedType) baseType1.getBaseType();
+        QName baseType2QName = baseType2.getQName();
+        assertEquals("string-ext2", baseType2QName.getLocalName());
+        assertEquals("t", baseType2QName.getPrefix());
+        assertEquals(typesNS, baseType2QName.getNamespace());
+        assertEquals(typesRev, baseType2QName.getRevision());
+        assertNull(baseType2.getUnits());
+        assertNull(baseType2.getDefaultValue());
+        assertTrue(baseType2.getPatterns().isEmpty());
+        List<LengthConstraint> baseType2Lengths = baseType2.getLengths();
+        assertEquals(1, baseType2Lengths.size());
+        LengthConstraint length = baseType2Lengths.get(0);
+        assertEquals(6L, length.getMin());
+        assertEquals(10L, length.getMax());
+        assertTrue(baseType2.getRanges().isEmpty());
+
+        ExtendedType baseType3 = (ExtendedType) baseType2.getBaseType();
+        QName baseType3QName = baseType3.getQName();
+        assertEquals("string-ext1", baseType3QName.getLocalName());
+        assertEquals("t", baseType3QName.getPrefix());
+        assertEquals(typesNS, baseType3QName.getNamespace());
+        assertEquals(typesRev, baseType3QName.getRevision());
+        assertNull(baseType3.getUnits());
+        assertNull(baseType3.getDefaultValue());
+        patterns = baseType3.getPatterns();
+        assertEquals(1, patterns.size());
+        pattern = patterns.iterator().next();
+        assertEquals("[a-k]*", pattern.getRegularExpression());
+        List<LengthConstraint> baseType3Lengths = baseType3.getLengths();
+        assertEquals(1, baseType3Lengths.size());
+        length = baseType3Lengths.get(0);
+        assertEquals(5L, length.getMin());
+        assertEquals(11L, length.getMax());
+        assertTrue(baseType3.getRanges().isEmpty());
+
+        assertTrue(baseType3.getBaseType() instanceof StringType);
+    }
+
+    @Test
+    public void testTypedefLengthsResolving() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+
+        LeafSchemaNode lengthLeaf = (LeafSchemaNode) testModule.getDataChildByName("length-leaf");
+        ExtendedType type = (ExtendedType) lengthLeaf.getType();
+
+        QName typeQName = type.getQName();
+        assertEquals("string-ext2", typeQName.getLocalName());
+        assertEquals("n", typeQName.getPrefix());
+        assertEquals(nodesNS, typeQName.getNamespace());
+        assertEquals(nodesRev, typeQName.getRevision());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        assertTrue(type.getPatterns().isEmpty());
+        List<LengthConstraint> typeLengths = type.getLengths();
+        assertEquals(1, typeLengths.size());
+        LengthConstraint length = typeLengths.get(0);
+        assertEquals(7L, length.getMin());
+        assertEquals(10L, length.getMax());
+        assertTrue(type.getRanges().isEmpty());
+
+        ExtendedType baseType1 = (ExtendedType) type.getBaseType();
+        QName baseType1QName = baseType1.getQName();
+        assertEquals("string-ext2", baseType1QName.getLocalName());
+        assertEquals("t", baseType1QName.getPrefix());
+        assertEquals(typesNS, baseType1QName.getNamespace());
+        assertEquals(typesRev, baseType1QName.getRevision());
+        assertNull(baseType1.getUnits());
+        assertNull(baseType1.getDefaultValue());
+        assertTrue(baseType1.getPatterns().isEmpty());
+        List<LengthConstraint> baseType2Lengths = baseType1.getLengths();
+        assertEquals(1, baseType2Lengths.size());
+        length = baseType2Lengths.get(0);
+        assertEquals(6L, length.getMin());
+        assertEquals(10L, length.getMax());
+        assertTrue(baseType1.getRanges().isEmpty());
+
+        ExtendedType baseType2 = (ExtendedType) baseType1.getBaseType();
+        QName baseType2QName = baseType2.getQName();
+        assertEquals("string-ext1", baseType2QName.getLocalName());
+        assertEquals("t", baseType2QName.getPrefix());
+        assertEquals(typesNS, baseType2QName.getNamespace());
+        assertEquals(typesRev, baseType2QName.getRevision());
+        assertNull(baseType2.getUnits());
+        assertNull(baseType2.getDefaultValue());
+        List<PatternConstraint> patterns = baseType2.getPatterns();
+        assertEquals(1, patterns.size());
+        PatternConstraint pattern = patterns.iterator().next();
+        assertEquals("[a-k]*", pattern.getRegularExpression());
+        List<LengthConstraint> baseType3Lengths = baseType2.getLengths();
+        assertEquals(1, baseType3Lengths.size());
+        length = baseType3Lengths.get(0);
+        assertEquals(5L, length.getMin());
+        assertEquals(11L, length.getMax());
+        assertTrue(baseType2.getRanges().isEmpty());
+
+        assertTrue(baseType2.getBaseType() instanceof StringType);
+    }
+
+    @Test
+    public void testTypedefDecimal1() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode testleaf = (LeafSchemaNode) testModule.getDataChildByName("decimal-leaf");
+
+        ExtendedType type = (ExtendedType) testleaf.getType();
+        QName typeQName = type.getQName();
+        assertEquals("my-decimal-type", typeQName.getLocalName());
+        assertEquals("n", typeQName.getPrefix());
+        assertEquals(nodesNS, typeQName.getNamespace());
+        assertEquals(nodesRev, typeQName.getRevision());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        assertEquals(4, (int) type.getFractionDigits());
+        assertTrue(type.getLengths().isEmpty());
+        assertTrue(type.getPatterns().isEmpty());
+        assertTrue(type.getRanges().isEmpty());
+
+        ExtendedType typeBase = (ExtendedType) type.getBaseType();
+        QName typeBaseQName = typeBase.getQName();
+        assertEquals("my-decimal-type", typeBaseQName.getLocalName());
+        assertEquals("t", typeBaseQName.getPrefix());
+        assertEquals(typesNS, typeBaseQName.getNamespace());
+        assertEquals(typesRev, typeBaseQName.getRevision());
+        assertNull(typeBase.getUnits());
+        assertNull(typeBase.getDefaultValue());
+        assertNull(typeBase.getFractionDigits());
+        assertTrue(typeBase.getLengths().isEmpty());
+        assertTrue(typeBase.getPatterns().isEmpty());
+        assertTrue(typeBase.getRanges().isEmpty());
+
+        Decimal64 decimal = (Decimal64) typeBase.getBaseType();
+        assertEquals(6, (int) decimal.getFractionDigits());
+    }
+
+    @Test
+    public void testTypedefDecimal2() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode testleaf = (LeafSchemaNode) testModule.getDataChildByName("decimal-leaf2");
+
+        ExtendedType type = (ExtendedType) testleaf.getType();
+        QName typeQName = type.getQName();
+        assertEquals("my-decimal-type", typeQName.getLocalName());
+        assertEquals("t", typeQName.getPrefix());
+        assertEquals(typesNS, typeQName.getNamespace());
+        assertEquals(typesRev, typeQName.getRevision());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        assertNull(type.getFractionDigits());
+        assertTrue(type.getLengths().isEmpty());
+        assertTrue(type.getPatterns().isEmpty());
+        assertTrue(type.getRanges().isEmpty());
+
+        Decimal64 baseTypeDecimal = (Decimal64) type.getBaseType();
+        assertEquals(6, (int) baseTypeDecimal.getFractionDigits());
+    }
+
+    @Test
+    public void testTypedefUnion() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode unionleaf = (LeafSchemaNode) testModule.getDataChildByName("union-leaf");
+
+        ExtendedType type = (ExtendedType) unionleaf.getType();
+        QName typeQName = type.getQName();
+        assertEquals("my-union-ext", typeQName.getLocalName());
+        assertEquals("t", typeQName.getPrefix());
+        assertEquals(typesNS, typeQName.getNamespace());
+        assertEquals(typesRev, typeQName.getRevision());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        assertNull(type.getFractionDigits());
+        assertTrue(type.getLengths().isEmpty());
+        assertTrue(type.getPatterns().isEmpty());
+        assertTrue(type.getRanges().isEmpty());
+
+        ExtendedType baseType = (ExtendedType) type.getBaseType();
+        QName baseTypeQName = baseType.getQName();
+        assertEquals("my-union", baseTypeQName.getLocalName());
+        assertEquals("t", baseTypeQName.getPrefix());
+        assertEquals(typesNS, baseTypeQName.getNamespace());
+        assertEquals(typesRev, baseTypeQName.getRevision());
+        assertNull(baseType.getUnits());
+        assertNull(baseType.getDefaultValue());
+        assertNull(baseType.getFractionDigits());
+        assertTrue(baseType.getLengths().isEmpty());
+        assertTrue(baseType.getPatterns().isEmpty());
+        assertTrue(baseType.getRanges().isEmpty());
+
+        UnionType unionType = (UnionType) baseType.getBaseType();
+        List<TypeDefinition<?>> unionTypes = unionType.getTypes();
+        assertEquals(2, unionTypes.size());
+
+        ExtendedType unionType1 = (ExtendedType) unionTypes.get(0);
+        QName unionType1QName = baseType.getQName();
+        assertEquals("my-union", unionType1QName.getLocalName());
+        assertEquals("t", unionType1QName.getPrefix());
+        assertEquals(typesNS, unionType1QName.getNamespace());
+        assertEquals(typesRev, unionType1QName.getRevision());
+        assertNull(unionType1.getUnits());
+        assertNull(unionType1.getDefaultValue());
+        assertNull(unionType1.getFractionDigits());
+        assertTrue(unionType1.getLengths().isEmpty());
+        assertTrue(unionType1.getPatterns().isEmpty());
+        List<RangeConstraint> ranges = unionType1.getRanges();
+        assertEquals(1, ranges.size());
+        RangeConstraint range = ranges.get(0);
+        assertEquals(1L, range.getMin());
+        assertEquals(100L, range.getMax());
+        assertTrue(unionType1.getBaseType() instanceof Int16);
+
+        assertTrue(unionTypes.get(1) instanceof Int32);
+    }
+
+    @Test
+    public void testNestedUnionResolving() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        LeafSchemaNode testleaf = (LeafSchemaNode) testModule.getDataChildByName("custom-union-leaf");
+
+        ExtendedType type = (ExtendedType) testleaf.getType();
+        QName testleafTypeQName = type.getQName();
+        assertEquals(customNS, testleafTypeQName.getNamespace());
+        assertEquals(customRev, testleafTypeQName.getRevision());
+        assertEquals("c", testleafTypeQName.getPrefix());
+        assertEquals("union1", testleafTypeQName.getLocalName());
+        assertNull(type.getUnits());
+        assertNull(type.getDefaultValue());
+        assertNull(type.getFractionDigits());
+        assertTrue(type.getLengths().isEmpty());
+        assertTrue(type.getPatterns().isEmpty());
+        assertTrue(type.getRanges().isEmpty());
+
+        ExtendedType typeBase = (ExtendedType) type.getBaseType();
+        QName typeBaseQName = typeBase.getQName();
+        assertEquals(customNS, typeBaseQName.getNamespace());
+        assertEquals(customRev, typeBaseQName.getRevision());
+        assertEquals("c", typeBaseQName.getPrefix());
+        assertEquals("union2", typeBaseQName.getLocalName());
+        assertNull(typeBase.getUnits());
+        assertNull(typeBase.getDefaultValue());
+        assertNull(typeBase.getFractionDigits());
+        assertTrue(typeBase.getLengths().isEmpty());
+        assertTrue(typeBase.getPatterns().isEmpty());
+        assertTrue(typeBase.getRanges().isEmpty());
+
+        UnionType union = (UnionType) typeBase.getBaseType();
+        List<TypeDefinition<?>> unionTypes = union.getTypes();
+        assertEquals(2, unionTypes.size());
+        assertTrue(unionTypes.get(0) instanceof Int32);
+        assertTrue(unionTypes.get(1) instanceof ExtendedType);
+
+        ExtendedType unionType1 = (ExtendedType) unionTypes.get(1);
+        QName uniontType1QName = unionType1.getQName();
+        assertEquals(typesNS, uniontType1QName.getNamespace());
+        assertEquals(typesRev, uniontType1QName.getRevision());
+        assertEquals("t", uniontType1QName.getPrefix());
+        assertEquals("nested-union2", uniontType1QName.getLocalName());
+        assertNull(unionType1.getUnits());
+        assertNull(unionType1.getDefaultValue());
+        assertNull(unionType1.getFractionDigits());
+        assertTrue(unionType1.getLengths().isEmpty());
+        assertTrue(unionType1.getPatterns().isEmpty());
+        assertTrue(unionType1.getRanges().isEmpty());
+
+        UnionType nestedUnion = (UnionType) unionType1.getBaseType();
+        List<TypeDefinition<?>> nestedUnion2Types = nestedUnion.getTypes();
+        assertEquals(2, nestedUnion2Types.size());
+        assertTrue(nestedUnion2Types.get(0) instanceof StringType);
+        assertTrue(nestedUnion2Types.get(1) instanceof ExtendedType);
+
+        ExtendedType myUnionExt = (ExtendedType) nestedUnion2Types.get(1);
+        QName myUnionExtQName = myUnionExt.getQName();
+        assertEquals(typesNS, myUnionExtQName.getNamespace());
+        assertEquals(typesRev, myUnionExtQName.getRevision());
+        assertEquals("t", myUnionExtQName.getPrefix());
+        assertEquals("my-union-ext", myUnionExtQName.getLocalName());
+        assertNull(myUnionExt.getUnits());
+        assertNull(myUnionExt.getDefaultValue());
+        assertNull(myUnionExt.getFractionDigits());
+        assertTrue(myUnionExt.getLengths().isEmpty());
+        assertTrue(myUnionExt.getPatterns().isEmpty());
+        assertTrue(myUnionExt.getRanges().isEmpty());
+
+        ExtendedType myUnion = (ExtendedType) myUnionExt.getBaseType();
+        QName myUnionQName = myUnion.getQName();
+        assertEquals(typesNS, myUnionQName.getNamespace());
+        assertEquals(typesRev, myUnionQName.getRevision());
+        assertEquals("t", myUnionQName.getPrefix());
+        assertEquals("my-union", myUnionQName.getLocalName());
+        assertNull(myUnion.getUnits());
+        assertNull(myUnion.getDefaultValue());
+        assertNull(myUnion.getFractionDigits());
+        assertTrue(myUnion.getLengths().isEmpty());
+        assertTrue(myUnion.getPatterns().isEmpty());
+        assertTrue(myUnion.getRanges().isEmpty());
+
+        UnionType myUnionBase = (UnionType) myUnion.getBaseType();
+        List<TypeDefinition<?>> myUnionBaseTypes = myUnionBase.getTypes();
+        assertEquals(2, myUnionBaseTypes.size());
+        assertTrue(myUnionBaseTypes.get(0) instanceof ExtendedType);
+        assertTrue(myUnionBaseTypes.get(1) instanceof Int32);
+
+        ExtendedType int16Ext = (ExtendedType) myUnionBaseTypes.get(0);
+        QName int16ExtQName = int16Ext.getQName();
+        assertEquals(typesNS, int16ExtQName.getNamespace());
+        assertEquals(typesRev, int16ExtQName.getRevision());
+        assertEquals("t", int16ExtQName.getPrefix());
+        assertEquals("int16", int16ExtQName.getLocalName());
+        assertNull(int16Ext.getUnits());
+        assertNull(int16Ext.getDefaultValue());
+        assertNull(int16Ext.getFractionDigits());
+        assertTrue(int16Ext.getLengths().isEmpty());
+        assertTrue(int16Ext.getPatterns().isEmpty());
+        List<RangeConstraint> ranges = int16Ext.getRanges();
+        assertEquals(1, ranges.size());
+        RangeConstraint range = ranges.get(0);
+        assertEquals(1L, range.getMin());
+        assertEquals(100L, range.getMax());
+
+        assertTrue(int16Ext.getBaseType() instanceof Int16);
+    }
+
+    @Test
+    public void testChoice() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        ContainerSchemaNode transfer = (ContainerSchemaNode) testModule.getDataChildByName("transfer");
+        ChoiceNode how = (ChoiceNode) transfer.getDataChildByName("how");
+        Set<ChoiceCaseNode> cases = how.getCases();
+        assertEquals(5, cases.size());
+        ChoiceCaseNode input = null;
+        ChoiceCaseNode output = null;
+        for (ChoiceCaseNode caseNode : cases) {
+            if ("input".equals(caseNode.getQName().getLocalName())) {
+                input = caseNode;
+            } else if ("output".equals(caseNode.getQName().getLocalName())) {
+                output = caseNode;
+            }
+        }
+        assertNotNull(input);
+        assertNotNull(input.getPath());
+        assertNotNull(output);
+        assertNotNull(output.getPath());
+    }
+
+    @Test
+    public void testAnyXml() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        AnyXmlSchemaNode data = (AnyXmlSchemaNode) testModule.getDataChildByName("datas");
+        assertNotNull("anyxml data not found", data);
+
+        // test SchemaNode args
+        QName qname = data.getQName();
+        assertEquals("datas", qname.getLocalName());
+        assertEquals("n", qname.getPrefix());
+        assertEquals(nodesNS, qname.getNamespace());
+        assertEquals(nodesRev, qname.getRevision());
+        assertTrue(data.getDescription().contains("Copy of the source typesstore subset that matched"));
+        assertNull(data.getReference());
+        assertEquals(Status.OBSOLETE, data.getStatus());
+        assertEquals(0, data.getUnknownSchemaNodes().size());
+        // test DataSchemaNode args
+        assertFalse(data.isAugmenting());
+        assertTrue(data.isConfiguration());
+        ConstraintDefinition constraints = data.getConstraints();
+        assertNull(constraints.getWhenCondition());
+        assertEquals(0, constraints.getMustConstraints().size());
+        assertFalse(constraints.isMandatory());
+        assertNull(constraints.getMinElements());
+        assertNull(constraints.getMaxElements());
+    }
+
+    @Test
+    public void testDeviation() {
+        Module testModule = TestUtils.findModule(modules, "nodes");
+        Set<Deviation> deviations = testModule.getDeviations();
+        assertEquals(1, deviations.size());
+        Deviation dev = deviations.iterator().next();
+
+        assertEquals("system/user ref", dev.getReference());
+
+        List<QName> path = new ArrayList<QName>();
+        path.add(new QName(typesNS, typesRev, "t", "interfaces"));
+        path.add(new QName(typesNS, typesRev, "t", "ifEntry"));
+        SchemaPath expectedPath = new SchemaPath(path, true);
+
+        assertEquals(expectedPath, dev.getTargetPath());
+        assertEquals(Deviate.ADD, dev.getDeviate());
+    }
+
+    @Test
+    public void testUnknownNode() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+        ContainerSchemaNode network = (ContainerSchemaNode) testModule.getDataChildByName("network");
+        List<UnknownSchemaNode> unknownNodes = network.getUnknownSchemaNodes();
+        assertEquals(1, unknownNodes.size());
+        UnknownSchemaNode unknownNode = unknownNodes.get(0);
+        assertNotNull(unknownNode.getNodeType());
+        assertEquals("point", unknownNode.getNodeParameter());
+    }
+
+    @Test
+    public void testFeature() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+        Set<FeatureDefinition> features = testModule.getFeatures();
+        assertEquals(1, features.size());
+    }
+
+    @Test
+    public void testExtension() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+        List<ExtensionDefinition> extensions = testModule.getExtensionSchemaNodes();
+        assertEquals(1, extensions.size());
+        ExtensionDefinition extension = extensions.get(0);
+        assertEquals("name", extension.getArgument());
+        assertTrue(extension.isYinElement());
+    }
+
+    @Test
+    public void testNotification() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+        String expectedPrefix = "c";
+
+        Set<NotificationDefinition> notifications = testModule.getNotifications();
+        assertEquals(1, notifications.size());
+
+        NotificationDefinition notification = notifications.iterator().next();
+        // test SchemaNode args
+        QName expectedQName = new QName(customNS, customRev, expectedPrefix, "event");
+        assertEquals(expectedQName, notification.getQName());
+        SchemaPath expectedPath = TestUtils.createPath(true, customNS, customRev, expectedPrefix, "event");
+        assertEquals(expectedPath, notification.getPath());
+        assertNull(notification.getDescription());
+        assertNull(notification.getReference());
+        assertEquals(Status.CURRENT, notification.getStatus());
+        assertEquals(0, notification.getUnknownSchemaNodes().size());
+        // test DataNodeContainer args
+        assertEquals(0, notification.getTypeDefinitions().size());
+        assertEquals(3, notification.getChildNodes().size());
+        assertEquals(0, notification.getGroupings().size());
+        assertEquals(0, notification.getUses().size());
+
+        LeafSchemaNode eventClass = (LeafSchemaNode) notification.getDataChildByName("event-class");
+        assertTrue(eventClass.getType() instanceof StringType);
+        AnyXmlSchemaNode reportingEntity = (AnyXmlSchemaNode) notification.getDataChildByName("reporting-entity");
+        assertNotNull(reportingEntity);
+        LeafSchemaNode severity = (LeafSchemaNode) notification.getDataChildByName("severity");
+        assertTrue(severity.getType() instanceof StringType);
+    }
+
+    @Test
+    public void testRpc() {
+        Module testModule = TestUtils.findModule(modules, "custom");
+
+        Set<RpcDefinition> rpcs = testModule.getRpcs();
+        assertEquals(1, rpcs.size());
+
+        RpcDefinition rpc = rpcs.iterator().next();
+        assertEquals("Retrieve all or part of a specified configuration.", rpc.getDescription());
+        assertEquals("RFC 6241, Section 7.1", rpc.getReference());
+
+        ContainerSchemaNode input = rpc.getInput();
+        assertNotNull(input.getDataChildByName("source"));
+        assertNotNull(input.getDataChildByName("filter"));
+        ContainerSchemaNode output = rpc.getOutput();
+        assertNotNull(output.getDataChildByName("data"));
+    }
+
+    @Test
+    public void testTypePath() throws ParseException {
+        Module test = TestUtils.findModule(modules, "types");
+        Set<TypeDefinition<?>> types = test.getTypeDefinitions();
+
+        // my-base-int32-type
+        ExtendedType int32Typedef = (ExtendedType) TestUtils.findTypedef(types, "int32-ext1");
+        QName int32TypedefQName = int32Typedef.getQName();
+
+        assertEquals(typesNS, int32TypedefQName.getNamespace());
+        assertEquals(typesRev, int32TypedefQName.getRevision());
+        assertEquals("t", int32TypedefQName.getPrefix());
+        assertEquals("int32-ext1", int32TypedefQName.getLocalName());
+
+        SchemaPath typeSchemaPath = int32Typedef.getPath();
+        List<QName> typePath = typeSchemaPath.getPath();
+        assertEquals(1, typePath.size());
+        assertEquals(int32TypedefQName, typePath.get(0));
+
+        // my-base-int32-type/int32
+        Int32 int32 = (Int32) int32Typedef.getBaseType();
+        QName int32QName = int32.getQName();
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:1"), int32QName.getNamespace());
+        assertNull(int32QName.getRevision());
+        assertEquals("", int32QName.getPrefix());
+        assertEquals("int32", int32QName.getLocalName());
+
+        SchemaPath int32SchemaPath = int32.getPath();
+        List<QName> int32Path = int32SchemaPath.getPath();
+        assertEquals(3, int32Path.size());
+        assertEquals(int32TypedefQName, int32Path.get(0));
+        assertEquals(int32QName, int32Path.get(2));
+    }
+
+    @Test
+    public void testTypePath2() throws ParseException {
+        Module test = TestUtils.findModule(modules, "types");
+        Set<TypeDefinition<?>> types = test.getTypeDefinitions();
+
+        // my-base-int32-type
+        ExtendedType myDecType = (ExtendedType) TestUtils.findTypedef(types, "my-decimal-type");
+        QName myDecTypeQName = myDecType.getQName();
+
+        assertEquals(typesNS, myDecTypeQName.getNamespace());
+        assertEquals(typesRev, myDecTypeQName.getRevision());
+        assertEquals("t", myDecTypeQName.getPrefix());
+        assertEquals("my-decimal-type", myDecTypeQName.getLocalName());
+
+        SchemaPath typeSchemaPath = myDecType.getPath();
+        List<QName> typePath = typeSchemaPath.getPath();
+        assertEquals(1, typePath.size());
+        assertEquals(myDecTypeQName, typePath.get(0));
+
+        // my-base-int32-type/int32
+        Decimal64 dec64 = (Decimal64) myDecType.getBaseType();
+        QName dec64QName = dec64.getQName();
+
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:1"), dec64QName.getNamespace());
+        assertNull(dec64QName.getRevision());
+        assertEquals("", dec64QName.getPrefix());
+        assertEquals("decimal64", dec64QName.getLocalName());
+
+        SchemaPath dec64SchemaPath = dec64.getPath();
+        List<QName> dec64Path = dec64SchemaPath.getPath();
+        assertEquals(2, dec64Path.size());
+        assertEquals(myDecTypeQName, dec64Path.get(0));
+        assertEquals(dec64QName, dec64Path.get(1));
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserWithContextTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserWithContextTest.java
new file mode 100644 (file)
index 0000000..846b09c
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Test;
+import org.opendaylight.controller.yang.common.QName;
+import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.controller.yang.model.api.ChoiceNode;
+import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.controller.yang.model.api.DataSchemaNode;
+import org.opendaylight.controller.yang.model.api.Deviation;
+import org.opendaylight.controller.yang.model.api.Deviation.Deviate;
+import org.opendaylight.controller.yang.model.api.GroupingDefinition;
+import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
+import org.opendaylight.controller.yang.model.api.ListSchemaNode;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.MustDefinition;
+import org.opendaylight.controller.yang.model.api.SchemaContext;
+import org.opendaylight.controller.yang.model.api.SchemaNode;
+import org.opendaylight.controller.yang.model.api.SchemaPath;
+import org.opendaylight.controller.yang.model.api.TypeDefinition;
+import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.UsesNode;
+import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
+
+import com.google.common.collect.Lists;
+
+public class YangParserWithContextTest {
+    private final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+    private final YangParserImpl parser = new YangParserImpl();
+
+    @Test
+    public void testTypeFromContext() throws Exception {
+        SchemaContext context = null;
+        String resource = "/types/ietf-inet-types@2010-09-24.yang";
+        InputStream stream = new FileInputStream(getClass().getResource(resource).getPath());
+        context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream)));
+        stream.close();
+
+        Module module = null;
+        resource = "/context-test/test1.yang";
+        InputStream stream2 = new FileInputStream(getClass().getResource(resource).getPath());
+        module = TestUtils.loadModuleWithContext(stream2, context);
+        stream2.close();
+        assertNotNull(module);
+
+        LeafSchemaNode leaf = (LeafSchemaNode) module.getDataChildByName("id");
+
+        ExtendedType leafType = (ExtendedType) leaf.getType();
+        QName qname = leafType.getQName();
+        assertEquals(URI.create("urn:simple.demo.test1"), qname.getNamespace());
+        assertEquals(simpleDateFormat.parse("2013-06-18"), qname.getRevision());
+        assertEquals("t1", qname.getPrefix());
+        assertEquals("port-number", qname.getLocalName());
+
+        ExtendedType leafBaseType = (ExtendedType) leafType.getBaseType();
+        qname = leafBaseType.getQName();
+        assertEquals(URI.create("urn:ietf:params:xml:ns:yang:ietf-inet-types"), qname.getNamespace());
+        assertEquals(simpleDateFormat.parse("2010-09-24"), qname.getRevision());
+        assertEquals("inet", qname.getPrefix());
+        assertEquals("port-number", qname.getLocalName());
+
+        ExtendedType dscpExt = (ExtendedType) TestUtils.findTypedef(module.getTypeDefinitions(), "dscp-ext");
+        List<RangeConstraint> ranges = dscpExt.getRanges();
+        assertEquals(1, ranges.size());
+        RangeConstraint range = ranges.get(0);
+        assertEquals(0L, range.getMin());
+        assertEquals(63L, range.getMax());
+    }
+
+    @Test
+    public void testUsesFromContext() throws Exception {
+        SchemaContext context = null;
+        try (InputStream stream1 = new FileInputStream(getClass().getResource("/model/custom.yang").getPath());
+                InputStream stream2 = new FileInputStream(getClass().getResource("/model/types.yang").getPath());
+                InputStream stream3 = new FileInputStream(getClass().getResource("/model/nodes.yang").getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream1, stream2, stream3)));
+        }
+        Module testModule = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/test2.yang").getPath())) {
+            testModule = TestUtils.loadModuleWithContext(stream, context);
+        }
+        assertNotNull(testModule);
+
+        // suffix _u = added by uses
+        // suffix _g = defined in grouping from context
+
+        // get grouping
+        Module contextModule = context.findModuleByNamespace(URI.create("urn:custom.nodes.test"));
+        assertNotNull(contextModule);
+        Set<GroupingDefinition> groupings = contextModule.getGroupings();
+        assertEquals(1, groupings.size());
+        GroupingDefinition grouping = groupings.iterator().next();
+
+        // get node containing uses
+        ContainerSchemaNode peer = (ContainerSchemaNode) testModule.getDataChildByName("peer");
+        ContainerSchemaNode destination = (ContainerSchemaNode) peer.getDataChildByName("destination");
+
+        // check uses
+        Set<UsesNode> uses = destination.getUses();
+        assertEquals(1, uses.size());
+
+        // check uses process
+        AnyXmlSchemaNode data_u = (AnyXmlSchemaNode) destination.getDataChildByName("data");
+        assertNotNull(data_u);
+        assertTrue(data_u.isAddedByUses());
+
+        AnyXmlSchemaNode data_g = (AnyXmlSchemaNode) grouping.getDataChildByName("data");
+        assertNotNull(data_g);
+        assertFalse(data_g.isAddedByUses());
+        assertFalse(data_u.equals(data_g));
+
+        ChoiceNode how_u = (ChoiceNode) destination.getDataChildByName("how");
+        assertNotNull(how_u);
+        assertTrue(how_u.isAddedByUses());
+
+        ChoiceNode how_g = (ChoiceNode) grouping.getDataChildByName("how");
+        assertNotNull(how_g);
+        assertFalse(how_g.isAddedByUses());
+        assertFalse(how_u.equals(how_g));
+
+        LeafSchemaNode address_u = (LeafSchemaNode) destination.getDataChildByName("address");
+        assertNotNull(address_u);
+        assertTrue(address_u.isAddedByUses());
+
+        LeafSchemaNode address_g = (LeafSchemaNode) grouping.getDataChildByName("address");
+        assertNotNull(address_g);
+        assertFalse(address_g.isAddedByUses());
+        assertFalse(address_u.equals(address_g));
+
+        ContainerSchemaNode port_u = (ContainerSchemaNode) destination.getDataChildByName("port");
+        assertNotNull(port_u);
+        assertTrue(port_u.isAddedByUses());
+
+        ContainerSchemaNode port_g = (ContainerSchemaNode) grouping.getDataChildByName("port");
+        assertNotNull(port_g);
+        assertFalse(port_g.isAddedByUses());
+        assertFalse(port_u.equals(port_g));
+
+        ListSchemaNode addresses_u = (ListSchemaNode) destination.getDataChildByName("addresses");
+        assertNotNull(addresses_u);
+        assertTrue(addresses_u.isAddedByUses());
+
+        ListSchemaNode addresses_g = (ListSchemaNode) grouping.getDataChildByName("addresses");
+        assertNotNull(addresses_g);
+        assertFalse(addresses_g.isAddedByUses());
+        assertFalse(addresses_u.equals(addresses_g));
+
+        // grouping defined by 'uses'
+        Set<GroupingDefinition> groupings_u = destination.getGroupings();
+        assertEquals(1, groupings_u.size());
+        GroupingDefinition grouping_u = groupings_u.iterator().next();
+        assertTrue(grouping_u.isAddedByUses());
+
+        // grouping defined in 'grouping' node
+        Set<GroupingDefinition> groupings_g = grouping.getGroupings();
+        assertEquals(1, groupings_g.size());
+        GroupingDefinition grouping_g = groupings_g.iterator().next();
+        assertFalse(grouping_g.isAddedByUses());
+        assertFalse(grouping_u.equals(grouping_g));
+
+        List<UnknownSchemaNode> nodes_u = destination.getUnknownSchemaNodes();
+        assertEquals(1, nodes_u.size());
+        UnknownSchemaNode node_u = nodes_u.get(0);
+        assertTrue(node_u.isAddedByUses());
+
+        List<UnknownSchemaNode> nodes_g = grouping.getUnknownSchemaNodes();
+        assertEquals(1, nodes_g.size());
+        UnknownSchemaNode node_g = nodes_g.get(0);
+        assertFalse(node_g.isAddedByUses());
+        assertFalse(node_u.equals(node_g));
+    }
+
+    @Test
+    public void testUsesRefineFromContext() throws Exception {
+        SchemaContext context = null;
+        try (InputStream stream1 = new FileInputStream(getClass().getResource("/model/custom.yang").getPath());
+                InputStream stream2 = new FileInputStream(getClass().getResource("/model/types.yang").getPath());
+                InputStream stream3 = new FileInputStream(getClass().getResource("/model/nodes.yang").getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream1, stream2, stream3)));
+        }
+        Module module = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/test2.yang").getPath())) {
+            module = TestUtils.loadModuleWithContext(stream, context);
+        }
+        assertNotNull(module);
+
+        ContainerSchemaNode peer = (ContainerSchemaNode) module.getDataChildByName("peer");
+        ContainerSchemaNode destination = (ContainerSchemaNode) peer.getDataChildByName("destination");
+        Set<UsesNode> usesNodes = destination.getUses();
+        assertEquals(1, usesNodes.size());
+        UsesNode usesNode = usesNodes.iterator().next();
+
+        // test grouping path
+        List<QName> path = new ArrayList<QName>();
+        QName qname = new QName(URI.create("urn:custom.nodes.test"), simpleDateFormat.parse("2013-02-27"), "c",
+                "target");
+        path.add(qname);
+        SchemaPath expectedPath = new SchemaPath(path, true);
+        assertEquals(expectedPath, usesNode.getGroupingPath());
+
+        // test refine
+        Map<SchemaPath, SchemaNode> refines = usesNode.getRefines();
+        assertEquals(5, refines.size());
+
+        LeafSchemaNode refineLeaf = null;
+        ContainerSchemaNode refineContainer = null;
+        ListSchemaNode refineList = null;
+        GroupingDefinition refineGrouping = null;
+        TypeDefinition<?> typedef = null;
+        for (Map.Entry<SchemaPath, SchemaNode> entry : refines.entrySet()) {
+            SchemaNode value = entry.getValue();
+            if (value instanceof LeafSchemaNode) {
+                refineLeaf = (LeafSchemaNode) value;
+            } else if (value instanceof ContainerSchemaNode) {
+                refineContainer = (ContainerSchemaNode) value;
+            } else if (value instanceof ListSchemaNode) {
+                refineList = (ListSchemaNode) value;
+            } else if (value instanceof GroupingDefinition) {
+                refineGrouping = (GroupingDefinition) value;
+            } else if (value instanceof TypeDefinition<?>) {
+                typedef = (TypeDefinition<?>) value;
+            }
+        }
+
+        // leaf address
+        assertNotNull(refineLeaf);
+        assertEquals("address", refineLeaf.getQName().getLocalName());
+        assertEquals("description of address defined by refine", refineLeaf.getDescription());
+        assertEquals("address reference added by refine", refineLeaf.getReference());
+        assertFalse(refineLeaf.isConfiguration());
+        assertTrue(refineLeaf.getConstraints().isMandatory());
+        Set<MustDefinition> leafMustConstraints = refineLeaf.getConstraints().getMustConstraints();
+        assertEquals(1, leafMustConstraints.size());
+        MustDefinition leafMust = leafMustConstraints.iterator().next();
+        assertEquals("\"ifType != 'ethernet' or (ifType = 'ethernet' and ifMTU = 1500)\"", leafMust.toString());
+
+        // container port
+        assertNotNull(refineContainer);
+        Set<MustDefinition> mustConstraints = refineContainer.getConstraints().getMustConstraints();
+        assertTrue(mustConstraints.isEmpty());
+        assertEquals("description of port defined by refine", refineContainer.getDescription());
+        assertEquals("port reference added by refine", refineContainer.getReference());
+        assertFalse(refineContainer.isConfiguration());
+        assertTrue(refineContainer.isPresenceContainer());
+
+        // list addresses
+        assertNotNull(refineList);
+        assertEquals("description of addresses defined by refine", refineList.getDescription());
+        assertEquals("addresses reference added by refine", refineList.getReference());
+        assertFalse(refineList.isConfiguration());
+        assertEquals(2, (int) refineList.getConstraints().getMinElements());
+        assertEquals(12, (int) refineList.getConstraints().getMaxElements());
+
+        // grouping target-inner
+        assertNotNull(refineGrouping);
+        Set<DataSchemaNode> refineGroupingChildren = refineGrouping.getChildNodes();
+        assertEquals(1, refineGroupingChildren.size());
+        LeafSchemaNode refineGroupingLeaf = (LeafSchemaNode) refineGroupingChildren.iterator().next();
+        assertEquals("inner-grouping-id", refineGroupingLeaf.getQName().getLocalName());
+        assertEquals("new target-inner grouping description", refineGrouping.getDescription());
+
+        // typedef group-type
+        assertNotNull(typedef);
+        assertEquals("new group-type description", typedef.getDescription());
+        assertEquals("new group-type reference", typedef.getReference());
+        assertTrue(typedef.getBaseType() instanceof ExtendedType);
+    }
+
+    @Test
+    public void testIdentity() throws Exception {
+        SchemaContext context = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/types/custom-types-test@2012-4-4.yang")
+                .getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream)));
+        }
+        Module module = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/test3.yang").getPath())) {
+            module = TestUtils.loadModuleWithContext(stream, context);
+        }
+        assertNotNull(module);
+
+        Set<IdentitySchemaNode> identities = module.getIdentities();
+        assertEquals(1, identities.size());
+
+        IdentitySchemaNode identity = identities.iterator().next();
+        QName idQName = identity.getQName();
+        assertEquals(URI.create("urn:simple.demo.test3"), idQName.getNamespace());
+        assertEquals(simpleDateFormat.parse("2013-06-18"), idQName.getRevision());
+        assertEquals("t3", idQName.getPrefix());
+        assertEquals("pt", idQName.getLocalName());
+
+        IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
+        QName idBaseQName = baseIdentity.getQName();
+        assertEquals(URI.create("urn:custom.types.demo"), idBaseQName.getNamespace());
+        assertEquals(simpleDateFormat.parse("2012-04-16"), idBaseQName.getRevision());
+        assertEquals("iit", idBaseQName.getPrefix());
+        assertEquals("service-type", idBaseQName.getLocalName());
+    }
+
+    @Test
+    public void testUnknownNodes() throws Exception {
+        SchemaContext context = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/types/custom-types-test@2012-4-4.yang")
+                .getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream)));
+        }
+
+        Module module = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/test3.yang").getPath())) {
+            module = TestUtils.loadModuleWithContext(stream, context);
+        }
+
+        ContainerSchemaNode network = (ContainerSchemaNode) module.getDataChildByName("network");
+        List<UnknownSchemaNode> unknownNodes = network.getUnknownSchemaNodes();
+        assertEquals(1, unknownNodes.size());
+
+        UnknownSchemaNode un = unknownNodes.get(0);
+        QName unType = un.getNodeType();
+        assertEquals(URI.create("urn:custom.types.demo"), unType.getNamespace());
+        assertEquals(simpleDateFormat.parse("2012-04-16"), unType.getRevision());
+        assertEquals("custom", unType.getPrefix());
+        assertEquals("mountpoint", unType.getLocalName());
+        assertEquals("point", un.getNodeParameter());
+    }
+
+    @Test
+    public void testAugment() throws Exception {
+        // load first module
+        SchemaContext context = null;
+        String resource = "/context-augment-test/test4.yang";
+
+        try (InputStream stream = new FileInputStream(getClass().getResource(resource).getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream)));
+        }
+
+        Set<Module> contextModules = context.getModules();
+        Module t3 = TestUtils.findModule(contextModules, "test4");
+        ContainerSchemaNode interfaces = (ContainerSchemaNode) t3.getDataChildByName("interfaces");
+        ListSchemaNode ifEntry = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+
+        // load another modules and parse them against already existing context
+        Set<Module> modules = null;
+        try (InputStream stream1 = new FileInputStream(getClass().getResource("/context-augment-test/test1.yang")
+                .getPath());
+                InputStream stream2 = new FileInputStream(getClass().getResource("/context-augment-test/test2.yang")
+                        .getPath());
+                InputStream stream3 = new FileInputStream(getClass().getResource("/context-augment-test/test3.yang")
+                        .getPath())) {
+            List<InputStream> input = Lists.newArrayList(stream1, stream2, stream3);
+            modules = TestUtils.loadModulesWithContext(input, context);
+        }
+        assertNotNull(modules);
+
+        // test augmentation process
+        ContainerSchemaNode augmentHolder = (ContainerSchemaNode) ifEntry.getDataChildByName("augment-holder");
+        assertNotNull(augmentHolder);
+        DataSchemaNode ds0 = augmentHolder.getDataChildByName("ds0ChannelNumber");
+        assertNotNull(ds0);
+        DataSchemaNode interfaceId = augmentHolder.getDataChildByName("interface-id");
+        assertNotNull(interfaceId);
+        DataSchemaNode higherLayerIf = augmentHolder.getDataChildByName("higher-layer-if");
+        assertNotNull(higherLayerIf);
+        ContainerSchemaNode schemas = (ContainerSchemaNode) augmentHolder.getDataChildByName("schemas");
+        assertNotNull(schemas);
+        assertNotNull(schemas.getDataChildByName("id"));
+
+        // test augment target after augmentation: check if it is same instance
+        ListSchemaNode ifEntryAfterAugment = (ListSchemaNode) interfaces.getDataChildByName("ifEntry");
+        assertTrue(ifEntry == ifEntryAfterAugment);
+    }
+
+    @Test
+    public void testDeviation() throws Exception {
+        // load first module
+        SchemaContext context = null;
+        String resource = "/model/types.yang";
+
+        try (InputStream stream = new FileInputStream(getClass().getResource(resource).getPath())) {
+            context = parser.resolveSchemaContext(TestUtils.loadModules(Lists.newArrayList(stream)));
+        }
+
+        // load another modules and parse them against already existing context
+        Set<Module> modules = null;
+        try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/deviation-test.yang")
+                .getPath())) {
+            List<InputStream> input = Lists.newArrayList(stream);
+            modules = TestUtils.loadModulesWithContext(input, context);
+        }
+        assertNotNull(modules);
+
+        // test deviation
+        Module testModule = TestUtils.findModule(modules, "deviation-test");
+        Set<Deviation> deviations = testModule.getDeviations();
+        assertEquals(1, deviations.size());
+        Deviation dev = deviations.iterator().next();
+
+        assertEquals("system/user ref", dev.getReference());
+
+        URI expectedNS = URI.create("urn:simple.types.test");
+        DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date expectedRev = simpleDateFormat.parse("2013-07-03");
+        List<QName> path = new ArrayList<QName>();
+        path.add(new QName(expectedNS, expectedRev, "t", "interfaces"));
+        path.add(new QName(expectedNS, expectedRev, "t", "ifEntry"));
+        SchemaPath expectedPath = new SchemaPath(path, true);
+
+        assertEquals(expectedPath, dev.getTargetPath());
+        assertEquals(Deviate.ADD, dev.getDeviate());
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySortTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySortTest.java
new file mode 100644 (file)
index 0000000..70bf404
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import static org.hamcrest.core.AnyOf.anyOf;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Mockito.*;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.opendaylight.controller.yang.model.api.Module;
+import org.opendaylight.controller.yang.model.api.ModuleImport;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.controller.yang.parser.util.ModuleDependencySort.ModuleNodeImpl;
+import org.opendaylight.controller.yang.parser.util.TopologicalSort.Edge;
+
+import com.google.common.collect.Sets;
+
+public class ModuleDependencySortTest {
+
+    private ModuleBuilder a = mockModuleBuilder("a", null);
+    private ModuleBuilder b = mockModuleBuilder("b", null);
+    private ModuleBuilder c = mockModuleBuilder("c", null);
+    private ModuleBuilder d = mockModuleBuilder("d", null);
+
+    @Test
+    public void testValid() throws Exception {
+
+        mockDependency(a, b);
+        mockDependency(b, c);
+        mockDependency(b, d);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { d, b, c, a };
+
+        List<ModuleBuilder> l = ModuleDependencySort.sort(builders);
+
+        assertDependencyGraph(ModuleDependencySort.createModuleGraph(Arrays.asList(builders)));
+
+        @SuppressWarnings("unchecked")
+        Matcher<String> cOrD = anyOf(is(c.getName()), is(d.getName()));
+
+        assertThat(l.get(0).getName(), cOrD);
+        assertThat(l.get(1).getName(), cOrD);
+        assertThat(l.get(2).getName(), is(b.getName()));
+        assertThat(l.get(3).getName(), is(a.getName()));
+    }
+
+    @Test
+    public void testValidModule() throws Exception {
+
+        Date rev = new Date();
+        Module a = mockModule("a", rev);
+        Module b = mockModule("b", rev);
+        Module c = mockModule("c", rev);
+
+        mockDependency(a, b);
+        mockDependency(b, c);
+        mockDependency(a, c);
+
+        Module[] builders = new Module[] { a, b, c };
+
+        List<Module> l = ModuleDependencySort.sort(builders);
+
+        assertThat(l.get(0).getName(), is(c.getName()));
+        assertThat(l.get(1).getName(), is(b.getName()));
+        assertThat(l.get(2).getName(), is(a.getName()));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testModuleTwice() throws Exception {
+        ModuleBuilder a2 = mockModuleBuilder("a", null);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2 };
+        try {
+            ModuleDependencySort.sort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(), containsString("Module:a with revision:default declared twice"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testImportNotExistingModule() throws Exception {
+        mockDependency(a, b);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a };
+        try {
+            ModuleDependencySort.sort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(), containsString("Not existing module imported:b:default by:a:default"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testImportTwice() throws Exception {
+        mockDependency(a, b);
+        mockDependency(c, b);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, b, c };
+        ModuleDependencySort.sort(builders);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testImportTwiceDifferentRevision() throws Exception {
+        Date date1 = new Date(463846463486L);
+        Date date2 = new Date(364896446683L);
+        b = mockModuleBuilder("b", date1);
+        ModuleBuilder b2 = mockModuleBuilder("b", date2);
+
+        mockDependency(a, b);
+        mockDependency(c, b2);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, c, b, b2 };
+        try {
+            ModuleDependencySort.sort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(), containsString("Module:b imported twice with different revisions:"
+                    + YangParserListenerImpl.simpleDateFormat.format(date1) + ", "
+                    + YangParserListenerImpl.simpleDateFormat.format(date2)));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testModuleTwiceWithDifferentRevs() throws Exception {
+        ModuleBuilder a2 = mockModuleBuilder("a", new Date());
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2 };
+        ModuleDependencySort.sort(builders);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testModuleTwice2() throws Exception {
+        Date rev = new Date();
+        ModuleBuilder a2 = mockModuleBuilder("a", rev);
+        ModuleBuilder a3 = mockModuleBuilder("a", rev);
+
+        ModuleBuilder[] builders = new ModuleBuilder[] { a, a2, a3 };
+        try {
+            ModuleDependencySort.sort(builders);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(), containsString("Module:a with revision:"
+                    + YangParserListenerImpl.simpleDateFormat.format(rev) + " declared twice"));
+            throw e;
+        }
+    }
+
+    private void assertDependencyGraph(Map<String, Map<Date, ModuleNodeImpl>> moduleGraph) {
+        for (Entry<String, Map<Date, ModuleNodeImpl>> node : moduleGraph.entrySet()) {
+            String name = node.getKey();
+
+            // Expects only one module revision
+
+            Set<Edge> inEdges = node.getValue().values().iterator().next().getInEdges();
+            Set<Edge> outEdges = node.getValue().values().iterator().next().getOutEdges();
+
+            if (name.equals("a")) {
+                assertEdgeCount(inEdges, 0, outEdges, 1);
+            } else if (name.equals("b")) {
+                assertEdgeCount(inEdges, 1, outEdges, 2);
+            } else {
+                assertEdgeCount(inEdges, 1, outEdges, 0);
+            }
+        }
+    }
+
+    private void assertEdgeCount(Set<Edge> inEdges, int i, Set<Edge> outEdges, int j) {
+        assertThat(inEdges.size(), is(i));
+        assertThat(outEdges.size(), is(j));
+    }
+
+    private void mockDependency(ModuleBuilder a, ModuleBuilder b) {
+        ModuleImport imprt = mock(ModuleImport.class);
+        doReturn(b.getName()).when(imprt).getModuleName();
+        doReturn(b.getRevision()).when(imprt).getRevision();
+        a.getModuleImports().add(imprt);
+    }
+
+    private void mockDependency(Module a, Module b) {
+        ModuleImport imprt = mock(ModuleImport.class);
+        doReturn(b.getName()).when(imprt).getModuleName();
+        doReturn(b.getRevision()).when(imprt).getRevision();
+        a.getImports().add(imprt);
+    }
+
+    private ModuleBuilder mockModuleBuilder(String name, Date rev) {
+        ModuleBuilder a = mock(ModuleBuilder.class);
+        doReturn(name).when(a).getName();
+        Set<ModuleImport> set = Sets.newHashSet();
+        doReturn(set).when(a).getModuleImports();
+        if (rev != null) {
+            doReturn(rev).when(a).getRevision();
+        }
+        return a;
+    }
+
+    private Module mockModule(String name, Date rev) {
+        Module a = mock(Module.class);
+        doReturn(name).when(a).getName();
+        Set<ModuleImport> set = Sets.newHashSet();
+        doReturn(set).when(a).getImports();
+        if (rev != null) {
+            doReturn(rev).when(a).getRevision();
+        }
+        return a;
+    }
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/TopologicalSortTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/TopologicalSortTest.java
new file mode 100644 (file)
index 0000000..1cd97bf
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.parser.util;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.opendaylight.controller.yang.parser.util.TopologicalSort.Node;
+import org.opendaylight.controller.yang.parser.util.TopologicalSort.NodeImpl;
+
+import com.google.common.collect.Sets;
+
+public class TopologicalSortTest {
+
+    @Test(expected = IllegalStateException.class)
+    public void test() throws Exception {
+        Set<Node> nodes = Sets.newHashSet();
+
+        NodeImpl node1 = new NodeImpl();
+        nodes.add(node1);
+        NodeImpl node2 = new NodeImpl();
+        nodes.add(node2);
+        NodeImpl node3 = new NodeImpl();
+        nodes.add(node3);
+
+        node1.addEdge(node2);
+        node2.addEdge(node3);
+        node3.addEdge(node1);
+
+        try {
+            TopologicalSort.sort(nodes);
+        } catch (IllegalStateException e) {
+            throw e;
+        }
+    }
+
+    @Test
+    public void testValidSimple() throws Exception {
+        Set<Node> nodes = Sets.newHashSet();
+
+        Node node1 = new NodeImpl();
+        nodes.add(node1);
+        Node node2 = new NodeImpl();
+        nodes.add(node2);
+        Node node3 = new NodeImpl();
+        nodes.add(node3);
+        Node node4 = new NodeImpl();
+        nodes.add(node4);
+
+        ((NodeImpl) node1).addEdge(node2);
+        ((NodeImpl) node1).addEdge(node3);
+        ((NodeImpl) node2).addEdge(node4);
+        ((NodeImpl) node3).addEdge(node2);
+
+        List<Node> sorted = TopologicalSort.sort(nodes);
+
+        assertThat(sorted.get(0), is(node4));
+        assertThat(sorted.get(1), is(node2));
+        assertThat(sorted.get(2), is(node3));
+        assertThat(sorted.get(3), is(node1));
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationListTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationListTest.java
new file mode 100644 (file)
index 0000000..1db855c
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Key_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leaf_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.List_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Unique_stmtContext;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+public class YangModelValidationListTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testKeyValidationDuplicates() {
+
+        List_stmtContext list = YangModelValidationTest.mockStatement(
+                List_stmtContext.class, "list");
+        Key_stmtContext key = YangModelValidationTest.mockStatement(
+                Key_stmtContext.class, "leaf1 leaf2 leaf1 leaf1");
+        YangModelValidationTest.addChild(list, key);
+
+        try {
+            valid.enterKey_stmt(key);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("contains duplicates:[leaf1]"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testUniqueValidationDuplicates() {
+        List_stmtContext list = YangModelValidationTest.mockStatement(
+                List_stmtContext.class, "list");
+        Unique_stmtContext unique = YangModelValidationTest.mockStatement(
+                Unique_stmtContext.class, "leaf1/a leaf2/n leaf1/a leaf1");
+        YangModelValidationTest.addChild(list, unique);
+
+        try {
+            valid.enterUnique_stmt(unique);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("contains duplicates:[leaf1/a]"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testOrderBy() {
+        Ordered_by_argContext ctx = YangModelValidationTest.mockStatement(
+                Ordered_by_argContext.class, "unknown");
+
+        try {
+            valid.enterOrdered_by_arg(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Ordered-by:unknown, illegal value for Ordered-by statement, only permitted:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testLeaf() {
+        Leaf_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Leaf_stmtContext.class, "leaf1");
+        Default_stmtContext def = YangModelValidationTest.mockStatement(
+                Default_stmtContext.class, "default");
+        YangModelValidationTest.addChild(ctx, def);
+        Type_stmtContext typ = YangModelValidationTest.mockStatement(
+                Type_stmtContext.class, "type");
+        YangModelValidationTest.addChild(ctx, def);
+        YangModelValidationTest.addChild(ctx, typ);
+
+        Mandatory_stmtContext mand = YangModelValidationTest.mockStatement(
+                Mandatory_stmtContext.class, null);
+        YangModelValidationTest.addChild(ctx, mand);
+
+        try {
+            valid.enterLeaf_stmt(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Both Mandatory and Default statement present"));
+            throw e;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationModuleTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationModuleTest.java
new file mode 100644 (file)
index 0000000..3f9a53f
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+public class YangModelValidationModuleTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testRevisionInvalidDateFormat() {
+        Revision_stmtContext mockedRev = mockModuleWithRevision("badFormat",
+                "module1");
+
+        try {
+            valid.enterRevision_stmt(mockedRev);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Revision:badFormat, invalid date format expected date format is:"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testRevisionValidDateFormat() {
+        Revision_stmtContext mockedRev = mockModuleWithRevision(
+                YangModelValidationTest.getFormattedDate(), "module1");
+
+        valid.enterRevision_stmt(mockedRev);
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoHeaderStmts() {
+        Revision_stmtContext rev = mockModuleWithRevision("1999-4-5", "module1");
+
+        try {
+            valid.enterModule_stmt((Module_stmtContext) rev.getParent()
+                    .getParent());
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Module-header statement in Module:module1"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testMultipleModulesPerSession() {
+        Module_stmtContext module1 = (Module_stmtContext) mockModuleWithRevision(
+                "1999-09-10", "m1").getParent().getParent();
+        YangModelValidationTest.addChild(module1, YangModelValidationTest
+                .mockStatement(Namespace_stmtContext.class, ""));
+
+        Module_stmtContext module2 = (Module_stmtContext) mockModuleWithRevision(
+                "1999-09-10", "m2").getParent().getParent();
+        YangModelValidationTest.addChild(module1, YangModelValidationTest
+                .mockStatement(Namespace_stmtContext.class, ""));
+        valid.enterModule_stmt(module1);
+
+        try {
+            valid.enterModule_stmt(module2);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Multiple (sub)modules per file"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoNamespace() {
+        Module_header_stmtsContext header = YangModelValidationTest
+                .mockStatement(Module_header_stmtsContext.class, null);
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, header);
+
+        try {
+            valid.enterModule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Namespace statement in Module-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoPrefix() {
+        Module_header_stmtsContext header = YangModelValidationTest
+                .mockStatement(Module_header_stmtsContext.class, null);
+        Namespace_stmtContext nmspc = YangModelValidationTest.mockStatement(
+                Namespace_stmtContext.class, "http://test");
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, header);
+        YangModelValidationTest.addChild(header, nmspc);
+
+        try {
+            valid.enterModule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Prefix statement in Module-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testInvalidYangVersion() {
+
+        Yang_version_stmtContext yangVersion = YangModelValidationTest
+                .mockStatement(Yang_version_stmtContext.class, "55Unsup");
+
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, "module1");
+        YangModelValidationTest.addChild(mod, yangVersion);
+
+        try {
+            valid.enterYang_version_stmt(yangVersion);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Unsupported yang version:55Unsup, supported version:"
+                            + BasicValidations.SUPPORTED_YANG_VERSION));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testValidYangVersion() {
+
+        Yang_version_stmtContext ctx = mock(Yang_version_stmtContext.class);
+        doReturn(1).when(ctx).getChildCount();
+        YangModelValidationTest.mockName(ctx, "1");
+
+        valid.enterYang_version_stmt(ctx);
+    }
+
+    private static Revision_stmtContext mockModuleWithRevision(String date,
+            String moduleName) {
+        Revision_stmtContext mockedRev = YangModelValidationTest.mockStatement(
+                Revision_stmtContext.class, date);
+        Revision_stmtsContext revs = YangModelValidationTest.mockStatement(
+                Revision_stmtsContext.class, null);
+        Module_stmtContext mod = YangModelValidationTest.mockStatement(
+                Module_stmtContext.class, moduleName);
+
+        YangModelValidationTest.addChild(revs, mockedRev);
+        YangModelValidationTest.addChild(mod, revs);
+        return mockedRev;
+    }
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationSubModuleTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationSubModuleTest.java
new file mode 100644 (file)
index 0000000..d3276fa
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Mockito.mock;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Submodule_stmtContext;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+public class YangModelValidationSubModuleTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoRevision() {
+
+        Submodule_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Submodule_stmtContext.class, "submodule1");
+
+        try {
+            valid.enterSubmodule_stmt(ctx);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Submodule-header statement in Submodule:submodule"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testNoBelongsTo() {
+        Submodule_header_stmtsContext header = mock(Submodule_header_stmtsContext.class);
+        mockSubmoduleParent(header, "submodule");
+
+        try {
+            valid.enterSubmodule_header_stmts(header);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Belongs-to statement in Submodule-header:"));
+            throw e;
+        }
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testBelongsToNoPrefix() {
+        Belongs_to_stmtContext belongsTo = YangModelValidationTest
+                .mockStatement(Belongs_to_stmtContext.class, "supermodule");
+
+        mockSubmoduleParent(belongsTo, "submodule");
+
+        try {
+            valid.enterBelongs_to_stmt(belongsTo);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Missing Prefix statement in Belongs-to:supermodule"));
+            throw e;
+        }
+    }
+
+    private Submodule_stmtContext mockSubmoduleParent(ParseTree child,
+            String moduleName) {
+        Submodule_stmtContext ctx = YangModelValidationTest.mockStatement(
+                Submodule_stmtContext.class, moduleName);
+        YangModelValidationTest.addChild(ctx, child);
+        return ctx;
+    }
+}
diff --git a/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationTest.java b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationTest.java
new file mode 100644 (file)
index 0000000..d15a7a2
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.yang.validator;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Mockito.*;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
+import org.opendaylight.controller.yang.parser.impl.YangParserListenerImpl;
+import org.opendaylight.controller.yang.parser.util.YangValidationException;
+
+import com.google.common.collect.Sets;
+
+public class YangModelValidationTest {
+
+    private YangModelBasicValidationListener valid;
+
+    @Before
+    public void setUp() {
+
+        valid = new YangModelBasicValidationListener();
+    }
+
+    @Test
+    public void testPrefixes() {
+        Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class,
+                "unique1");
+        Module_stmtContext module = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(module, pref);
+
+        valid.enterPrefix_stmt(pref);
+
+        pref = mockStatement(Prefix_stmtContext.class, "unique1");
+        module = mockStatement(Module_stmtContext.class, "module1");
+        addChild(module, pref);
+
+        try {
+            valid.enterPrefix_stmt(pref);
+        } catch (Exception e) {
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testNamespace() {
+
+        Namespace_stmtContext namespace = mockStatement(
+                Namespace_stmtContext.class, "http://test.parsing.uri.com");
+        Module_stmtContext module = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(module, namespace);
+
+        valid.enterNamespace_stmt(namespace);
+
+        namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
+        module = mockStatement(Module_stmtContext.class, "module1");
+        addChild(module, namespace);
+
+        try {
+            valid.enterNamespace_stmt(namespace);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Namespace:invalid uri cannot be parsed as URI"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testImports() {
+        Import_stmtContext impor = mockImport("unique1", "p1");
+        Module_stmtContext mod = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(mod, impor);
+
+        valid.enterImport_stmt(impor);
+
+        impor = mockImport("unique1", "p2");
+        mod = mockStatement(Module_stmtContext.class, "module1");
+        addChild(mod, impor);
+
+        try {
+            valid.enterImport_stmt(impor);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Import:unique1 not unique"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testIncludes() {
+        Include_stmtContext incl = mockInclude("unique1");
+        Module_stmtContext mod = mockStatement(Module_stmtContext.class,
+                "module1");
+        addChild(mod, incl);
+        valid.enterInclude_stmt(incl);
+
+        incl = mockInclude("unique1");
+        mod = mockStatement(Module_stmtContext.class, "module1");
+        addChild(mod, incl);
+
+        try {
+            valid.enterInclude_stmt(incl);
+        } catch (YangValidationException e) {
+            assertThat(e.getMessage(),
+                    containsString("Include:unique1 not unique in (sub)module"));
+            return;
+        }
+
+        fail("Validation Exception should have occured");
+    }
+
+    @Test
+    public void testIdentifierMatching() {
+        List<String> ids = new ArrayList<String>();
+        // valid
+        ids.add("_ok98-.87.-.8...88-asdAD");
+        ids.add("AA.bcd");
+        ids.add("a");
+        // invalid
+        ids.add("9aa");
+        ids.add("-");
+        ids.add(".");
+
+        int thrown = 0;
+        for (String id : ids) {
+            try {
+                Module_stmtContext module = mock(Module_stmtContext.class);
+                Token token = mock(Token.class);
+                when(module.getStart()).thenReturn(token);
+                BasicValidations.checkIdentifierInternal(
+                        module, id);
+            } catch (YangValidationException e) {
+                thrown++;
+            }
+        }
+
+        assertThat(thrown, is(3));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testAugument() {
+        Augment_stmtContext augument = mockStatement(Augment_stmtContext.class,
+                "/a:*abc/a:augument1");
+        Module_stmtContext mod1 = mockStatement(Module_stmtContext.class,
+                "mod1");
+        addChild(mod1, augument);
+
+        Token token = mock(Token.class);
+        when(augument.getStart()).thenReturn(token);
+
+        try {
+            valid.enterAugment_stmt(augument);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
+            throw e;
+        }
+    }
+
+    @Test
+    public void testDeviate() {
+        Deviation_stmtContext ctx = mockStatement(Deviation_stmtContext.class,
+                "deviations");
+        Deviate_add_stmtContext add = mockStatement(
+                Deviate_add_stmtContext.class, "add");
+        Deviate_delete_stmtContext del = mockStatement(
+                Deviate_delete_stmtContext.class, "delete");
+
+        addChild(ctx, add);
+        addChild(ctx, del);
+
+        valid.enterDeviation_stmt(ctx);
+
+        HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
+        types.add(Deviate_add_stmtContext.class);
+        types.add(Deviate_delete_stmtContext.class);
+
+        int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
+        assertThat(count, is(2));
+    }
+
+    @Test(expected = YangValidationException.class)
+    public void testStatus() throws Exception {
+        Status_argContext status = mockStatement(Status_argContext.class,
+                "unknown");
+        try {
+            valid.enterStatus_arg(status);
+        } catch (YangValidationException e) {
+            assertThat(
+                    e.getMessage(),
+                    containsString("illegal value for Status statement, only permitted:"));
+            throw e;
+        }
+    }
+
+    private Import_stmtContext mockImport(String name, String prefixName) {
+        Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
+
+        Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class,
+                prefixName);
+        Revision_date_stmtContext revDate = mockStatement(
+                Revision_date_stmtContext.class, getFormattedDate());
+
+        addChild(impor, prefix);
+        addChild(impor, revDate);
+        return impor;
+    }
+
+    static String getFormattedDate() {
+        return YangParserListenerImpl.simpleDateFormat.format(new Date());
+    }
+
+    private Include_stmtContext mockInclude(String name) {
+        Include_stmtContext incl = mockStatement(Include_stmtContext.class,
+                name);
+
+        Revision_date_stmtContext revDate = mockStatement(
+                Revision_date_stmtContext.class, getFormattedDate());
+
+        addChild(incl, revDate);
+        return incl;
+    }
+
+    static void mockName(ParseTree stmt, String name) {
+        StringContext nameCtx = mock(StringContext.class);
+        ParseTree internalName = mock(ParseTree.class);
+        doReturn(1).when(stmt).getChildCount();
+        doReturn(name).when(internalName).getText();
+        doReturn(internalName).when(nameCtx).getChild(0);
+        doReturn(nameCtx).when(stmt).getChild(0);
+    }
+
+    static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
+        T stmt = stmtType.cast(mock(stmtType));
+
+        doReturn(0).when(stmt).getChildCount();
+
+        if (name != null)
+            mockName(stmt, name);
+        return stmt;
+    }
+
+    static void addChild(ParseTree parent, ParseTree child) {
+        int childCount = parent.getChildCount() + 1;
+        doReturn(childCount).when(parent).getChildCount();
+        doReturn(child).when(parent).getChild(childCount - 1);
+        doReturn(parent).when(child).getParent();
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-augment-test/test1.yang b/yang-model-parser-impl/src/test/resources/context-augment-test/test1.yang
new file mode 100644 (file)
index 0000000..04468fb
--- /dev/null
@@ -0,0 +1,34 @@
+module test1 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test1";
+    prefix "t1";
+
+    import test3 {
+        prefix "t3";
+        revision-date 2013-06-18;
+    }
+
+    import test2 {
+        prefix "t2";
+        revision-date 2013-06-18;
+    }
+
+    import test4 {
+        prefix "t4";
+        revision-date 2013-06-18;
+    }
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    augment "/t4:interfaces/t4:ifEntry/t2:augment-holder/t3:schemas" {
+        when "if:ifType='ds0'";
+        leaf id {
+            type string;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-augment-test/test2.yang b/yang-model-parser-impl/src/test/resources/context-augment-test/test2.yang
new file mode 100644 (file)
index 0000000..44bdf66
--- /dev/null
@@ -0,0 +1,41 @@
+module test2 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test2";
+    prefix "t2";
+
+    import test3 {
+        prefix "t3";
+        revision-date 2013-06-18;
+    }
+
+    import test4 {
+        prefix "t4";
+        revision-date 2013-06-18;
+    }
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    augment "/t4:interfaces/t4:ifEntry/t3:augment-holder" {
+        when "if:ifType='ds0'";
+        leaf ds0ChannelNumber {
+            type string;
+        }
+        leaf interface-id {
+            type leafref {
+                path "/if:interfaces/if:interface/if:name";
+            }
+        }
+        leaf-list higher-layer-if {
+            type leafref {
+                path "/if:interfaces/if:interface/if:higher-layer-if";
+            }
+        }
+        container schemas {
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-augment-test/test3.yang b/yang-model-parser-impl/src/test/resources/context-augment-test/test3.yang
new file mode 100644 (file)
index 0000000..f954153
--- /dev/null
@@ -0,0 +1,24 @@
+module test3 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test3";
+    prefix "t3";
+
+    import test4 {
+        prefix "t4";
+        revision-date 2013-06-18;
+    }
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    augment "/t4:interfaces/t4:ifEntry" {
+        when "if:ifType='ds0'";
+        container augment-holder {
+            description "Description for augment holder";
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-augment-test/test4.yang b/yang-model-parser-impl/src/test/resources/context-augment-test/test4.yang
new file mode 100644 (file)
index 0000000..9d57a9e
--- /dev/null
@@ -0,0 +1,27 @@
+module test4 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test4";
+    prefix "t4";
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    container interfaces {
+         list ifEntry {
+             key "ifIndex";
+             leaf ifIndex {
+                 type uint32;
+                 units minutes;
+             }
+             leaf ifMtu {
+                 type int32;
+             }
+             min-elements 1;
+             max-elements 11;
+         }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-test/deviation-test.yang b/yang-model-parser-impl/src/test/resources/context-test/deviation-test.yang
new file mode 100644 (file)
index 0000000..eafcb56
--- /dev/null
@@ -0,0 +1,27 @@
+module deviation-test {
+    yang-version 1;
+    namespace "urn:simple.deviation.test";
+    prefix "dev";
+
+    import types {
+        prefix "t";
+        revision-date 2013-07-03;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+
+    deviation /t:interfaces/t:ifEntry {
+        deviate add {
+            default "admin"; // new users are 'admin' by default
+            config "true";
+        }
+        reference "system/user ref";
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-test/test1.yang b/yang-model-parser-impl/src/test/resources/context-test/test1.yang
new file mode 100644 (file)
index 0000000..1ba5142
--- /dev/null
@@ -0,0 +1,29 @@
+module test1 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test1";
+    prefix "t1";
+    
+    import ietf-inet-types {
+        prefix "inet";
+        revision-date 2010-09-24;
+    }
+    
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+    
+    typedef dscp-ext {
+        type inet:dscp {
+            range "min..max";
+        }
+    }
+
+    leaf id {
+        type inet:port-number {
+            range "0..65536";
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-test/test2.yang b/yang-model-parser-impl/src/test/resources/context-test/test2.yang
new file mode 100644 (file)
index 0000000..4cff192
--- /dev/null
@@ -0,0 +1,54 @@
+module test2 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test2";
+    prefix "t2";
+
+    import custom {
+        prefix "data";
+    }
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    container peer {
+        container destination {
+            uses data:target {
+                refine address {
+                    default "1.2.3.4";
+                    description "description of address defined by refine";
+                    reference "address reference added by refine";
+                    config false;
+                    mandatory true;
+                    must "ifType != 'ethernet' or " +
+                            "(ifType = 'ethernet' and ifMTU = 1500)" {
+                        error-message "An ethernet MTU must be 1500";
+                    }
+                }
+                refine port {
+                    description "description of port defined by refine";
+                    reference "port reference added by refine";
+                    config false;
+                    presence "presence is required";
+                }
+                refine addresses {
+                    description "description of addresses defined by refine";
+                    reference "addresses reference added by refine";
+                    config false;
+                    min-elements 2;
+                    max-elements 12;
+                }
+                refine target-inner {
+                    description "new target-inner grouping description";
+                }
+                refine group-type {
+                    description "new group-type description";
+                    reference "new group-type reference";
+                }
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/context-test/test3.yang b/yang-model-parser-impl/src/test/resources/context-test/test3.yang
new file mode 100644 (file)
index 0000000..b597aab
--- /dev/null
@@ -0,0 +1,32 @@
+module test3 {
+
+    yang-version 1;
+    namespace "urn:simple.demo.test3";
+    prefix "t3";
+    
+    import custom-types-test {
+        prefix "custom";
+    }
+    
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2013-06-18 {
+    }
+
+    identity pt {
+        base custom:service-type;
+    }
+    
+    container network {
+        custom:mountpoint point {
+            mnt:target-ref target;
+        }
+        
+        description "network-description";
+        reference "network-reference";
+        status obsolete;
+        config true;
+        presence "some presence text";
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/model/custom.yang b/yang-model-parser-impl/src/test/resources/model/custom.yang
new file mode 100644 (file)
index 0000000..d8d6054
--- /dev/null
@@ -0,0 +1,205 @@
+module custom {
+    yang-version 1;
+    namespace "urn:custom.nodes.test";
+    prefix "c";
+
+    import types {
+        prefix "types";
+        revision-date 2013-07-03;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+    typedef union1 {
+        type union2;
+    }
+
+    typedef union2 {
+        type union {
+            type int32;
+            type types:nested-union2;
+        }
+    }
+
+    augment "/types:interfaces/types:ifEntry" {
+        when "if:ifType='ds0'";
+        container augment-holder {
+            description "Description for augment holder";
+        }
+    }
+
+    augment "/types:interfaces/types:ifEntry" {
+        when "if:ifType='ds2'";
+        container augment-holder2 {
+            description "Description for augment holder";
+        }
+    }
+
+    augment "/types:interfaces/types:ifEntry/t3:augment-holder/t1:schemas" {
+        when "if:leafType='ds1'";
+        leaf linkleaf {
+            type binary;
+        }
+    }
+
+    container network {
+        mnt:mountpoint point {
+            mnt:target-ref target;
+        }
+
+        description "network-description";
+        reference "network-reference";
+        status obsolete;
+        config true;
+        presence "some presence text";
+    }
+
+    feature local-storage {
+        description
+            "This feature means the device supports local
+             storage (memory, flash or disk) that can be used to
+             store syslog messages.";
+    }
+
+    extension c-define {
+        description
+        "Takes as argument a name string. Makes the code generator use the given name in the #define.";
+        argument "name" {
+            yin-element "true";
+        }
+    }
+
+    notification event {
+        leaf event-class {
+            type string;
+        }
+        anyxml reporting-entity;
+        leaf severity {
+            type string;
+        }
+    }
+
+    rpc get-config {
+        description
+          "Retrieve all or part of a specified configuration.";
+
+        reference "RFC 6241, Section 7.1";
+
+        input {
+            container source {
+                description
+                  "Particular configuration to retrieve.";
+
+                choice config-source {
+                    mandatory true;
+                    description
+                      "The configuration to retrieve.";
+                    case a {
+                        leaf candidate {
+                            if-feature candidate;
+                            type empty;
+                            description
+                              "The candidate configuration is the config source.";
+                        }
+                    }
+                    case b {
+                        leaf running {
+                            type empty;
+                            description
+                              "The running configuration is the config source.";
+                        }
+                    }
+                    case c {
+                        leaf startup {
+                            if-feature startup;
+                            type empty;
+                            description
+                              "The startup configuration is the config source.
+                               This is optional-to-implement on the server because
+                               not all servers will support filtering for this
+                               datastore.";
+                        }
+                    }
+                }
+            }
+
+            anyxml filter {
+                description
+                  "Subtree or XPath filter to use.";
+                   nc:get-filter-element-attributes;
+            }
+        }
+
+        output {
+            anyxml data {
+                description
+                  "Copy of the source datastore subset that matched
+                   the filter criteria (if any).  An empty data container
+                   indicates that the request did not produce any results.";
+            }
+        }
+    }
+
+    grouping target {
+        anyxml data {
+            config true;
+            description "Copy of the source datastore subset.";
+            mandatory false;
+            must "test-condition-text";
+            reference "test-no-reference";
+            status "obsolete";
+            when "test-when-text";
+        }
+        choice how {
+            description "test choice description";
+            default interval;
+            case interval {
+                leaf interval {
+                    type uint16;
+                    default 30;
+                    units minutes;
+                }
+            }
+            case daily {
+                leaf daily {
+                    type empty;
+                }
+                leaf time-of-day {
+                    type string;
+                    units 24-hour-clock;
+                    default 1am;
+                }
+            }
+        }
+        leaf address {
+            type string;
+            description "Target IP address";
+        }
+        container port {
+            description "Target port container";
+        }
+        list addresses {
+            key "id";
+            leaf id {
+                type int8;
+            }
+        }
+        grouping target-inner {
+            description "target-inner default description";
+            leaf inner-grouping-id {
+                type int8;
+            }
+        }
+        typedef group-type {
+            type types:my-decimal-type;
+        }
+
+        opendaylight;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/model/nodes.yang b/yang-model-parser-impl/src/test/resources/model/nodes.yang
new file mode 100644 (file)
index 0000000..2cde385
--- /dev/null
@@ -0,0 +1,201 @@
+module nodes {
+    yang-version 1;
+    namespace "urn:simple.nodes.test";
+    prefix "n";
+
+    import types {
+        prefix "t";
+        revision-date 2013-07-03;
+    }
+
+   import custom {
+        prefix "c";
+        revision-date 2013-02-27;
+    }
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+    leaf int32-leaf {
+        type t:int32-ext2 {
+            range "12..max";
+        }
+    }
+
+    leaf string-leaf {
+        type t:string-ext4;
+    }
+
+    leaf length-leaf {
+        type t:string-ext2 {
+            length "7..max";
+        }
+    }
+
+    leaf decimal-leaf {
+        type t:my-decimal-type {
+            fraction-digits 4;
+        }
+    }
+
+    leaf decimal-leaf2 {
+        type t:my-decimal-type;
+    }
+
+    container ext {
+        types:c-define "MY_INTERFACES";
+    }
+
+    leaf union-leaf {
+        type t:my-union-ext;
+    }
+
+    deviation /t:interfaces/t:ifEntry {
+        deviate add {
+            default "admin"; // new users are 'admin' by default
+            config "true";
+        }
+        reference "system/user ref";
+    }
+
+    leaf custom-union-leaf {
+        type c:union1;
+    }
+
+    container transfer {
+        choice how {
+            default interval;
+            container input {
+            }
+            list output {
+                leaf id {
+                    type string;
+                }
+            }
+            case interval {
+                leaf interval {
+                    type uint16;
+                    default 30;
+                    units minutes;
+                }
+            }
+            case daily {
+                leaf daily {
+                    type empty;
+                }
+                leaf time-of-day {
+                    type string;
+                    units 24-hour-clock;
+                    default 1am;
+                }
+            }
+            case manual {
+                leaf manual {
+                    type empty;
+                }
+            }
+        }
+    }
+
+    anyxml datas {
+        description
+          "Copy of the source typesstore subset that matched
+           the filter criteria (if any).  An empty types container
+           indicates that the request did not produce any results.";
+        status obsolete;
+    }
+
+    augment "/t:interfaces/t:ifEntry/c:augment-holder" {
+        when "if:ifType='ds0'";
+        leaf ds0ChannelNumber {
+            type string;
+        }
+        leaf interface-id {
+            type leafref {
+                path "/if:interfaces/if:interface/if:name";
+            }
+        }
+        leaf my-type {
+            type t:int32-ext2;
+        }
+        container schemas {
+        }
+        choice odl {
+            leaf id {
+                type int8;
+            }
+            case node1 {
+                description "node1";
+            }
+            case node2 {
+                description "node2";
+            }
+            container node3 {
+                description "node3";
+            }
+        }
+    }
+
+    container mycont {
+        container innercont {
+            typedef mytype {
+                type string;
+            }
+            leaf myleaf {
+                type mytype;
+            }
+        }
+    }
+
+    uses c:target {
+        augment "/mycont/innercont" {
+            description "inner augment";
+            leaf name {
+                type string;
+            }
+        }
+    }
+
+    container peer {
+        container destination {
+            uses c:target {
+                refine address {
+                    default "1.2.3.4";
+                    description "IP address of target node";
+                    reference "address reference added by refine";
+                    config false;
+                    mandatory true;
+                    must "ifType != 'ethernet' or " +
+                            "(ifType = 'ethernet' and ifMTU = 1500)" {
+                        error-message "An ethernet MTU must be 1500";
+                    }
+                }
+                refine port {
+                    description "description of port defined by refine";
+                    reference "port reference added by refine";
+                    config false;
+                    presence "presence is required";
+                }
+                refine addresses {
+                    description "description of addresses defined by refine";
+                    reference "addresses reference added by refine";
+                    config false;
+                    min-elements 2;
+                    max-elements 12;
+                }
+                refine target-inner {
+                    description "new target-inner grouping description";
+                }
+                refine group-type {
+                    description "new group-type description";
+                    reference "new group-type reference";
+                }
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/model/types.yang b/yang-model-parser-impl/src/test/resources/model/types.yang
new file mode 100644 (file)
index 0000000..bff9543
--- /dev/null
@@ -0,0 +1,100 @@
+module types {
+    yang-version 1;
+    namespace "urn:simple.types.test";
+    prefix "t";
+
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+    description "This is types-data test description";
+
+    revision "2013-07-03" {
+        reference " WILL BE DEFINED LATER";
+    }
+
+    typedef int32-ext1 {
+        type int32 {
+            range "2..20";
+        }
+    }
+
+    typedef int32-ext2 {
+        type int32-ext1 {
+            range "3..9|11..max";
+        }
+        units "mile";
+        default "11";
+    }
+
+    typedef string-ext1 {
+        type string {
+            pattern "[a-k]*";
+            length "5..11";
+        }
+    }
+
+    typedef string-ext2 {
+        type string-ext1 {
+            length "6..10";
+        }
+    }
+
+    typedef string-ext3 {
+        type string-ext2 {
+            pattern "[b-u]*";
+        }
+    }
+
+    typedef string-ext4 {
+        type string-ext3 {
+            pattern "[e-z]*";
+        }
+    }
+
+    typedef my-decimal-type {
+        type decimal64 {
+            fraction-digits 6;
+        }
+    }
+
+    typedef my-union {
+        type union {
+            type int16 {
+                range "1..100";
+            }
+            type int32;
+        }
+    }
+
+    typedef my-union-ext {
+        type my-union;
+    }
+
+    typedef nested-union2 {
+        type union {
+            type my-union-ext;
+            type string;
+        }
+    }
+
+    container interfaces {
+        grouping ifEntry {
+            container augment-holder;
+        }
+        list ifEntry {
+            key "ifIndex";
+
+            leaf ifIndex {
+                type uint32;
+                units minutes;
+            }
+
+            leaf ifMtu {
+                type int32;
+            }
+
+            min-elements 1;
+            max-elements 11;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment0.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment0.yang
new file mode 100644 (file)
index 0000000..ff8519c
--- /dev/null
@@ -0,0 +1,25 @@
+module augment0 {
+    yang-version 1;
+    namespace "urn:simple.augment0.demo";
+    prefix "a0";
+
+    container foo {
+        description "foo container";
+        container bar {
+            leaf id {
+                type int8;
+            }
+            typedef int-ext {
+                type int8 {
+                    range "5..10";
+                }
+            }
+            choice choice-ext {
+                leaf delta {
+                    type int8;
+                }
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment1.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment1.yang
new file mode 100644 (file)
index 0000000..6afb493
--- /dev/null
@@ -0,0 +1,16 @@
+module augment1 {
+    yang-version 1;
+    namespace "urn:simple.augment1.demo";
+    prefix "a1";
+
+    import augment0 {
+        prefix "a0";
+    }
+
+    augment "/a0:foo/a0:bar" {
+        leaf id {
+            type string;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment2.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment2.yang
new file mode 100644 (file)
index 0000000..4d87619
--- /dev/null
@@ -0,0 +1,14 @@
+module augment2 {
+    yang-version 1;
+    namespace "urn:simple.augment2.demo";
+    prefix "a2";
+
+    import augment0 {
+        prefix "a0";
+    }
+
+    augment "/a0:foo/a0:bar/a0:choice-ext" {
+        anyxml delta;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-leaf.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-leaf.yang
new file mode 100644 (file)
index 0000000..9679385
--- /dev/null
@@ -0,0 +1,14 @@
+module container-leaf {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    container foo {
+        description "foo container";
+    }
+
+    leaf foo {
+        type int8;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-list.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-list.yang
new file mode 100644 (file)
index 0000000..08d90af
--- /dev/null
@@ -0,0 +1,14 @@
+module container-list {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    container foo {
+        description "foo container";
+    }
+
+    list foo {
+        description "foo list";
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container.yang
new file mode 100644 (file)
index 0000000..8e347a1
--- /dev/null
@@ -0,0 +1,14 @@
+module container {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    container foo {
+        description "foo 1";
+    }
+
+    container foo {
+        description "foo 2";
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/identity.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/identity.yang
new file mode 100644 (file)
index 0000000..f81e6e5
--- /dev/null
@@ -0,0 +1,14 @@
+module identity {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    identity id1;
+
+    identity id2;
+
+    identity id1 {
+        base id2;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/typedef.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/typedef.yang
new file mode 100644 (file)
index 0000000..b4ec590
--- /dev/null
@@ -0,0 +1,14 @@
+module typedef {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    typedef int-ext {
+        type int32;
+    }
+
+    typedef int-ext {
+        type int16;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile0.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile0.yang
new file mode 100644 (file)
index 0000000..6e6377e
--- /dev/null
@@ -0,0 +1,9 @@
+module test0 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t0";
+
+    container interfaces {
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile1.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile1.yang
new file mode 100644 (file)
index 0000000..fdc7e71
--- /dev/null
@@ -0,0 +1,11 @@
+module test1 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    import some-module {
+        prefix "data";
+        revision-date 2013-02-27;
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile2.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile2.yang
new file mode 100644 (file)
index 0000000..ea5a11f
--- /dev/null
@@ -0,0 +1,29 @@
+module test2 {
+    yang-version 1;
+    namespace "urn:simple.types.data.demo";
+    prefix "t2";
+    
+    organization "opendaylight";
+    contact "http://www.opendaylight.org/";
+    
+    description "This is types-data test description";
+
+    revision "2013-02-27" {
+        reference " WILL BE DEFINED LATER";
+    }
+    
+    container c1 {
+        typedef int-ext {
+            type int32 {
+                range "10..20";
+            }
+        }
+    }
+    
+    container top {
+        leaf id {
+            type int-ext;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile3.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile3.yang
new file mode 100644 (file)
index 0000000..187e9dd
--- /dev/null
@@ -0,0 +1,19 @@
+module test3 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    import test0 {
+        prefix "data";
+    }
+    
+    augment "/data:unknown" {
+        when "if:ifType='ds0'";
+        leaf interface-id {
+            type leafref {
+                path "/if:interfaces/if:interface/if:name";
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile4.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile4.yang
new file mode 100644 (file)
index 0000000..c327de3
--- /dev/null
@@ -0,0 +1,26 @@
+module test4 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    grouping tree {
+        leaf-list node {
+            type string;
+        }
+        container holder {
+        
+        }
+    }
+
+    container schema {
+        uses tree {
+            refine node {
+                presence "true";
+            }
+            refine holder {
+                default "one";
+            }
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile5.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile5.yang
new file mode 100644 (file)
index 0000000..0d8de38
--- /dev/null
@@ -0,0 +1,19 @@
+module test5 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    typedef my-custom-string {
+        type string {
+            pattern "[a-k]*";
+            length "5..11";
+        }
+    }
+
+    typedef my-string-type {
+        type my-custom-string {
+            length "4..10";
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/negative-scenario/testfile6.yang b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile6.yang
new file mode 100644 (file)
index 0000000..31a4c1e
--- /dev/null
@@ -0,0 +1,18 @@
+module test5 {
+    yang-version 1;
+    namespace "urn:simple.container.demo";
+    prefix "t1";
+
+    typedef my-custom-int {
+        type int32 {
+            range "5..11 | 15..20";
+        }
+    }
+
+    typedef my-int-type {
+        type my-custom-int {
+            range "min..max";
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang b/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang
new file mode 100644 (file)
index 0000000..c365228
--- /dev/null
@@ -0,0 +1,113 @@
+module custom-types-test {
+
+    yang-version 1;
+    namespace "urn:custom.types.demo";
+    prefix "iit";
+
+    organization "opendaylight";
+    contact "WILL-BE-DEFINED-LATER";
+        revision 2012-04-16 {
+    }
+
+    typedef access-operations-type {
+        type bits {
+            bit create {
+                description "Any protocol operation that creates a new data node.";
+            }
+            bit read {
+                description "Any protocol operation or notification that returns the value of a data node.";
+                position 500;
+            }
+            bit update {
+                description "Any protocol operation that alters an existing data node.";
+            }
+            bit delete {
+                description "Any protocol operation that removes a data node.";
+                position 365;
+            }
+            bit exec {
+                description "Execution access to the specified protocol operation.";
+            }
+        }
+        description "NETCONF Access Operation.";
+    }
+
+    leaf inst-id-leaf1 {
+        type instance-identifier {
+           require-instance false;
+        }
+    }
+
+    leaf inst-id-leaf2 {
+        type instance-identifier;
+    }
+
+    leaf type {
+        type service-type-ref;
+    }
+
+    identity crypto-base {
+        description "crypto-base description";
+    }
+     
+    identity crypto-alg {
+        base "crypto-base";
+        description "crypto-alg description";
+    }
+
+    leaf mybits {
+        type bits {
+            bit disable-nagle {
+                position 0;
+            }
+            bit auto-sense-speed {
+                position 1;
+            }
+            bit 10-Mb-only {
+                position 2;
+            }
+        }
+        default "auto-sense-speed";
+    }
+
+    typedef ip-version {
+        type enumeration {
+            enum unknown {
+                description "An unknown or unspecified version of the Internet protocol.";
+            }
+            enum ipv4 {
+                value "19";
+                description "The IPv4 protocol as defined in RFC 791.";
+            }
+            enum ipv6 {
+                value "7";
+                description "The IPv6 protocol as defined in RFC 2460.";
+            }
+            enum default {
+                description "default ip";
+            }
+        }
+    }
+
+    identity service-type {
+        description
+            "Service identity base type. All service identities must be
+             derived from this type. A service type uniquely defines a single
+             atomic API contract, such as a Java interface, a set of C
+             function declarations, or similar.
+
+             If the service type has a corresponding Java interface, the name
+             of that interface should be attached to the derived identity MUST
+             include a java-class keyword, whose name argument points to that
+             interface.";
+    }
+
+    typedef service-type-ref {
+        description
+            "Internal type of references to service type identity.";
+        type identityref {
+            base service-type;
+        }
+    }
+
+}
diff --git a/yang-model-parser-impl/src/test/resources/types/iana-afn-safi@2012-06-04.yang b/yang-model-parser-impl/src/test/resources/types/iana-afn-safi@2012-06-04.yang
new file mode 100644 (file)
index 0000000..5d5bdd0
--- /dev/null
@@ -0,0 +1,387 @@
+module iana-afn-safi {
+  namespace "urn:ietf:params:xml:ns:yang:iana-afn-safi";
+  prefix "ianaaf";
+
+  organization
+    "IANA";
+  contact
+    "        Internet Assigned Numbers Authority
+
+     Postal: ICANN
+             4676 Admiralty Way, Suite 330
+             Marina del Rey, CA 90292
+
+     Tel:    +1 310 823 9358
+     E-Mail: iana&iana.org";
+  description
+    "This YANG module provides two typedefs containing YANG
+     definitions for the following IANA-registered enumerations:
+
+     - Address Family Numbers (AFN)
+
+     - Subsequent Address Family Identifiers (SAFI)
+
+     The latest revision of this YANG module can be obtained from the
+     IANA web site.
+
+     Copyright (c) 2012 IETF Trust and the persons identified as
+     authors of the code. All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject to
+     the license terms contained in, the Simplified BSD License set
+     forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC XXXX; see the
+     RFC itself for full legal notices.";
+  // RFC Ed.: replace XXXX with actual RFC number and remove this
+  // note.
+
+  // RFC Ed.: update the date below with the date of RFC publication
+  // and remove this note.
+  revision 2012-06-04 {
+    description
+      "Initial revision.";
+    reference
+      "RFC XXXX: TITLE";
+  }
+
+  typedef address-family {
+    type enumeration {
+      enum other {
+        value "0";
+        description
+          "none of the following";
+      }
+      enum ipv4 {
+        value "1";
+        description
+          "IP version 4";
+      }
+      enum ipv6 {
+        value "2";
+        description
+          "IP version 6";
+      }
+      enum nsap {
+        value "3";
+        description
+          "NSAP";
+      }
+      enum hdlc {
+        value "4";
+        description
+          "HDLC (8-bit multidrop)";
+      }
+      enum bbn1822 {
+        value "5";
+        description
+          "BBN 1822";
+      }
+      enum all802 {
+        value "6";
+        description
+          "802 (includes all 802 media plus Ethernet 'canonical
+           format')";
+      }
+      enum e163 {
+        value "7";
+        description
+          "E.163";
+      }
+      enum e164 {
+        value "8";
+        description
+          "E.164 (SMDS, FrameRelay, ATM)";
+      }
+      enum f69 {
+        value "9";
+        description
+          "F.69 (Telex)";
+      }
+      enum x121 {
+        value "10";
+        description
+          "X.121 (X.25, Frame Relay)";
+      }
+      enum ipx {
+        value "11";
+        description
+          "IPX (Internetwork Packet Exchange)";
+      }
+      enum appletalk {
+        value "12";
+        description
+          "Appletalk";
+      }
+      enum decnetIV {
+        value "13";
+        description
+          "DECnet IV";
+      }
+      enum banyanVines {
+        value "14";
+        description
+          "Banyan Vines";
+      }
+      enum e164withNsap {
+        value "15";
+        description
+          "E.164 with NSAP format subaddress";
+        reference
+          "ATM Forum UNI 3.1";
+      }
+      enum dns {
+        value "16";
+        description
+          "DNS (Domain Name System)";
+      }
+      enum distinguishedName {
+        value "17";
+        description
+          "Distinguished Name (per X.500)";
+      }
+      enum asNumber {
+        value "18";
+        description
+          "Autonomous System Number";
+      }
+      enum xtpOverIPv4 {
+        value "19";
+        description
+          "XTP over IP version 4";
+      }
+      enum xtpOverIpv6 {
+        value "20";
+        description
+          "XTP over IP version 6";
+      }
+      enum xtpNativeModeXTP {
+        value "21";
+        description
+          "XTP native mode XTP";
+      }
+      enum fibreChannelWWPN {
+        value "22";
+        description
+          "Fibre Channel World-Wide Port Name";
+      }
+      enum fibreChannelWWNN {
+        value "23";
+        description
+          "Fibre Channel World-Wide Node Name";
+      }
+      enum gwid {
+        value "24";
+        description
+          "Gateway Identifier";
+      }
+      enum l2vpn {
+        value "25";
+        description
+          "AFI for L2VPN information";
+        reference
+          "RFC 4761: Virtual Private LAN Service (VPLS): Using BGP
+           for Auto-Discovery and Signaling
+
+           RFC 6074: Provisioning, Auto-Discovery, and Signaling in
+           Layer 2 Virtual Private Networks (L2VPNs)
+          ";
+      }
+      enum eigrpCommon {
+        value "16384";
+        description
+          "EIGRP Common Service Family";
+      }
+      enum eigrpIPv4 {
+        value "16385";
+        description
+          "EIGRP IPv4 Service Family";
+      }
+      enum eigrpIPv6 {
+        value "16386";
+        description
+          "EIGRP IPv6 Service Family";
+      }
+      enum lcaf {
+        value "16387";
+        description
+          "LISP Canonical Address Format";
+      }
+    }
+    description
+      "This typedef is a YANG enumeration of IANA-registered address
+       family numbers (AFN).";
+    reference
+      "Address Family Numbers. IANA, 2011-01-20.
+       <http://www.iana.org/assignments/address-family-numbers/
+       address-family-numbers.xml>
+      ";
+  }
+
+  typedef subsequent-address-family {
+    type enumeration {
+      enum nlri-unicast {
+        value "1";
+        description
+          "Network Layer Reachability Information used for unicast
+           forwarding";
+        reference
+          "RFC 4760: Multiprotocol Extensions for BGP-4";
+      }
+      enum nlri-multicast {
+        value "2";
+        description
+          "Network Layer Reachability Information used for multicast
+           forwarding";
+        reference
+          "RFC 4760: Multiprotocol Extensions for BGP-4";
+      }
+      enum nlri-mpls {
+        value "4";
+        description
+          "Network Layer Reachability Information (NLRI) with MPLS
+           Labels";
+        reference
+          "RFC 3107: Carrying Label Information in BGP-4";
+      }
+      enum mcast-vpn {
+        value "5";
+        description
+          "MCAST-VPN";
+        reference
+          "RFC 6514: BGP Encodings and Procedures for Multicast in
+           MPLS/BGP IP VPNs";
+      }
+      enum nlri-dynamic-ms-pw {
+        value "6";
+        status "obsolete";
+        description
+          "Network Layer Reachability Information used for Dynamic
+           Placement of Multi-Segment Pseudowires (TEMPORARY -
+           Expires 2008-08-23)";
+        reference
+          "draft-ietf-pwe3-dynamic-ms-pw: Dynamic Placement of Multi
+           Segment Pseudowires";
+      }
+      enum encapsulation {
+        value "7";
+        description
+          "Encapsulation SAFI";
+        reference
+          "RFC 5512: The BGP Encapsulation Subsequent Address Family
+           Identifier (SAFI) and the BGP Tunnel Encapsulation
+           Attribute";
+      }
+      enum tunnel-safi {
+        value "64";
+        status "obsolete";
+        description
+          "Tunnel SAFI";
+        reference
+          "draft-nalawade-kapoor-tunnel-safi: BGP Tunnel SAFI";
+      }
+      enum vpls {
+        value "65";
+        description
+          "Virtual Private LAN Service (VPLS)";
+        reference
+          "RFC 4761: Virtual Private LAN Service (VPLS): Using BGP
+           for Auto-Discovery and Signaling
+
+           RFC 6074: Provisioning, Auto-Discovery, and Signaling in
+           Layer 2 Virtual Private Networks (L2VPNs)
+          ";
+      }
+      enum bgp-mdt {
+        value "66";
+        description
+          "BGP MDT SAFI";
+        reference
+          "RFC 6037: Cisco Systems' Solution for Multicast in
+           BGP/MPLS IP VPNs";
+      }
+      enum bgp-4over6 {
+        value "67";
+        description
+          "BGP 4over6 SAFI";
+        reference
+          "RFC 5747: 4over6 Transit Solution Using IP Encapsulation
+           and MP-BGP Extensions";
+      }
+      enum bgp-6over4 {
+        value "68";
+        description
+          "BGP 6over4 SAFI";
+      }
+      enum l1vpn-auto-discovery {
+        value "69";
+        description
+          "Layer-1 VPN auto-discovery information";
+        reference
+          "RFC 5195: BGP-Based Auto-Discovery for Layer-1 VPNs";
+      }
+      enum mpls-vpn {
+        value "128";
+        description
+          "MPLS-labeled VPN address";
+        reference
+          "RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs)";
+      }
+      enum multicast-bgp-mpls-vpn {
+        value "129";
+        description
+          "Multicast for BGP/MPLS IP Virtual Private Networks
+           (VPNs)";
+        reference
+          "RFC 6513: Multicast in MPLS/BGP IP VPNs
+
+           RFC 6514: BGP Encodings and Procedures for Multicast in
+           MPLS/BGP IP VPNs
+          ";
+      }
+      enum route-target-constraints {
+        value "132";
+        description
+          "Route Target constraints";
+        reference
+          "RFC 4684: Constrained Route Distribution for Border
+           Gateway Protocol/MultiProtocol Label Switching (BGP/MPLS)
+           Internet Protocol (IP) Virtual Private Networks (VPNs)";
+      }
+      enum ipv4-diss-flow {
+        value "133";
+        description
+          "IPv4 dissemination of flow specification rules";
+        reference
+          "RFC 5575: Dissemination of Flow Specification Rules";
+      }
+      enum vpnv4-diss-flow {
+        value "134";
+        description
+          "IPv4 dissemination of flow specification rules";
+        reference
+          "RFC 5575: Dissemination of Flow Specification Rules";
+      }
+      enum vpn-auto-discovery {
+        value "140";
+        status "obsolete";
+        description
+          "VPN auto-discovery";
+        reference
+          "draft-ietf-l3vpn-bgpvpn-auto: Using BGP as an
+           Auto-Discovery Mechanism for VR-based Layer-3 VPNs";
+      }
+    }
+    description
+      "This typedef is a YANG enumeration of IANA-registered
+       subsequent address family identifiers (SAFI).";
+    reference
+      "Subsequent Address Family Identifiers (SAFI) Parameters. IANA,
+       2012-02-22. <http://www.iana.org/assignments/safi-namespace/
+       safi-namespace.xml>
+      ";
+  }
+}
diff --git a/yang-model-parser-impl/src/test/resources/types/iana-if-type@2012-06-05.yang b/yang-model-parser-impl/src/test/resources/types/iana-if-type@2012-06-05.yang
new file mode 100644 (file)
index 0000000..c5ce80c
--- /dev/null
@@ -0,0 +1,1516 @@
+module iana-if-type {
+  namespace "urn:ietf:params:xml:ns:yang:iana-if-type";
+  prefix ianaift;
+
+  organization "IANA";
+  contact
+    "        Internet Assigned Numbers Authority
+
+     Postal: ICANN
+             4676 Admiralty Way, Suite 330
+             Marina del Rey, CA 90292
+
+     Tel:    +1 310 823 9358
+     E-Mail: iana&iana.org";
+  description
+    "This YANG module defines the iana-if-type typedef, which
+     contains YANG definitions for IANA-registered interface types.
+
+     This YANG module is maintained by IANA, and reflects the
+     'ifType definitions' registry.
+
+     The latest revision of this YANG module can be obtained from
+     the IANA web site.
+
+     Copyright (c) 2011 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC XXXX; see
+     the RFC itself for full legal notices.";
+  // RFC Ed.: replace XXXX with actual RFC number and remove this
+  // note.
+
+  // RFC Ed.: update the date below with the date of RFC publication
+  // and remove this note.
+  revision 2012-06-05 {
+    description
+      "Initial revision.";
+    reference
+      "RFC XXXX: TITLE";
+  }
+
+  typedef iana-if-type {
+    type enumeration {
+      enum "other" {
+        value 1;
+        description
+          "None of the following";
+      }
+      enum "regular1822" {
+        value 2;
+      }
+      enum "hdh1822" {
+        value 3;
+      }
+      enum "ddnX25" {
+        value 4;
+      }
+      enum "rfc877x25" {
+        value 5;
+        reference
+          "RFC 1382 - SNMP MIB Extension for the X.25 Packet Layer";
+      }
+      enum "ethernetCsmacd" {
+        value 6;
+        description
+          "For all ethernet-like interfaces, regardless of speed,
+           as per RFC3635.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "iso88023Csmacd" {
+        value 7;
+        status deprecated;
+        description
+          "Deprecated via RFC3635.
+           Use ethernetCsmacd(6) instead.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "iso88024TokenBus" {
+        value 8;
+      }
+      enum "iso88025TokenRing" {
+        value 9;
+      }
+      enum "iso88026Man" {
+        value 10;
+      }
+      enum "starLan" {
+        value 11;
+        status deprecated;
+        description
+          "Deprecated via RFC3635.
+           Use ethernetCsmacd(6) instead.";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "proteon10Mbit" {
+        value 12;
+      }
+      enum "proteon80Mbit" {
+        value 13;
+      }
+      enum "hyperchannel" {
+        value 14;
+      }
+      enum "fddi" {
+        value 15;
+        reference
+          "RFC 1512 - FDDI Management Information Base";
+      }
+      enum "lapb" {
+        value 16;
+        reference
+          "RFC 1381 - SNMP MIB Extension for X.25 LAPB";
+      }
+      enum "sdlc" {
+        value 17;
+      }
+      enum "ds1" {
+        value 18;
+        description
+          "DS1-MIB";
+        reference
+          "RFC 4805 - Definitions of Managed Objects for the
+                      DS1, J1, E1, DS2, and E2 Interface Types";
+      }
+      enum "e1" {
+        value 19;
+        status obsolete;
+        description
+          "Obsolete see DS1-MIB";
+        reference
+          "RFC 4805 - Definitions of Managed Objects for the
+                      DS1, J1, E1, DS2, and E2 Interface Types";
+      }
+      enum "basicISDN" {
+        value 20;
+        description
+          "see also RFC2127";
+      }
+      enum "primaryISDN" {
+        value 21;
+      }
+      enum "propPointToPointSerial" {
+        value 22;
+        description
+          "proprietary serial";
+      }
+      enum "ppp" {
+        value 23;
+      }
+      enum "softwareLoopback" {
+        value 24;
+      }
+      enum "eon" {
+        value 25;
+        description
+          "CLNP over IP";
+      }
+      enum "ethernet3Mbit" {
+        value 26;
+      }
+      enum "nsip" {
+        value 27;
+        description
+          "XNS over IP";
+      }
+      enum "slip" {
+        value 28;
+        description
+          "generic SLIP";
+      }
+      enum "ultra" {
+        value 29;
+        description
+          "ULTRA technologies";
+      }
+      enum "ds3" {
+        value 30;
+        description
+          "DS3-MIB";
+        reference
+          "RFC 3896 - Definitions of Managed Objects for the
+                      DS3/E3 Interface Type";
+      }
+      enum "sip" {
+        value 31;
+        description
+          "SMDS, coffee";
+        reference
+          "RFC 1694 - Definitions of Managed Objects for SMDS
+                      Interfaces using SMIv2";
+      }
+      enum "frameRelay" {
+        value 32;
+        description
+          "DTE only.";
+        reference
+          "RFC 2115 - Management Information Base for Frame Relay
+                      DTEs Using SMIv2";
+      }
+      enum "rs232" {
+        value 33;
+        reference
+          "RFC 1659 - Definitions of Managed Objects for RS-232-like
+                      Hardware Devices using SMIv2";
+      }
+      enum "para" {
+        value 34;
+        description
+          "parallel-port";
+        reference
+          "RFC 1660 - Definitions of Managed Objects for
+                      Parallel-printer-like Hardware Devices using
+                      SMIv2";
+      }
+      enum "arcnet" {
+        value 35;
+        description
+          "arcnet";
+      }
+      enum "arcnetPlus" {
+        value 36;
+        description
+          "arcnet plus";
+      }
+      enum "atm" {
+        value 37;
+        description
+          "ATM cells";
+      }
+      enum "miox25" {
+        value 38;
+        reference
+          "RFC 1461 - SNMP MIB extension for Multiprotocol
+                      Interconnect over X.25";
+      }
+      enum "sonet" {
+        value 39;
+        description
+          "SONET or SDH";
+      }
+      enum "x25ple" {
+        value 40;
+        reference
+          "RFC 2127 - ISDN Management Information Base using SMIv2";
+      }
+      enum "iso88022llc" {
+        value 41;
+      }
+      enum "localTalk" {
+        value 42;
+      }
+      enum "smdsDxi" {
+        value 43;
+      }
+      enum "frameRelayService" {
+        value 44;
+        description
+          "FRNETSERV-MIB";
+        reference
+          "RFC 2954 - Definitions of Managed Objects for Frame
+                      Relay Service";
+      }
+      enum "v35" {
+        value 45;
+      }
+      enum "hssi" {
+        value 46;
+      }
+      enum "hippi" {
+        value 47;
+      }
+      enum "modem" {
+        value 48;
+        description
+          "Generic modem";
+      }
+      enum "aal5" {
+        value 49;
+        description
+          "AAL5 over ATM";
+      }
+      enum "sonetPath" {
+        value 50;
+      }
+      enum "sonetVT" {
+        value 51;
+      }
+      enum "smdsIcip" {
+        value 52;
+        description
+          "SMDS InterCarrier Interface";
+      }
+      enum "propVirtual" {
+        value 53;
+        description
+          "proprietary virtual/internal";
+        reference
+          "RFC 2863 - The Interfaces Group MIB";
+      }
+      enum "propMultiplexor" {
+        value 54;
+        description
+          "proprietary multiplexing";
+        reference
+          "RFC 2863 - The Interfaces Group MIB";
+      }
+      enum "ieee80212" {
+        value 55;
+        description
+          "100BaseVG";
+      }
+      enum "fibreChannel" {
+        value 56;
+        description
+          "Fibre Channel";
+      }
+      enum "hippiInterface" {
+        value 57;
+        description
+          "HIPPI interfaces";
+      }
+      enum "frameRelayInterconnect" {
+        value 58;
+        status obsolete;
+        description
+          "Obsolete use either
+           frameRelay(32) or frameRelayService(44).";
+      }
+      enum "aflane8023" {
+        value 59;
+        description
+          "ATM Emulated LAN for 802.3";
+      }
+      enum "aflane8025" {
+        value 60;
+        description
+          "ATM Emulated LAN for 802.5";
+      }
+      enum "cctEmul" {
+        value 61;
+        description
+         "ATM Emulated circuit";
+      }
+      enum "fastEther" {
+        value 62;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635.
+          ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "isdn" {
+        value 63;
+        description
+          "ISDN and X.25";
+        reference
+          "RFC 1356 - Multiprotocol Interconnect on X.25 and ISDN
+                      in the Packet Mode";
+      }
+      enum "v11" {
+        value 64;
+        description
+         "CCITT V.11/X.21";
+      }
+      enum "v36" {
+        value 65;
+        description
+          "CCITT V.36";
+      }
+      enum "g703at64k" {
+        value 66;
+        description
+          "CCITT G703 at 64Kbps";
+      }
+      enum "g703at2mb" {
+        value 67;
+        status obsolete;
+        description
+          "Obsolete see DS1-MIB";
+      }
+      enum "qllc" {
+        value 68;
+        description
+          "SNA QLLC";
+      }
+      enum "fastEtherFX" {
+        value 69;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635
+          ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "channel" {
+        value 70;
+        description
+          "channel";
+      }
+      enum "ieee80211" {
+        value 71;
+        description
+          "radio spread spectrum";
+      }
+      enum "ibm370parChan" {
+        value 72;
+        description
+          "IBM System 360/370 OEMI Channel";
+      }
+      enum "escon" {
+        value 73;
+        description
+          "IBM Enterprise Systems Connection";
+      }
+      enum "dlsw" {
+        value 74;
+        description
+          "Data Link Switching";
+      }
+      enum "isdns" {
+        value 75;
+        description
+          "ISDN S/T interface";
+      }
+      enum "isdnu" {
+        value 76;
+        description
+          "ISDN U interface";
+      }
+      enum "lapd" {
+        value 77;
+        description
+          "Link Access Protocol D";
+      }
+      enum "ipSwitch" {
+        value 78;
+        description
+          "IP Switching Objects";
+      }
+      enum "rsrb" {
+        value 79;
+        description
+          "Remote Source Route Bridging";
+      }
+      enum "atmLogical" {
+        value 80;
+        description
+          "ATM Logical Port";
+        reference
+          "RFC 3606 - Definitions of Supplemental Managed Objects
+                      for ATM Interface";
+      }
+      enum "ds0" {
+        value 81;
+        description
+          "Digital Signal Level 0";
+        reference
+          "RFC 2494 - Definitions of Managed Objects for the DS0
+                      and DS0 Bundle Interface Type";
+      }
+      enum "ds0Bundle" {
+        value 82;
+        description
+          "group of ds0s on the same ds1";
+        reference
+          "RFC 2494 - Definitions of Managed Objects for the DS0
+                      and DS0 Bundle Interface Type";
+      }
+      enum "bsc" {
+        value 83;
+        description
+          "Bisynchronous Protocol";
+      }
+      enum "async" {
+        value 84;
+        description
+          "Asynchronous Protocol";
+      }
+      enum "cnr" {
+        value 85;
+        description
+          "Combat Net Radio";
+      }
+      enum "iso88025Dtr" {
+        value 86;
+        description
+          "ISO 802.5r DTR";
+      }
+      enum "eplrs" {
+        value 87;
+        description
+          "Ext Pos Loc Report Sys";
+      }
+      enum "arap" {
+        value 88;
+        description
+          "Appletalk Remote Access Protocol";
+      }
+      enum "propCnls" {
+        value 89;
+        description
+          "Proprietary Connectionless Protocol";
+      }
+      enum "hostPad" {
+        value 90;
+        description
+          "CCITT-ITU X.29 PAD Protocol";
+      }
+      enum "termPad" {
+        value 91;
+        description
+          "CCITT-ITU X.3 PAD Facility";
+      }
+      enum "frameRelayMPI" {
+        value 92;
+        description
+          "Multiproto Interconnect over FR";
+      }
+      enum "x213" {
+        value 93;
+        description
+          "CCITT-ITU X213";
+      }
+      enum "adsl" {
+        value 94;
+        description
+          "Asymmetric Digital Subscriber Loop";
+      }
+      enum "radsl" {
+        value 95;
+        description
+          "Rate-Adapt. Digital Subscriber Loop";
+      }
+      enum "sdsl" {
+        value 96;
+        description
+          "Symmetric Digital Subscriber Loop";
+      }
+      enum "vdsl" {
+        value 97;
+        description
+          "Very H-Speed Digital Subscrib. Loop";
+      }
+      enum "iso88025CRFPInt" {
+        value 98;
+        description
+          "ISO 802.5 CRFP";
+      }
+      enum "myrinet" {
+        value 99;
+        description
+          "Myricom Myrinet";
+      }
+      enum "voiceEM" {
+        value 100;
+        description
+          "voice recEive and transMit";
+      }
+      enum "voiceFXO" {
+        value 101;
+        description
+          "voice Foreign Exchange Office";
+      }
+      enum "voiceFXS" {
+        value 102;
+        description
+          "voice Foreign Exchange Station";
+      }
+      enum "voiceEncap" {
+        value 103;
+        description
+          "voice encapsulation";
+      }
+      enum "voiceOverIp" {
+        value 104;
+        description
+          "voice over IP encapsulation";
+      }
+      enum "atmDxi" {
+        value 105;
+        description
+          "ATM DXI";
+      }
+      enum "atmFuni" {
+        value 106;
+        description
+          "ATM FUNI";
+      }
+      enum "atmIma" {
+        value 107;
+        description
+          "ATM IMA";
+      }
+      enum "pppMultilinkBundle" {
+        value 108;
+        description
+          "PPP Multilink Bundle";
+      }
+      enum "ipOverCdlc" {
+        value 109;
+        description
+          "IBM ipOverCdlc";
+      }
+      enum "ipOverClaw" {
+        value 110;
+        description
+          "IBM Common Link Access to Workstn";
+      }
+      enum "stackToStack" {
+        value 111;
+        description
+          "IBM stackToStack";
+      }
+      enum "virtualIpAddress" {
+        value 112;
+        description
+          "IBM VIPA";
+      }
+      enum "mpc" {
+        value 113;
+        description
+          "IBM multi-protocol channel support";
+      }
+      enum "ipOverAtm" {
+        value 114;
+        description
+          "IBM ipOverAtm";
+        reference
+          "RFC 2320 - Definitions of Managed Objects for Classical IP
+                      and ARP Over ATM Using SMIv2 (IPOA-MIB)";
+      }
+      enum "iso88025Fiber" {
+        value 115;
+        description
+          "ISO 802.5j Fiber Token Ring";
+      }
+      enum "tdlc" {
+        value 116;
+        description
+          "IBM twinaxial data link control";
+      }
+      enum "gigabitEthernet" {
+        value 117;
+        status deprecated;
+        description
+          "Obsoleted via RFC3635
+           ethernetCsmacd(6) should be used instead";
+        reference
+          "RFC 3635 - Definitions of Managed Objects for the
+                      Ethernet-like Interface Types.";
+      }
+      enum "hdlc" {
+        value 118;
+        description
+          "HDLC";
+      }
+      enum "lapf" {
+        value 119;
+        description
+          "LAP F";
+      }
+      enum "v37" {
+        value 120;
+        description
+          "V.37";
+      }
+      enum "x25mlp" {
+        value 121;
+        description
+          "Multi-Link Protocol";
+      }
+      enum "x25huntGroup" {
+        value 122;
+        description
+          "X25 Hunt Group";
+      }
+      enum "transpHdlc" {
+        value 123;
+        description
+          "Transp HDLC";
+      }
+      enum "interleave" {
+        value 124;
+        description
+          "Interleave channel";
+      }
+      enum "fast" {
+        value 125;
+        description
+          "Fast channel";
+      }
+      enum "ip" {
+        value 126;
+        description
+          "IP (for APPN HPR in IP networks)";
+      }
+      enum "docsCableMaclayer" {
+        value 127;
+        description
+          "CATV Mac Layer";
+      }
+      enum "docsCableDownstream" {
+        value 128;
+        description
+          "CATV Downstream interface";
+      }
+      enum "docsCableUpstream" {
+        value 129;
+        description
+          "CATV Upstream interface";
+      }
+      enum "a12MppSwitch" {
+        value 130;
+        description
+          "Avalon Parallel Processor";
+      }
+      enum "tunnel" {
+        value 131;
+        description
+          "Encapsulation interface";
+      }
+      enum "coffee" {
+        value 132;
+        description
+          "coffee pot";
+        reference
+          "RFC 2325 - Coffee MIB";
+      }
+      enum "ces" {
+        value 133;
+        description
+          "Circuit Emulation Service";
+      }
+      enum "atmSubInterface" {
+        value 134;
+        description
+          "ATM Sub Interface";
+      }
+      enum "l2vlan" {
+        value 135;
+        description
+          "Layer 2 Virtual LAN using 802.1Q";
+      }
+      enum "l3ipvlan" {
+        value 136;
+        description
+          "Layer 3 Virtual LAN using IP";
+      }
+      enum "l3ipxvlan" {
+        value 137;
+        description
+          "Layer 3 Virtual LAN using IPX";
+      }
+      enum "digitalPowerline" {
+        value 138;
+        description
+          "IP over Power Lines";
+      }
+      enum "mediaMailOverIp" {
+        value 139;
+        description
+          "Multimedia Mail over IP";
+      }
+      enum "dtm" {
+        value 140;
+        description
+          "Dynamic syncronous Transfer Mode";
+      }
+      enum "dcn" {
+        value 141;
+        description
+          "Data Communications Network";
+      }
+      enum "ipForward" {
+        value 142;
+        description
+          "IP Forwarding Interface";
+      }
+      enum "msdsl" {
+        value 143;
+        description
+          "Multi-rate Symmetric DSL";
+      }
+      enum "ieee1394" {
+        value 144;
+        description
+          "IEEE1394 High Performance Serial Bus";
+      }
+      enum "if-gsn" {
+        value 145;
+        description
+          "HIPPI-6400";
+      }
+      enum "dvbRccMacLayer" {
+        value 146;
+        description
+          "DVB-RCC MAC Layer";
+      }
+      enum "dvbRccDownstream" {
+        value 147;
+        description
+          "DVB-RCC Downstream Channel";
+      }
+      enum "dvbRccUpstream" {
+        value 148;
+        description
+          "DVB-RCC Upstream Channel";
+      }
+      enum "atmVirtual" {
+        value 149;
+        description
+          "ATM Virtual Interface";
+      }
+      enum "mplsTunnel" {
+        value 150;
+        description
+          "MPLS Tunnel Virtual Interface";
+      }
+      enum "srp" {
+        value 151;
+        description
+          "Spatial Reuse Protocol       ";
+      }
+      enum "voiceOverAtm" {
+        value 152;
+        description
+          "Voice Over ATM";
+      }
+      enum "voiceOverFrameRelay" {
+        value 153;
+        description
+          "Voice Over Frame Relay";
+      }
+      enum "idsl" {
+        value 154;
+        description
+          "Digital Subscriber Loop over ISDN";
+      }
+      enum "compositeLink" {
+        value 155;
+        description
+          "Avici Composite Link Interface";
+      }
+      enum "ss7SigLink" {
+        value 156;
+        description
+          "SS7 Signaling Link";
+      }
+      enum "propWirelessP2P" {
+        value 157;
+        description
+          "Prop. P2P wireless interface";
+      }
+      enum "frForward" {
+        value 158;
+        description
+          "Frame Forward Interface";
+      }
+      enum "rfc1483" {
+        value 159;
+        description
+          "Multiprotocol over ATM AAL5";
+        reference
+          "RFC 1483 - Multiprotocol Encapsulation over ATM
+                      Adaptation Layer 5";
+      }
+      enum "usb" {
+        value 160;
+        description
+          "USB Interface";
+      }
+      enum "ieee8023adLag" {
+        value 161;
+        description
+          "IEEE 802.3ad Link Aggregate";
+      }
+      enum "bgppolicyaccounting" {
+        value 162;
+        description
+          "BGP Policy Accounting";
+      }
+      enum "frf16MfrBundle" {
+        value 163;
+        description
+          "FRF .16 Multilink Frame Relay";
+      }
+      enum "h323Gatekeeper" {
+        value 164;
+        description
+          "H323 Gatekeeper";
+      }
+      enum "h323Proxy" {
+        value 165;
+        description
+          "H323 Voice and Video Proxy";
+      }
+      enum "mpls" {
+        value 166;
+        description
+          "MPLS";
+      }
+      enum "mfSigLink" {
+        value 167;
+        description
+          "Multi-frequency signaling link";
+      }
+      enum "hdsl2" {
+        value 168;
+        description
+          "High Bit-Rate DSL - 2nd generation";
+      }
+      enum "shdsl" {
+        value 169;
+        description
+          "Multirate HDSL2";
+      }
+      enum "ds1FDL" {
+        value 170;
+        description
+          "Facility Data Link 4Kbps on a DS1";
+      }
+      enum "pos" {
+        value 171;
+        description
+          "Packet over SONET/SDH Interface";
+      }
+      enum "dvbAsiIn" {
+        value 172;
+        description
+          "DVB-ASI Input";
+      }
+      enum "dvbAsiOut" {
+        value 173;
+        description
+          "DVB-ASI Output";
+      }
+      enum "plc" {
+        value 174;
+        description
+          "Power Line Communtications";
+      }
+      enum "nfas" {
+        value 175;
+        description
+          "Non Facility Associated Signaling";
+      }
+      enum "tr008" {
+        value 176;
+        description
+          "TR008";
+      }
+      enum "gr303RDT" {
+        value 177;
+        description
+          "Remote Digital Terminal";
+      }
+      enum "gr303IDT" {
+        value 178;
+        description
+          "Integrated Digital Terminal";
+      }
+      enum "isup" {
+        value 179;
+        description
+          "ISUP";
+      }
+      enum "propDocsWirelessMaclayer" {
+        value 180;
+        description
+          "Cisco proprietary Maclayer";
+      }
+      enum "propDocsWirelessDownstream" {
+        value 181;
+        description
+          "Cisco proprietary Downstream";
+      }
+      enum "propDocsWirelessUpstream" {
+        value 182;
+        description
+          "Cisco proprietary Upstream";
+      }
+      enum "hiperlan2" {
+        value 183;
+        description
+          "HIPERLAN Type 2 Radio Interface";
+      }
+      enum "propBWAp2Mp" {
+        value 184;
+        description
+          "PropBroadbandWirelessAccesspt2multipt use of this value
+           for IEEE 802.16 WMAN interfaces as per IEEE Std 802.16f
+           is deprecated and ieee80216WMAN(237) should be used
+           instead.";
+      }
+      enum "sonetOverheadChannel" {
+        value 185;
+        description
+          "SONET Overhead Channel";
+      }
+      enum "digitalWrapperOverheadChannel" {
+        value 186;
+        description
+          "Digital Wrapper";
+      }
+      enum "aal2" {
+        value 187;
+        description
+          "ATM adaptation layer 2";
+      }
+      enum "radioMAC" {
+        value 188;
+        description
+          "MAC layer over radio links";
+      }
+      enum "atmRadio" {
+        value 189;
+        description
+          "ATM over radio links";
+      }
+      enum "imt" {
+        value 190;
+        description
+          "Inter Machine Trunks";
+      }
+      enum "mvl" {
+        value 191;
+        description
+          "Multiple Virtual Lines DSL";
+      }
+      enum "reachDSL" {
+        value 192;
+        description
+          "Long Reach DSL";
+      }
+      enum "frDlciEndPt" {
+        value 193;
+        description
+          "Frame Relay DLCI End Point";
+      }
+      enum "atmVciEndPt" {
+        value 194;
+        description
+          "ATM VCI End Point";
+      }
+      enum "opticalChannel" {
+        value 195;
+        description
+          "Optical Channel";
+      }
+      enum "opticalTransport" {
+        value 196;
+        description
+          "Optical Transport";
+      }
+      enum "propAtm" {
+        value 197;
+        description
+          "Proprietary ATM";
+      }
+      enum "voiceOverCable" {
+        value 198;
+        description
+          "Voice Over Cable Interface";
+      }
+      enum "infiniband" {
+        value 199;
+        description
+          "Infiniband";
+      }
+      enum "teLink" {
+        value 200;
+        description
+          "TE Link";
+      }
+      enum "q2931" {
+        value 201;
+        description
+          "Q.2931";
+      }
+      enum "virtualTg" {
+        value 202;
+        description
+          "Virtual Trunk Group";
+      }
+      enum "sipTg" {
+        value 203;
+        description
+          "SIP Trunk Group";
+      }
+      enum "sipSig" {
+        value 204;
+        description
+          "SIP Signaling";
+      }
+      enum "docsCableUpstreamChannel" {
+        value 205;
+        description
+          "CATV Upstream Channel";
+      }
+      enum "econet" {
+        value 206;
+        description
+          "Acorn Econet";
+      }
+      enum "pon155" {
+        value 207;
+        description
+          "FSAN 155Mb Symetrical PON interface";
+      }
+      enum "pon622" {
+        value 208;
+        description
+          "FSAN622Mb Symetrical PON interface";
+      }
+      enum "bridge" {
+        value 209;
+        description
+          "Transparent bridge interface";
+      }
+      enum "linegroup" {
+        value 210;
+        description
+          "Interface common to multiple lines";
+      }
+      enum "voiceEMFGD" {
+        value 211;
+        description
+          "voice E&M Feature Group D";
+      }
+      enum "voiceFGDEANA" {
+        value 212;
+        description
+          "voice FGD Exchange Access North American";
+      }
+      enum "voiceDID" {
+        value 213;
+        description
+          "voice Direct Inward Dialing";
+      }
+      enum "mpegTransport" {
+        value 214;
+        description
+          "MPEG transport interface";
+      }
+      enum "sixToFour" {
+        value 215;
+        status deprecated;
+        description
+          "6to4 interface (DEPRECATED)";
+        reference
+          "RFC 4087 - IP Tunnel MIB";
+      }
+      enum "gtp" {
+        value 216;
+        description
+          "GTP (GPRS Tunneling Protocol)";
+      }
+      enum "pdnEtherLoop1" {
+        value 217;
+        description
+          "Paradyne EtherLoop 1";
+      }
+      enum "pdnEtherLoop2" {
+        value 218;
+        description
+          "Paradyne EtherLoop 2";
+      }
+      enum "opticalChannelGroup" {
+        value 219;
+        description
+          "Optical Channel Group";
+      }
+      enum "homepna" {
+        value 220;
+        description
+          "HomePNA ITU-T G.989";
+      }
+      enum "gfp" {
+        value 221;
+        description
+          "Generic Framing Procedure (GFP)";
+      }
+      enum "ciscoISLvlan" {
+        value 222;
+        description
+          "Layer 2 Virtual LAN using Cisco ISL";
+      }
+      enum "actelisMetaLOOP" {
+        value 223;
+        description
+          "Acteleis proprietary MetaLOOP High Speed Link";
+      }
+      enum "fcipLink" {
+        value 224;
+        description
+          "FCIP Link";
+      }
+      enum "rpr" {
+        value 225;
+        description
+          "Resilient Packet Ring Interface Type";
+      }
+      enum "qam" {
+        value 226;
+        description
+          "RF Qam Interface";
+      }
+      enum "lmp" {
+        value 227;
+        description
+          "Link Management Protocol";
+        reference
+          "RFC 4327 - Link Management Protocol (LMP) Management
+                      Information Base (MIB)";
+      }
+      enum "cblVectaStar" {
+        value 228;
+        description
+          "Cambridge Broadband Networks Limited VectaStar";
+      }
+      enum "docsCableMCmtsDownstream" {
+        value 229;
+        description
+          "CATV Modular CMTS Downstream Interface";
+      }
+      enum "adsl2" {
+        value 230;
+        status deprecated;
+        description
+          "Asymmetric Digital Subscriber Loop Version 2
+           (DEPRECATED/OBSOLETED - please use adsl2plus(238)
+           instead)";
+        reference
+          "RFC 4706 - Definitions of Managed Objects for Asymmetric
+                      Digital Subscriber Line 2 (ADSL2)";
+      }
+      enum "macSecControlledIF" {
+        value 231;
+        description
+          "MACSecControlled";
+      }
+      enum "macSecUncontrolledIF" {
+        value 232;
+        description
+          "MACSecUncontrolled";
+      }
+      enum "aviciOpticalEther" {
+        value 233;
+        description
+         "Avici Optical Ethernet Aggregate";
+      }
+      enum "atmbond" {
+        value 234;
+        description
+          "atmbond";
+      }
+      enum "voiceFGDOS" {
+        value 235;
+        description
+          "voice FGD Operator Services";
+      }
+      enum "mocaVersion1" {
+        value 236;
+        description
+          "MultiMedia over Coax Alliance (MoCA) Interface
+           as documented in information provided privately to IANA";
+      }
+      enum "ieee80216WMAN" {
+        value 237;
+        description
+          "IEEE 802.16 WMAN interface";
+      }
+      enum "adsl2plus" {
+        value 238;
+        description
+          "Asymmetric Digital Subscriber Loop Version 2,
+           Version 2 Plus and all variants";
+      }
+      enum "dvbRcsMacLayer" {
+        value 239;
+        description
+          "DVB-RCS MAC Layer";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "dvbTdm" {
+        value 240;
+        description
+          "DVB Satellite TDM";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "dvbRcsTdma" {
+        value 241;
+        description
+          "DVB-RCS TDMA";
+        reference
+          "RFC 5728 - The SatLabs Group DVB-RCS MIB";
+      }
+      enum "x86Laps" {
+        value 242;
+        description
+          "LAPS based on ITU-T X.86/Y.1323";
+      }
+      enum "wwanPP" {
+        value 243;
+        description
+          "3GPP WWAN";
+      }
+      enum "wwanPP2" {
+        value 244;
+        description
+          "3GPP2 WWAN";
+      }
+      enum "voiceEBS" {
+        value 245;
+        description
+          "voice P-phone EBS physical interface";
+      }
+      enum "ifPwType" {
+        value 246;
+        description
+          "Pseudowire interface type";
+        reference
+          "RFC 5601 - Pseudowire (PW) Management Information Base";
+      }
+      enum "ilan" {
+        value 247;
+        description
+          "Internal LAN on a bridge per IEEE 802.1ap";
+      }
+      enum "pip" {
+        value 248;
+        description
+          "Provider Instance Port on a bridge per IEEE 802.1ah PBB";
+      }
+      enum "aluELP" {
+        value 249;
+        description
+          "Alcatel-Lucent Ethernet Link Protection";
+      }
+      enum "gpon" {
+        value 250;
+        description
+          "Gigabit-capable passive optical networks (G-PON) as per
+           ITU-T G.948";
+      }
+      enum "vdsl2" {
+        value 251;
+        description
+          "Very high speed digital subscriber line Version 2
+           (as per ITU-T Recommendation G.993.2)";
+        reference
+          "RFC 5650 - Definitions of Managed Objects for Very High
+                      Speed Digital Subscriber Line 2 (VDSL2)";
+      }
+      enum "capwapDot11Profile" {
+        value 252;
+        description
+          "WLAN Profile Interface";
+        reference
+          "RFC 5834 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Binding MIB for
+                      IEEE 802.11";
+      }
+      enum "capwapDot11Bss" {
+        value 253;
+        description
+          "WLAN BSS Interface";
+        reference
+          "RFC 5834 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Binding MIB for
+                      IEEE 802.11";
+      }
+      enum "capwapWtpVirtualRadio" {
+        value 254;
+        description
+          "WTP Virtual Radio Interface";
+        reference
+          "RFC 5833 - Control and Provisioning of Wireless Access
+                      Points (CAPWAP) Protocol Base MIB";
+      }
+      enum "bits" {
+        value 255;
+        description
+          "bitsport";
+      }
+      enum "docsCableUpstreamRfPort" {
+        value 256;
+        description
+          "DOCSIS CATV Upstream RF Port";
+      }
+      enum "cableDownstreamRfPort" {
+        value 257;
+        description
+          "CATV downstream RF port";
+      }
+      enum "vmwareVirtualNic" {
+        value 258;
+        description
+          "VMware Virtual Network Interface";
+      }
+      enum "ieee802154" {
+        value 259;
+        description
+          "IEEE 802.15.4 WPAN interface";
+        reference
+          "IEEE 802.15.4-2006";
+      }
+      enum "otnOdu" {
+        value 260;
+        description
+          "OTN Optical Data Unit";
+      }
+      enum "otnOtu" {
+        value 261;
+        description
+          "OTN Optical channel Transport Unit";
+      }
+      enum "ifVfiType" {
+        value 262;
+        description
+          "VPLS Forwarding Instance Interface Type";
+      }
+      enum "g9981" {
+        value 263;
+        description
+          "G.998.1 bonded interface";
+      }
+      enum "g9982" {
+        value 264;
+        description
+          "G.998.2 bonded interface";
+      }
+      enum "g9983" {
+        value 265;
+        description
+          "G.998.3 bonded interface";
+      }
+      enum "aluEpon" {
+        value 266;
+        description
+          "Ethernet Passive Optical Networks (E-PON)";
+      }
+      enum "aluEponOnu" {
+        value 267;
+        description
+          "EPON Optical Network Unit";
+      }
+      enum "aluEponPhysicalUni" {
+        value 268;
+        description
+          "EPON physical User to Network interface";
+      }
+      enum "aluEponLogicalLink" {
+        value 269;
+        description
+          "The emulation of a point-to-point link over the EPON
+           layer";
+      }
+      enum "aluGponOnu" {
+        value 270;
+        description
+          "GPON Optical Network Unit";
+        reference
+          "ITU-T G.984.2";
+      }
+      enum "aluGponPhysicalUni" {
+        value 271;
+        description
+          "GPON physical User to Network interface";
+        reference
+          "ITU-T G.984.2";
+      }
+      enum "vmwareNicTeam" {
+        value 272;
+        description
+          "VMware NIC Team";
+      }
+    }
+    description
+      "This data type is used as the syntax of the 'type'
+       leaf in the 'interface' list in the YANG module
+       ietf-interface.
+
+       The definition of this typedef with the
+       addition of newly assigned values is published
+       periodically by the IANA, in either the Assigned
+       Numbers RFC, or some derivative of it specific to
+       Internet Network Management number assignments.  (The
+       latest arrangements can be obtained by contacting the
+       IANA.)
+
+       Requests for new values should be made to IANA via
+       email (iana&iana.org).";
+    reference
+      "ifType definitions registry.
+       <http://www.iana.org/assignments/smi-numbers>";
+  }
+}
diff --git a/yang-model-parser-impl/src/test/resources/types/iana-timezones@2012-07-09.yang b/yang-model-parser-impl/src/test/resources/types/iana-timezones@2012-07-09.yang
new file mode 100644 (file)
index 0000000..7fc1577
--- /dev/null
@@ -0,0 +1,1701 @@
+module iana-timezones {
+  namespace "urn:ietf:params:xml:ns:yang:iana-timezones";
+  prefix ianatz;
+
+  organization "IANA";
+  contact
+    "        Internet Assigned Numbers Authority
+
+     Postal: ICANN
+             4676 Admiralty Way, Suite 330
+             Marina del Rey, CA 90292
+
+     Tel:    +1 310 823 9358
+     E-Mail: iana&iana.org";
+  description
+    "This YANG module defines the iana-timezone typedef, which
+     contains YANG definitions for IANA-registered timezones.
+
+     This YANG module is maintained by IANA, and reflects the
+     IANA Time Zone Database.
+     (http://www.iana.org/time-zones)
+
+     The latest revision of this YANG module can be obtained from
+     the IANA web site.
+
+     Copyright (c) 2011 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or
+     without modification, is permitted pursuant to, and subject
+     to the license terms contained in, the Simplified BSD License
+     set forth in Section 4.c of the IETF Trust's Legal Provisions
+     Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC XXXX; see
+     the RFC itself for full legal notices.";
+
+  revision 2012-07-09 {
+    description
+      "Initial revision. Using IANA Time Zone Data v. 2012c
+       (Released 2012-03-27)";
+    reference "RFC XXXX: TITLE";
+  }
+  typedef iana-timezone {
+    description
+      "A timezone location as defined by the IANA timezone
+       database (http://www.iana.org/time-zones)";
+    type enumeration {
+      enum "Europe/Andorra" {
+        value 0;
+      }
+      enum "Asia/Dubai" {
+        value 1;
+      }
+      enum "Asia/Kabul" {
+        value 2;
+      }
+      enum "America/Antigua" {
+        value 3;
+      }
+      enum "America/Anguilla" {
+        value 4;
+      }
+      enum "Europe/Tirane" {
+        value 5;
+      }
+      enum "Asia/Yerevan" {
+        value 6;
+      }
+      enum "Africa/Luanda" {
+        value 7;
+      }
+      enum "Antarctica/McMurdo" {
+        value 8;
+        description
+          "McMurdo Station, Ross Island";
+      }
+      enum "Antarctica/South_Pole" {
+        value 9;
+        description
+          "Amundsen-Scott Station, South Pole";
+      }
+      enum "Antarctica/Rothera" {
+        value 10;
+        description
+          "Rothera Station, Adelaide Island";
+      }
+      enum "Antarctica/Palmer" {
+        value 11;
+        description
+          "Palmer Station, Anvers Island";
+      }
+      enum "Antarctica/Mawson" {
+        value 12;
+        description
+          "Mawson Station, Holme Bay";
+      }
+      enum "Antarctica/Davis" {
+        value 13;
+        description
+          "Davis Station, Vestfold Hills";
+      }
+      enum "Antarctica/Casey" {
+        value 14;
+        description
+          "Casey Station, Bailey Peninsula";
+      }
+      enum "Antarctica/Vostok" {
+        value 15;
+        description
+          "Vostok Station, Lake Vostok";
+      }
+      enum "Antarctica/DumontDUrville" {
+        value 16;
+        description
+          "Dumont-d'Urville Station, Terre Adelie";
+      }
+      enum "Antarctica/Syowa" {
+        value 17;
+        description
+          "Syowa Station, E Ongul I";
+      }
+      enum "Antarctica/Macquarie" {
+        value 18;
+        description
+          "Macquarie Island Station, Macquarie Island";
+      }
+      enum "America/Argentina/Buenos_Aires" {
+        value 19;
+        description
+          "Buenos Aires (BA, CF)";
+      }
+      enum "America/Argentina/Cordoba" {
+        value 20;
+        description
+          "most locations (CB, CC, CN, ER, FM, MN, SE, SF)";
+      }
+      enum "America/Argentina/Salta" {
+        value 21;
+        description
+          "(SA, LP, NQ, RN)";
+      }
+      enum "America/Argentina/Jujuy" {
+        value 22;
+        description
+          "Jujuy (JY)";
+      }
+      enum "America/Argentina/Tucuman" {
+        value 23;
+        description
+          "Tucuman (TM)";
+      }
+      enum "America/Argentina/Catamarca" {
+        value 24;
+        description
+          "Catamarca (CT), Chubut (CH)";
+      }
+      enum "America/Argentina/La_Rioja" {
+        value 25;
+        description
+          "La Rioja (LR)";
+      }
+      enum "America/Argentina/San_Juan" {
+        value 26;
+        description
+          "San Juan (SJ)";
+      }
+      enum "America/Argentina/Mendoza" {
+        value 27;
+        description
+          "Mendoza (MZ)";
+      }
+      enum "America/Argentina/San_Luis" {
+        value 28;
+        description
+          "San Luis (SL)";
+      }
+      enum "America/Argentina/Rio_Gallegos" {
+        value 29;
+        description
+          "Santa Cruz (SC)";
+      }
+      enum "America/Argentina/Ushuaia" {
+        value 30;
+        description
+          "Tierra del Fuego (TF)";
+      }
+      enum "Pacific/Pago_Pago" {
+        value 31;
+      }
+      enum "Europe/Vienna" {
+        value 32;
+      }
+      enum "Australia/Lord_Howe" {
+        value 33;
+        description
+          "Lord Howe Island";
+      }
+      enum "Australia/Hobart" {
+        value 34;
+        description
+          "Tasmania - most locations";
+      }
+      enum "Australia/Currie" {
+        value 35;
+        description
+          "Tasmania - King Island";
+      }
+      enum "Australia/Melbourne" {
+        value 36;
+        description
+          "Victoria";
+      }
+      enum "Australia/Sydney" {
+        value 37;
+        description
+          "New South Wales - most locations";
+      }
+      enum "Australia/Broken_Hill" {
+        value 38;
+        description
+          "New South Wales - Yancowinna";
+      }
+      enum "Australia/Brisbane" {
+        value 39;
+        description
+          "Queensland - most locations";
+      }
+      enum "Australia/Lindeman" {
+        value 40;
+        description
+          "Queensland - Holiday Islands";
+      }
+      enum "Australia/Adelaide" {
+        value 41;
+        description
+          "South Australia";
+      }
+      enum "Australia/Darwin" {
+        value 42;
+        description
+          "Northern Territory";
+      }
+      enum "Australia/Perth" {
+        value 43;
+        description
+          "Western Australia - most locations";
+      }
+      enum "Australia/Eucla" {
+        value 44;
+        description
+          "Western Australia - Eucla area";
+      }
+      enum "America/Aruba" {
+        value 45;
+      }
+      enum "Europe/Mariehamn" {
+        value 46;
+      }
+      enum "Asia/Baku" {
+        value 47;
+      }
+      enum "Europe/Sarajevo" {
+        value 48;
+      }
+      enum "America/Barbados" {
+        value 49;
+      }
+      enum "Asia/Dhaka" {
+        value 50;
+      }
+      enum "Europe/Brussels" {
+        value 51;
+      }
+      enum "Africa/Ouagadougou" {
+        value 52;
+      }
+      enum "Europe/Sofia" {
+        value 53;
+      }
+      enum "Asia/Bahrain" {
+        value 54;
+      }
+      enum "Africa/Bujumbura" {
+        value 55;
+      }
+      enum "Africa/Porto-Novo" {
+        value 56;
+      }
+      enum "America/St_Barthelemy" {
+        value 57;
+      }
+      enum "Atlantic/Bermuda" {
+        value 58;
+      }
+      enum "Asia/Brunei" {
+        value 59;
+      }
+      enum "America/La_Paz" {
+        value 60;
+      }
+      enum "America/Kralendijk" {
+        value 61;
+      }
+      enum "America/Noronha" {
+        value 62;
+        description
+          "Atlantic islands";
+      }
+      enum "America/Belem" {
+        value 63;
+        description
+          "Amapa, E Para";
+      }
+      enum "America/Fortaleza" {
+        value 64;
+        description
+          "NE Brazil (MA, PI, CE, RN, PB)";
+      }
+      enum "America/Recife" {
+        value 65;
+        description
+          "Pernambuco";
+      }
+      enum "America/Araguaina" {
+        value 66;
+        description
+          "Tocantins";
+      }
+      enum "America/Maceio" {
+        value 67;
+        description
+          "Alagoas, Sergipe";
+      }
+      enum "America/Bahia" {
+        value 68;
+        description
+          "Bahia";
+      }
+      enum "America/Sao_Paulo" {
+        value 69;
+        description
+          "S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS)";
+      }
+      enum "America/Campo_Grande" {
+        value 70;
+        description
+          "Mato Grosso do Sul";
+      }
+      enum "America/Cuiaba" {
+        value 71;
+        description
+          "Mato Grosso";
+      }
+      enum "America/Santarem" {
+        value 72;
+        description
+          "W Para";
+      }
+      enum "America/Porto_Velho" {
+        value 73;
+        description
+          "Rondonia";
+      }
+      enum "America/Boa_Vista" {
+        value 74;
+        description
+          "Roraima";
+      }
+      enum "America/Manaus" {
+        value 75;
+        description
+          "E Amazonas";
+      }
+      enum "America/Eirunepe" {
+        value 76;
+        description
+          "W Amazonas";
+      }
+      enum "America/Rio_Branco" {
+        value 77;
+        description
+          "Acre";
+      }
+      enum "America/Nassau" {
+        value 78;
+      }
+      enum "Asia/Thimphu" {
+        value 79;
+      }
+      enum "Africa/Gaborone" {
+        value 80;
+      }
+      enum "Europe/Minsk" {
+        value 81;
+      }
+      enum "America/Belize" {
+        value 82;
+      }
+      enum "America/St_Johns" {
+        value 83;
+        description
+          "Newfoundland Time, including SE Labrador";
+      }
+      enum "America/Halifax" {
+        value 84;
+        description
+          "Atlantic Time - Nova Scotia (most places), PEI";
+      }
+      enum "America/Glace_Bay" {
+        value 85;
+        description
+          "Atlantic Time - Nova Scotia - places that did not observe
+           DST 1966-1971";
+      }
+      enum "America/Moncton" {
+        value 86;
+        description
+          "Atlantic Time - New Brunswick";
+      }
+      enum "America/Goose_Bay" {
+        value 87;
+        description
+          "Atlantic Time - Labrador - most locations";
+      }
+      enum "America/Blanc-Sablon" {
+        value 88;
+        description
+          "Atlantic Standard Time - Quebec - Lower North Shore";
+      }
+      enum "America/Montreal" {
+        value 89;
+        description
+          "Eastern Time - Quebec - most locations";
+      }
+      enum "America/Toronto" {
+        value 90;
+        description
+          "Eastern Time - Ontario - most locations";
+      }
+      enum "America/Nipigon" {
+        value 91;
+        description
+          "Eastern Time - Ontario & Quebec - places that did not
+           observe DST 1967-1973";
+      }
+      enum "America/Thunder_Bay" {
+        value 92;
+        description
+          "Eastern Time - Thunder Bay, Ontario";
+      }
+      enum "America/Iqaluit" {
+        value 93;
+        description
+          "Eastern Time - east Nunavut - most locations";
+      }
+      enum "America/Pangnirtung" {
+        value 94;
+        description
+          "Eastern Time - Pangnirtung, Nunavut";
+      }
+      enum "America/Resolute" {
+        value 95;
+        description
+          "Central Standard Time - Resolute, Nunavut";
+      }
+      enum "America/Atikokan" {
+        value 96;
+        description
+          "Eastern Standard Time - Atikokan, Ontario and Southampton I,
+           Nunavut";
+      }
+      enum "America/Rankin_Inlet" {
+        value 97;
+        description
+          "Central Time - central Nunavut";
+      }
+      enum "America/Winnipeg" {
+        value 98;
+        description
+          "Central Time - Manitoba & west Ontario";
+      }
+      enum "America/Rainy_River" {
+        value 99;
+        description
+          "Central Time - Rainy River & Fort Frances, Ontario";
+      }
+      enum "America/Regina" {
+        value 100;
+        description
+          "Central Standard Time - Saskatchewan - most locations";
+      }
+      enum "America/Swift_Current" {
+        value 101;
+        description
+          "Central Standard Time - Saskatchewan - midwest";
+      }
+      enum "America/Edmonton" {
+        value 102;
+        description
+          "Mountain Time - Alberta, east British Columbia & west
+           Saskatchewan";
+      }
+      enum "America/Cambridge_Bay" {
+        value 103;
+        description
+          "Mountain Time - west Nunavut";
+      }
+      enum "America/Yellowknife" {
+        value 104;
+        description
+          "Mountain Time - central Northwest Territories";
+      }
+      enum "America/Inuvik" {
+        value 105;
+        description
+          "Mountain Time - west Northwest Territories";
+      }
+      enum "America/Creston" {
+        value 106;
+        description
+          "Mountain Standard Time - Creston, British Columbia";
+      }
+      enum "America/Dawson_Creek" {
+        value 107;
+        description
+          "Mountain Standard Time - Dawson Creek & Fort Saint John,
+           British Columbia";
+      }
+      enum "America/Vancouver" {
+        value 108;
+        description
+          "Pacific Time - west British Columbia";
+      }
+      enum "America/Whitehorse" {
+        value 109;
+        description
+          "Pacific Time - south Yukon";
+      }
+      enum "America/Dawson" {
+        value 110;
+        description
+          "Pacific Time - north Yukon";
+      }
+      enum "Indian/Cocos" {
+        value 111;
+      }
+      enum "Africa/Kinshasa" {
+        value 112;
+        description
+          "west Dem. Rep. of Congo";
+      }
+      enum "Africa/Lubumbashi" {
+        value 113;
+        description
+          "east Dem. Rep. of Congo";
+      }
+      enum "Africa/Bangui" {
+        value 114;
+      }
+      enum "Africa/Brazzaville" {
+        value 115;
+      }
+      enum "Europe/Zurich" {
+        value 116;
+      }
+      enum "Africa/Abidjan" {
+        value 117;
+      }
+      enum "Pacific/Rarotonga" {
+        value 118;
+      }
+      enum "America/Santiago" {
+        value 119;
+        description
+          "most locations";
+      }
+      enum "Pacific/Easter" {
+        value 120;
+        description
+          "Easter Island & Sala y Gomez";
+      }
+      enum "Africa/Douala" {
+        value 121;
+      }
+      enum "Asia/Shanghai" {
+        value 122;
+        description
+          "east China - Beijing, Guangdong, Shanghai, etc.";
+      }
+      enum "Asia/Harbin" {
+        value 123;
+        description
+          "Heilongjiang (except Mohe), Jilin";
+      }
+      enum "Asia/Chongqing" {
+        value 124;
+        description
+          "central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou,
+           etc.";
+      }
+      enum "Asia/Urumqi" {
+        value 125;
+        description
+          "most of Tibet & Xinjiang";
+      }
+      enum "Asia/Kashgar" {
+        value 126;
+        description
+          "west Tibet & Xinjiang";
+      }
+      enum "America/Bogota" {
+        value 127;
+      }
+      enum "America/Costa_Rica" {
+        value 128;
+      }
+      enum "America/Havana" {
+        value 129;
+      }
+      enum "Atlantic/Cape_Verde" {
+        value 130;
+      }
+      enum "America/Curacao" {
+        value 131;
+      }
+      enum "Indian/Christmas" {
+        value 132;
+      }
+      enum "Asia/Nicosia" {
+        value 133;
+      }
+      enum "Europe/Prague" {
+        value 134;
+      }
+      enum "Europe/Berlin" {
+        value 135;
+      }
+      enum "Africa/Djibouti" {
+        value 136;
+      }
+      enum "Europe/Copenhagen" {
+        value 137;
+      }
+      enum "America/Dominica" {
+        value 138;
+      }
+      enum "America/Santo_Domingo" {
+        value 139;
+      }
+      enum "Africa/Algiers" {
+        value 140;
+      }
+      enum "America/Guayaquil" {
+        value 141;
+        description
+          "mainland";
+      }
+      enum "Pacific/Galapagos" {
+        value 142;
+        description
+          "Galapagos Islands";
+      }
+      enum "Europe/Tallinn" {
+        value 143;
+      }
+      enum "Africa/Cairo" {
+        value 144;
+      }
+      enum "Africa/El_Aaiun" {
+        value 145;
+      }
+      enum "Africa/Asmara" {
+        value 146;
+      }
+      enum "Europe/Madrid" {
+        value 147;
+        description
+          "mainland";
+      }
+      enum "Africa/Ceuta" {
+        value 148;
+        description
+          "Ceuta & Melilla";
+      }
+      enum "Atlantic/Canary" {
+        value 149;
+        description
+          "Canary Islands";
+      }
+      enum "Africa/Addis_Ababa" {
+        value 150;
+      }
+      enum "Europe/Helsinki" {
+        value 151;
+      }
+      enum "Pacific/Fiji" {
+        value 152;
+      }
+      enum "Atlantic/Stanley" {
+        value 153;
+      }
+      enum "Pacific/Chuuk" {
+        value 154;
+        description
+          "Chuuk (Truk) and Yap";
+      }
+      enum "Pacific/Pohnpei" {
+        value 155;
+        description
+          "Pohnpei (Ponape)";
+      }
+      enum "Pacific/Kosrae" {
+        value 156;
+        description
+          "Kosrae";
+      }
+      enum "Atlantic/Faroe" {
+        value 157;
+      }
+      enum "Europe/Paris" {
+        value 158;
+      }
+      enum "Africa/Libreville" {
+        value 159;
+      }
+      enum "Europe/London" {
+        value 160;
+      }
+      enum "America/Grenada" {
+        value 161;
+      }
+      enum "Asia/Tbilisi" {
+        value 162;
+      }
+      enum "America/Cayenne" {
+        value 163;
+      }
+      enum "Europe/Guernsey" {
+        value 164;
+      }
+      enum "Africa/Accra" {
+        value 165;
+      }
+      enum "Europe/Gibraltar" {
+        value 166;
+      }
+      enum "America/Godthab" {
+        value 167;
+        description
+          "most locations";
+      }
+      enum "America/Danmarkshavn" {
+        value 168;
+        description
+          "east coast, north of Scoresbysund";
+      }
+      enum "America/Scoresbysund" {
+        value 169;
+        description
+          "Scoresbysund / Ittoqqortoormiit";
+      }
+      enum "America/Thule" {
+        value 170;
+        description
+          "Thule / Pituffik";
+      }
+      enum "Africa/Banjul" {
+        value 171;
+      }
+      enum "Africa/Conakry" {
+        value 172;
+      }
+      enum "America/Guadeloupe" {
+        value 173;
+      }
+      enum "Africa/Malabo" {
+        value 174;
+      }
+      enum "Europe/Athens" {
+        value 175;
+      }
+      enum "Atlantic/South_Georgia" {
+        value 176;
+      }
+      enum "America/Guatemala" {
+        value 177;
+      }
+      enum "Pacific/Guam" {
+        value 178;
+      }
+      enum "Africa/Bissau" {
+        value 179;
+      }
+      enum "America/Guyana" {
+        value 180;
+      }
+      enum "Asia/Hong_Kong" {
+        value 181;
+      }
+      enum "America/Tegucigalpa" {
+        value 182;
+      }
+      enum "Europe/Zagreb" {
+        value 183;
+      }
+      enum "America/Port-au-Prince" {
+        value 184;
+      }
+      enum "Europe/Budapest" {
+        value 185;
+      }
+      enum "Asia/Jakarta" {
+        value 186;
+        description
+          "Java & Sumatra";
+      }
+      enum "Asia/Pontianak" {
+        value 187;
+        description
+          "west & central Borneo";
+      }
+      enum "Asia/Makassar" {
+        value 188;
+        description
+          "east & south Borneo, Sulawesi (Celebes), Bali, Nusa
+           Tengarra, west Timor";
+      }
+      enum "Asia/Jayapura" {
+        value 189;
+        description
+          "west New Guinea (Irian Jaya) & Malukus (Moluccas)";
+      }
+      enum "Europe/Dublin" {
+        value 190;
+      }
+      enum "Asia/Jerusalem" {
+        value 191;
+      }
+      enum "Europe/Isle_of_Man" {
+        value 192;
+      }
+      enum "Asia/Kolkata" {
+        value 193;
+      }
+      enum "Indian/Chagos" {
+        value 194;
+      }
+      enum "Asia/Baghdad" {
+        value 195;
+      }
+      enum "Asia/Tehran" {
+        value 196;
+      }
+      enum "Atlantic/Reykjavik" {
+        value 197;
+      }
+      enum "Europe/Rome" {
+        value 198;
+      }
+      enum "Europe/Jersey" {
+        value 199;
+      }
+      enum "America/Jamaica" {
+        value 200;
+      }
+      enum "Asia/Amman" {
+        value 201;
+      }
+      enum "Asia/Tokyo" {
+        value 202;
+      }
+      enum "Africa/Nairobi" {
+        value 203;
+      }
+      enum "Asia/Bishkek" {
+        value 204;
+      }
+      enum "Asia/Phnom_Penh" {
+        value 205;
+      }
+      enum "Pacific/Tarawa" {
+        value 206;
+        description
+          "Gilbert Islands";
+      }
+      enum "Pacific/Enderbury" {
+        value 207;
+        description
+          "Phoenix Islands";
+      }
+      enum "Pacific/Kiritimati" {
+        value 208;
+        description
+          "Line Islands";
+      }
+      enum "Indian/Comoro" {
+        value 209;
+      }
+      enum "America/St_Kitts" {
+        value 210;
+      }
+      enum "Asia/Pyongyang" {
+        value 211;
+      }
+      enum "Asia/Seoul" {
+        value 212;
+      }
+      enum "Asia/Kuwait" {
+        value 213;
+      }
+      enum "America/Cayman" {
+        value 214;
+      }
+      enum "Asia/Almaty" {
+        value 215;
+        description
+          "most locations";
+      }
+      enum "Asia/Qyzylorda" {
+        value 216;
+        description
+          "Qyzylorda (Kyzylorda, Kzyl-Orda)";
+      }
+      enum "Asia/Aqtobe" {
+        value 217;
+        description
+          "Aqtobe (Aktobe)";
+      }
+      enum "Asia/Aqtau" {
+        value 218;
+        description
+          "Atyrau (Atirau, Gur'yev), Mangghystau (Mankistau)";
+      }
+      enum "Asia/Oral" {
+        value 219;
+        description
+          "West Kazakhstan";
+      }
+      enum "Asia/Vientiane" {
+        value 220;
+      }
+      enum "Asia/Beirut" {
+        value 221;
+      }
+      enum "America/St_Lucia" {
+        value 222;
+      }
+      enum "Europe/Vaduz" {
+        value 223;
+      }
+      enum "Asia/Colombo" {
+        value 224;
+      }
+      enum "Africa/Monrovia" {
+        value 225;
+      }
+      enum "Africa/Maseru" {
+        value 226;
+      }
+      enum "Europe/Vilnius" {
+        value 227;
+      }
+      enum "Europe/Luxembourg" {
+        value 228;
+      }
+      enum "Europe/Riga" {
+        value 229;
+      }
+      enum "Africa/Tripoli" {
+        value 230;
+      }
+      enum "Africa/Casablanca" {
+        value 231;
+      }
+      enum "Europe/Monaco" {
+        value 232;
+      }
+      enum "Europe/Chisinau" {
+        value 233;
+      }
+      enum "Europe/Podgorica" {
+        value 234;
+      }
+      enum "America/Marigot" {
+        value 235;
+      }
+      enum "Indian/Antananarivo" {
+        value 236;
+      }
+      enum "Pacific/Majuro" {
+        value 237;
+        description
+          "most locations";
+      }
+      enum "Pacific/Kwajalein" {
+        value 238;
+        description
+          "Kwajalein";
+      }
+      enum "Europe/Skopje" {
+        value 239;
+      }
+      enum "Africa/Bamako" {
+        value 240;
+      }
+      enum "Asia/Rangoon" {
+        value 241;
+      }
+      enum "Asia/Ulaanbaatar" {
+        value 242;
+        description
+          "most locations";
+      }
+      enum "Asia/Hovd" {
+        value 243;
+        description
+          "Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan";
+      }
+      enum "Asia/Choibalsan" {
+        value 244;
+        description
+          "Dornod, Sukhbaatar";
+      }
+      enum "Asia/Macau" {
+        value 245;
+      }
+      enum "Pacific/Saipan" {
+        value 246;
+      }
+      enum "America/Martinique" {
+        value 247;
+      }
+      enum "Africa/Nouakchott" {
+        value 248;
+      }
+      enum "America/Montserrat" {
+        value 249;
+      }
+      enum "Europe/Malta" {
+        value 250;
+      }
+      enum "Indian/Mauritius" {
+        value 251;
+      }
+      enum "Indian/Maldives" {
+        value 252;
+      }
+      enum "Africa/Blantyre" {
+        value 253;
+      }
+      enum "America/Mexico_City" {
+        value 254;
+        description
+          "Central Time - most locations";
+      }
+      enum "America/Cancun" {
+        value 255;
+        description
+          "Central Time - Quintana Roo";
+      }
+      enum "America/Merida" {
+        value 256;
+        description
+          "Central Time - Campeche, Yucatan";
+      }
+      enum "America/Monterrey" {
+        value 257;
+        description
+          "Mexican Central Time - Coahuila, Durango, Nuevo Leon,
+           Tamaulipas away from US border";
+      }
+      enum "America/Matamoros" {
+        value 258;
+        description
+          "US Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas
+           near US border";
+      }
+      enum "America/Mazatlan" {
+        value 259;
+        description
+          "Mountain Time - S Baja, Nayarit, Sinaloa";
+      }
+      enum "America/Chihuahua" {
+        value 260;
+        description
+          "Mexican Mountain Time - Chihuahua away from US border";
+      }
+      enum "America/Ojinaga" {
+        value 261;
+        description
+          "US Mountain Time - Chihuahua near US border";
+      }
+      enum "America/Hermosillo" {
+        value 262;
+        description
+          "Mountain Standard Time - Sonora";
+      }
+      enum "America/Tijuana" {
+        value 263;
+        description
+          "US Pacific Time - Baja California near US border";
+      }
+      enum "America/Santa_Isabel" {
+        value 264;
+        description
+          "Mexican Pacific Time - Baja California away from US border";
+      }
+      enum "America/Bahia_Banderas" {
+        value 265;
+        description
+          "Mexican Central Time - Bahia de Banderas";
+      }
+      enum "Asia/Kuala_Lumpur" {
+        value 266;
+        description
+          "peninsular Malaysia";
+      }
+      enum "Asia/Kuching" {
+        value 267;
+        description
+          "Sabah & Sarawak";
+      }
+      enum "Africa/Maputo" {
+        value 268;
+      }
+      enum "Africa/Windhoek" {
+        value 269;
+      }
+      enum "Pacific/Noumea" {
+        value 270;
+      }
+      enum "Africa/Niamey" {
+        value 271;
+      }
+      enum "Pacific/Norfolk" {
+        value 272;
+      }
+      enum "Africa/Lagos" {
+        value 273;
+      }
+      enum "America/Managua" {
+        value 274;
+      }
+      enum "Europe/Amsterdam" {
+        value 275;
+      }
+      enum "Europe/Oslo" {
+        value 276;
+      }
+      enum "Asia/Kathmandu" {
+        value 277;
+      }
+      enum "Pacific/Nauru" {
+        value 278;
+      }
+      enum "Pacific/Niue" {
+        value 279;
+      }
+      enum "Pacific/Auckland" {
+        value 280;
+        description
+          "most locations";
+      }
+      enum "Pacific/Chatham" {
+        value 281;
+        description
+          "Chatham Islands";
+      }
+      enum "Asia/Muscat" {
+        value 282;
+      }
+      enum "America/Panama" {
+        value 283;
+      }
+      enum "America/Lima" {
+        value 284;
+      }
+      enum "Pacific/Tahiti" {
+        value 285;
+        description
+          "Society Islands";
+      }
+      enum "Pacific/Marquesas" {
+        value 286;
+        description
+          "Marquesas Islands";
+      }
+      enum "Pacific/Gambier" {
+        value 287;
+        description
+          "Gambier Islands";
+      }
+      enum "Pacific/Port_Moresby" {
+        value 288;
+      }
+      enum "Asia/Manila" {
+        value 289;
+      }
+      enum "Asia/Karachi" {
+        value 290;
+      }
+      enum "Europe/Warsaw" {
+        value 291;
+      }
+      enum "America/Miquelon" {
+        value 292;
+      }
+      enum "Pacific/Pitcairn" {
+        value 293;
+      }
+      enum "America/Puerto_Rico" {
+        value 294;
+      }
+      enum "Asia/Gaza" {
+        value 295;
+        description
+          "Gaza Strip";
+      }
+      enum "Asia/Hebron" {
+        value 296;
+        description
+          "West Bank";
+      }
+      enum "Europe/Lisbon" {
+        value 297;
+        description
+          "mainland";
+      }
+      enum "Atlantic/Madeira" {
+        value 298;
+        description
+          "Madeira Islands";
+      }
+      enum "Atlantic/Azores" {
+        value 299;
+        description
+          "Azores";
+      }
+      enum "Pacific/Palau" {
+        value 300;
+      }
+      enum "America/Asuncion" {
+        value 301;
+      }
+      enum "Asia/Qatar" {
+        value 302;
+      }
+      enum "Indian/Reunion" {
+        value 303;
+      }
+      enum "Europe/Bucharest" {
+        value 304;
+      }
+      enum "Europe/Belgrade" {
+        value 305;
+      }
+      enum "Europe/Kaliningrad" {
+        value 306;
+        description
+          "Moscow-01 - Kaliningrad";
+      }
+      enum "Europe/Moscow" {
+        value 307;
+        description
+          "Moscow+00 - west Russia";
+      }
+      enum "Europe/Volgograd" {
+        value 308;
+        description
+          "Moscow+00 - Caspian Sea";
+      }
+      enum "Europe/Samara" {
+        value 309;
+        description
+          "Moscow+00 - Samara, Udmurtia";
+      }
+      enum "Asia/Yekaterinburg" {
+        value 310;
+        description
+          "Moscow+02 - Urals";
+      }
+      enum "Asia/Omsk" {
+        value 311;
+        description
+          "Moscow+03 - west Siberia";
+      }
+      enum "Asia/Novosibirsk" {
+        value 312;
+        description
+          "Moscow+03 - Novosibirsk";
+      }
+      enum "Asia/Novokuznetsk" {
+        value 313;
+        description
+          "Moscow+03 - Novokuznetsk";
+      }
+      enum "Asia/Krasnoyarsk" {
+        value 314;
+        description
+          "Moscow+04 - Yenisei River";
+      }
+      enum "Asia/Irkutsk" {
+        value 315;
+        description
+          "Moscow+05 - Lake Baikal";
+      }
+      enum "Asia/Yakutsk" {
+        value 316;
+        description
+          "Moscow+06 - Lena River";
+      }
+      enum "Asia/Vladivostok" {
+        value 317;
+        description
+          "Moscow+07 - Amur River";
+      }
+      enum "Asia/Sakhalin" {
+        value 318;
+        description
+          "Moscow+07 - Sakhalin Island";
+      }
+      enum "Asia/Magadan" {
+        value 319;
+        description
+          "Moscow+08 - Magadan";
+      }
+      enum "Asia/Kamchatka" {
+        value 320;
+        description
+          "Moscow+08 - Kamchatka";
+      }
+      enum "Asia/Anadyr" {
+        value 321;
+        description
+          "Moscow+08 - Bering Sea";
+      }
+      enum "Africa/Kigali" {
+        value 322;
+      }
+      enum "Asia/Riyadh" {
+        value 323;
+      }
+      enum "Pacific/Guadalcanal" {
+        value 324;
+      }
+      enum "Indian/Mahe" {
+        value 325;
+      }
+      enum "Africa/Khartoum" {
+        value 326;
+      }
+      enum "Europe/Stockholm" {
+        value 327;
+      }
+      enum "Asia/Singapore" {
+        value 328;
+      }
+      enum "Atlantic/St_Helena" {
+        value 329;
+      }
+      enum "Europe/Ljubljana" {
+        value 330;
+      }
+      enum "Arctic/Longyearbyen" {
+        value 331;
+      }
+      enum "Europe/Bratislava" {
+        value 332;
+      }
+      enum "Africa/Freetown" {
+        value 333;
+      }
+      enum "Europe/San_Marino" {
+        value 334;
+      }
+      enum "Africa/Dakar" {
+        value 335;
+      }
+      enum "Africa/Mogadishu" {
+        value 336;
+      }
+      enum "America/Paramaribo" {
+        value 337;
+      }
+      enum "Africa/Juba" {
+        value 338;
+      }
+      enum "Africa/Sao_Tome" {
+        value 339;
+      }
+      enum "America/El_Salvador" {
+        value 340;
+      }
+      enum "America/Lower_Princes" {
+        value 341;
+      }
+      enum "Asia/Damascus" {
+        value 342;
+      }
+      enum "Africa/Mbabane" {
+        value 343;
+      }
+      enum "America/Grand_Turk" {
+        value 344;
+      }
+      enum "Africa/Ndjamena" {
+        value 345;
+      }
+      enum "Indian/Kerguelen" {
+        value 346;
+      }
+      enum "Africa/Lome" {
+        value 347;
+      }
+      enum "Asia/Bangkok" {
+        value 348;
+      }
+      enum "Asia/Dushanbe" {
+        value 349;
+      }
+      enum "Pacific/Fakaofo" {
+        value 350;
+      }
+      enum "Asia/Dili" {
+        value 351;
+      }
+      enum "Asia/Ashgabat" {
+        value 352;
+      }
+      enum "Africa/Tunis" {
+        value 353;
+      }
+      enum "Pacific/Tongatapu" {
+        value 354;
+      }
+      enum "Europe/Istanbul" {
+        value 355;
+      }
+      enum "America/Port_of_Spain" {
+        value 356;
+      }
+      enum "Pacific/Funafuti" {
+        value 357;
+      }
+      enum "Asia/Taipei" {
+        value 358;
+      }
+      enum "Africa/Dar_es_Salaam" {
+        value 359;
+      }
+      enum "Europe/Kiev" {
+        value 360;
+        description
+          "most locations";
+      }
+      enum "Europe/Uzhgorod" {
+        value 361;
+        description
+          "Ruthenia";
+      }
+      enum "Europe/Zaporozhye" {
+        value 362;
+        description
+          "Zaporozh'ye, E Lugansk / Zaporizhia, E Luhansk";
+      }
+      enum "Europe/Simferopol" {
+        value 363;
+        description
+          "central Crimea";
+      }
+      enum "Africa/Kampala" {
+        value 364;
+      }
+      enum "Pacific/Johnston" {
+        value 365;
+        description
+          "Johnston Atoll";
+      }
+      enum "Pacific/Midway" {
+        value 366;
+        description
+          "Midway Islands";
+      }
+      enum "Pacific/Wake" {
+        value 367;
+        description
+          "Wake Island";
+      }
+      enum "America/New_York" {
+        value 368;
+        description
+          "Eastern Time";
+      }
+      enum "America/Detroit" {
+        value 369;
+        description
+          "Eastern Time - Michigan - most locations";
+      }
+      enum "America/Kentucky/Louisville" {
+        value 370;
+        description
+          "Eastern Time - Kentucky - Louisville area";
+      }
+      enum "America/Kentucky/Monticello" {
+        value 371;
+        description
+          "Eastern Time - Kentucky - Wayne County";
+      }
+      enum "America/Indiana/Indianapolis" {
+        value 372;
+        description
+          "Eastern Time - Indiana - most locations";
+      }
+      enum "America/Indiana/Vincennes" {
+        value 373;
+        description
+          "Eastern Time - Indiana - Daviess, Dubois, Knox & Martin
+           Counties";
+      }
+      enum "America/Indiana/Winamac" {
+        value 374;
+        description
+          "Eastern Time - Indiana - Pulaski County";
+      }
+      enum "America/Indiana/Marengo" {
+        value 375;
+        description
+          "Eastern Time - Indiana - Crawford County";
+      }
+      enum "America/Indiana/Petersburg" {
+        value 376;
+        description
+          "Eastern Time - Indiana - Pike County";
+      }
+      enum "America/Indiana/Vevay" {
+        value 377;
+        description
+          "Eastern Time - Indiana - Switzerland County";
+      }
+      enum "America/Chicago" {
+        value 378;
+        description
+          "Central Time";
+      }
+      enum "America/Indiana/Tell_City" {
+        value 379;
+        description
+          "Central Time - Indiana - Perry County";
+      }
+      enum "America/Indiana/Knox" {
+        value 380;
+        description
+          "Central Time - Indiana - Starke County";
+      }
+      enum "America/Menominee" {
+        value 381;
+        description
+          "Central Time - Michigan - Dickinson, Gogebic, Iron &
+           Menominee Counties";
+      }
+      enum "America/North_Dakota/Center" {
+        value 382;
+        description
+          "Central Time - North Dakota - Oliver County";
+      }
+      enum "America/North_Dakota/New_Salem" {
+        value 383;
+        description
+          "Central Time - North Dakota - Morton County (except Mandan
+           area)";
+      }
+      enum "America/North_Dakota/Beulah" {
+        value 384;
+        description
+          "Central Time - North Dakota - Mercer County";
+      }
+      enum "America/Denver" {
+        value 385;
+        description
+          "Mountain Time";
+      }
+      enum "America/Boise" {
+        value 386;
+        description
+          "Mountain Time - south Idaho & east Oregon";
+      }
+      enum "America/Shiprock" {
+        value 387;
+        description
+          "Mountain Time - Navajo";
+      }
+      enum "America/Phoenix" {
+        value 388;
+        description
+          "Mountain Standard Time - Arizona";
+      }
+      enum "America/Los_Angeles" {
+        value 389;
+        description
+          "Pacific Time";
+      }
+      enum "America/Anchorage" {
+        value 390;
+        description
+          "Alaska Time";
+      }
+      enum "America/Juneau" {
+        value 391;
+        description
+          "Alaska Time - Alaska panhandle";
+      }
+      enum "America/Sitka" {
+        value 392;
+        description
+          "Alaska Time - southeast Alaska panhandle";
+      }
+      enum "America/Yakutat" {
+        value 393;
+        description
+          "Alaska Time - Alaska panhandle neck";
+      }
+      enum "America/Nome" {
+        value 394;
+        description
+          "Alaska Time - west Alaska";
+      }
+      enum "America/Adak" {
+        value 395;
+        description
+          "Aleutian Islands";
+      }
+      enum "America/Metlakatla" {
+        value 396;
+        description
+          "Metlakatla Time - Annette Island";
+      }
+      enum "Pacific/Honolulu" {
+        value 397;
+        description
+          "Hawaii";
+      }
+      enum "America/Montevideo" {
+        value 398;
+      }
+      enum "Asia/Samarkand" {
+        value 399;
+        description
+          "west Uzbekistan";
+      }
+      enum "Asia/Tashkent" {
+        value 400;
+        description
+          "east Uzbekistan";
+      }
+      enum "Europe/Vatican" {
+        value 401;
+      }
+      enum "America/St_Vincent" {
+        value 402;
+      }
+      enum "America/Caracas" {
+        value 403;
+      }
+      enum "America/Tortola" {
+        value 404;
+      }
+      enum "America/St_Thomas" {
+        value 405;
+      }
+      enum "Asia/Ho_Chi_Minh" {
+        value 406;
+      }
+      enum "Pacific/Efate" {
+        value 407;
+      }
+      enum "Pacific/Wallis" {
+        value 408;
+      }
+      enum "Pacific/Apia" {
+        value 409;
+      }
+      enum "Asia/Aden" {
+        value 410;
+      }
+      enum "Indian/Mayotte" {
+        value 411;
+      }
+      enum "Africa/Johannesburg" {
+        value 412;
+      }
+      enum "Africa/Lusaka" {
+        value 413;
+      }
+      enum "Africa/Harare" {
+        value 414;
+      }
+    }
+  }
+}
diff --git a/yang-model-parser-impl/src/test/resources/types/ietf-inet-types@2010-09-24.yang b/yang-model-parser-impl/src/test/resources/types/ietf-inet-types@2010-09-24.yang
new file mode 100644 (file)
index 0000000..de20feb
--- /dev/null
@@ -0,0 +1,418 @@
+ module ietf-inet-types {
+
+   namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+   prefix "inet";
+
+   organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+   contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   description
+    "This module contains a collection of generally useful derived
+     YANG data types for Internet addresses and related things.
+
+     Copyright (c) 2010 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or without
+     modification, is permitted pursuant to, and subject to the license
+     terms contained in, the Simplified BSD License set forth in Section
+     4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6021; see
+     the RFC itself for full legal notices.";
+
+   revision 2010-09-24 {
+     description
+      "Initial revision.";
+     reference
+      "RFC 6021: Common YANG Data Types";
+   }
+
+   /*** collection of protocol field related types ***/
+
+   typedef ip-version {
+     type enumeration {
+       enum unknown {
+         value "0";
+         description
+          "An unknown or unspecified version of the Internet protocol.";
+       }
+       enum ipv4 {
+         value "1";
+         description
+          "The IPv4 protocol as defined in RFC 791.";
+       }
+       enum ipv6 {
+         value "2";
+         description
+          "The IPv6 protocol as defined in RFC 2460.";
+       }
+     }
+     description
+      "This value represents the version of the IP protocol.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetVersion textual convention of the SMIv2.";
+     reference
+      "RFC  791: Internet Protocol
+       RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   typedef dscp {
+     type uint8 {
+       range "0..63";
+     }
+     description
+      "The dscp type represents a Differentiated Services Code-Point
+       that may be used for marking packets in a traffic stream.
+
+       In the value set and its semantics, this type is equivalent
+       to the Dscp textual convention of the SMIv2.";
+     reference
+      "RFC 3289: Management Information Base for the Differentiated
+                 Services Architecture
+       RFC 2474: Definition of the Differentiated Services Field
+                 (DS Field) in the IPv4 and IPv6 Headers
+       RFC 2780: IANA Allocation Guidelines For Values In
+                 the Internet Protocol and Related Headers";
+   }
+
+   typedef ipv6-flow-label {
+     type uint32 {
+       range "0..1048575";
+     }
+     description
+      "The flow-label type represents flow identifier or Flow Label
+       in an IPv6 packet header that may be used to discriminate
+       traffic flows.
+
+       In the value set and its semantics, this type is equivalent
+       to the IPv6FlowLabel textual convention of the SMIv2.";
+     reference
+      "RFC 3595: Textual Conventions for IPv6 Flow Label
+       RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+   }
+
+   typedef port-number {
+     type uint16 {
+       range "0..65535";
+     }
+     description
+      "The port-number type represents a 16-bit port number of an
+       Internet transport layer protocol such as UDP, TCP, DCCP, or
+       SCTP.  Port numbers are assigned by IANA.  A current list of
+       all assignments is available from <http://www.iana.org/>.
+
+       Note that the port number value zero is reserved by IANA.  In
+       situations where the value zero does not make sense, it can
+       be excluded by subtyping the port-number type.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetPortNumber textual convention of the SMIv2.";
+     reference
+      "RFC  768: User Datagram Protocol
+       RFC  793: Transmission Control Protocol
+       RFC 4960: Stream Control Transmission Protocol
+       RFC 4340: Datagram Congestion Control Protocol (DCCP)
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   /*** collection of autonomous system related types ***/
+
+   typedef as-number {
+     type uint32;
+     description
+      "The as-number type represents autonomous system numbers
+       which identify an Autonomous System (AS).  An AS is a set
+       of routers under a single technical administration, using
+       an interior gateway protocol and common metrics to route
+       packets within the AS, and using an exterior gateway
+       protocol to route packets to other ASs'.  IANA maintains
+       the AS number space and has delegated large parts to the
+       regional registries.
+
+       Autonomous system numbers were originally limited to 16
+       bits.  BGP extensions have enlarged the autonomous system
+       number space to 32 bits.  This type therefore uses an uint32
+       base type without a range restriction in order to support
+       a larger autonomous system number space.
+
+       In the value set and its semantics, this type is equivalent
+       to the InetAutonomousSystemNumber textual convention of
+       the SMIv2.";
+     reference
+      "RFC 1930: Guidelines for creation, selection, and registration
+                 of an Autonomous System (AS)
+       RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+       RFC 4893: BGP Support for Four-octet AS Number Space
+       RFC 4001: Textual Conventions for Internet Network Addresses";
+   }
+
+   /*** collection of IP address and hostname related types ***/
+
+   typedef ip-address {
+     type union {
+       type inet:ipv4-address;
+       type inet:ipv6-address;
+     }
+     description
+      "The ip-address type represents an IP address and is IP
+       version neutral.  The format of the textual representations
+       implies the IP version.";
+   }
+
+   typedef ipv4-address {
+     type string {
+       pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '(%[\p{N}\p{L}]+)?';
+     }
+     description
+       "The ipv4-address type represents an IPv4 address in
+        dotted-quad notation.  The IPv4 address may include a zone
+        index, separated by a % sign.
+
+        The zone index is used to disambiguate identical address
+        values.  For link-local addresses, the zone index will
+        typically be the interface index number or the name of an
+        interface.  If the zone index is not present, the default
+        zone of the device will be used.
+
+        The canonical format for the zone index is the numerical
+        format";
+   }
+
+   typedef ipv6-address {
+     type string {
+       pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+             + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+             + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+             + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+             + '(%[\p{N}\p{L}]+)?';
+       pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+             + '(%.+)?';
+     }
+     description
+      "The ipv6-address type represents an IPv6 address in full,
+       mixed, shortened, and shortened-mixed notation.  The IPv6
+       address may include a zone index, separated by a % sign.
+
+       The zone index is used to disambiguate identical address
+       values.  For link-local addresses, the zone index will
+       typically be the interface index number or the name of an
+       interface.  If the zone index is not present, the default
+       zone of the device will be used.
+
+       The canonical format of IPv6 addresses uses the compressed
+       format described in RFC 4291, Section 2.2, item 2 with the
+       following additional rules: the :: substitution must be
+       applied to the longest sequence of all-zero 16-bit chunks
+       in an IPv6 address.  If there is a tie, the first sequence
+       of all-zero 16-bit chunks is replaced by ::.  Single
+       all-zero 16-bit chunks are not compressed.  The canonical
+       format uses lowercase characters and leading zeros are
+       not allowed.  The canonical format for the zone index is
+       the numerical format as described in RFC 4007, Section
+       11.2.";
+     reference
+      "RFC 4291: IP Version 6 Addressing Architecture
+       RFC 4007: IPv6 Scoped Address Architecture
+       RFC 5952: A Recommendation for IPv6 Address Text Representation";
+   }
+
+   typedef ip-prefix {
+     type union {
+       type inet:ipv4-prefix;
+       type inet:ipv6-prefix;
+     }
+     description
+      "The ip-prefix type represents an IP prefix and is IP
+       version neutral.  The format of the textual representations
+       implies the IP version.";
+   }
+
+   typedef ipv4-prefix {
+     type string {
+       pattern
+          '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+        +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+        + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+     }
+     description
+      "The ipv4-prefix type represents an IPv4 address prefix.
+       The prefix length is given by the number following the
+       slash character and must be less than or equal to 32.
+
+       A prefix length value of n corresponds to an IP address
+       mask that has n contiguous 1-bits from the most
+       significant bit (MSB) and all other bits set to 0.
+
+       The canonical format of an IPv4 prefix has all bits of
+       the IPv4 address set to zero that are not part of the
+       IPv4 prefix.";
+   }
+
+   typedef ipv6-prefix {
+     type string {
+       pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+             + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+             + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+             + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+             + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+       pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+             + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+             + '(/.+)';
+     }
+     description
+      "The ipv6-prefix type represents an IPv6 address prefix.
+       The prefix length is given by the number following the
+       slash character and must be less than or equal 128.
+
+       A prefix length value of n corresponds to an IP address
+       mask that has n contiguous 1-bits from the most
+       significant bit (MSB) and all other bits set to 0.
+
+       The IPv6 address should have all bits that do not belong
+       to the prefix set to zero.
+
+       The canonical format of an IPv6 prefix has all bits of
+       the IPv6 address set to zero that are not part of the
+       IPv6 prefix.  Furthermore, IPv6 address is represented
+       in the compressed format described in RFC 4291, Section
+       2.2, item 2 with the following additional rules: the ::
+       substitution must be applied to the longest sequence of
+       all-zero 16-bit chunks in an IPv6 address.  If there is
+       a tie, the first sequence of all-zero 16-bit chunks is
+       replaced by ::.  Single all-zero 16-bit chunks are not
+       compressed.  The canonical format uses lowercase
+       characters and leading zeros are not allowed.";
+     reference
+      "RFC 4291: IP Version 6 Addressing Architecture";
+   }
+
+   /*** collection of domain name and URI types ***/
+
+   typedef domain-name {
+     type string {
+       pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+            +  '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+            +  '|\.';
+       length "1..253";
+     }
+     description
+      "The domain-name type represents a DNS domain name.  The
+       name SHOULD be fully qualified whenever possible.
+
+       Internet domain names are only loosely specified.  Section
+       3.5 of RFC 1034 recommends a syntax (modified in Section
+       2.1 of RFC 1123).  The pattern above is intended to allow
+       for current practice in domain name use, and some possible
+       future expansion.  It is designed to hold various types of
+       domain names, including names used for A or AAAA records
+       (host names) and other records, such as SRV records.  Note
+       that Internet host names have a stricter syntax (described
+       in RFC 952) than the DNS recommendations in RFCs 1034 and
+       1123, and that systems that want to store host names in
+       schema nodes using the domain-name type are recommended to
+       adhere to this stricter standard to ensure interoperability.
+
+       The encoding of DNS names in the DNS protocol is limited
+       to 255 characters.  Since the encoding consists of labels
+       prefixed by a length bytes and there is a trailing NULL
+       byte, only 253 characters can appear in the textual dotted
+       notation.
+
+       The description clause of schema nodes using the domain-name
+       type MUST describe when and how these names are resolved to
+       IP addresses.  Note that the resolution of a domain-name value
+       may require to query multiple DNS records (e.g., A for IPv4
+       and AAAA for IPv6).  The order of the resolution process and
+       which DNS record takes precedence can either be defined
+       explicitely or it may depend on the configuration of the
+       resolver.
+
+       Domain-name values use the US-ASCII encoding.  Their canonical
+       format uses lowercase US-ASCII characters.  Internationalized
+       domain names MUST be encoded in punycode as described in RFC
+       3492";
+     reference
+      "RFC  952: DoD Internet Host Table Specification
+       RFC 1034: Domain Names - Concepts and Facilities
+       RFC 1123: Requirements for Internet Hosts -- Application
+                 and Support
+       RFC 2782: A DNS RR for specifying the location of services
+                 (DNS SRV)
+       RFC 3492: Punycode: A Bootstring encoding of Unicode for
+                 Internationalized Domain Names in Applications
+                 (IDNA)
+       RFC 5891: Internationalizing Domain Names in Applications
+                 (IDNA): Protocol";
+   }
+
+   typedef host {
+     type union {
+       type inet:ip-address;
+       type inet:domain-name;
+     }
+     description
+      "The host type represents either an IP address or a DNS
+       domain name.";
+   }
+
+   typedef uri {
+     type string;
+     description
+      "The uri type represents a Uniform Resource Identifier
+       (URI) as defined by STD 66.
+
+       Objects using the uri type MUST be in US-ASCII encoding,
+       and MUST be normalized as described by RFC 3986 Sections
+       6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
+       percent-encoding is removed, and all case-insensitive
+       characters are set to lowercase except for hexadecimal
+       digits, which are normalized to uppercase as described in
+       Section 6.2.2.1.
+
+       The purpose of this normalization is to help provide
+       unique URIs.  Note that this normalization is not
+       sufficient to provide uniqueness.  Two URIs that are
+       textually distinct after this normalization may still be
+       equivalent.
+
+       Objects using the uri type may restrict the schemes that
+       they permit.  For example, 'data:' and 'urn:' schemes
+       might not be appropriate.
+
+       A zero-length URI is not a valid URI.  This can be used to
+       express 'URI absent' where required.
+
+       In the value set and its semantics, this type is equivalent
+       to the Uri SMIv2 textual convention defined in RFC 5017.";
+     reference
+      "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+       RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+                 Group: Uniform Resource Identifiers (URIs), URLs,
+                 and Uniform Resource Names (URNs): Clarifications
+                 and Recommendations
+       RFC 5017: MIB Textual Conventions for Uniform Resource
+                 Identifiers (URIs)";
+   }
+
+ }
diff --git a/yang-model-parser-impl/src/test/resources/types/ietf-yang-types@2010-09-24.yang b/yang-model-parser-impl/src/test/resources/types/ietf-yang-types@2010-09-24.yang
new file mode 100644 (file)
index 0000000..51d9f8b
--- /dev/null
@@ -0,0 +1,396 @@
+ module ietf-yang-types {
+
+   namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types";
+   prefix "yang";
+
+   organization
+    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+   contact
+    "WG Web:   <http://tools.ietf.org/wg/netmod/>
+     WG List:  <mailto:netmod@ietf.org>
+
+     WG Chair: David Partain
+               <mailto:david.partain@ericsson.com>
+
+     WG Chair: David Kessens
+               <mailto:david.kessens@nsn.com>
+
+     Editor:   Juergen Schoenwaelder
+               <mailto:j.schoenwaelder@jacobs-university.de>";
+
+   description
+    "This module contains a collection of generally useful derived
+     YANG data types.
+
+     Copyright (c) 2010 IETF Trust and the persons identified as
+     authors of the code.  All rights reserved.
+
+     Redistribution and use in source and binary forms, with or without
+     modification, is permitted pursuant to, and subject to the license
+     terms contained in, the Simplified BSD License set forth in Section
+     4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+     (http://trustee.ietf.org/license-info).
+
+     This version of this YANG module is part of RFC 6021; see
+     the RFC itself for full legal notices.";
+
+   revision 2010-09-24 {
+     description
+      "Initial revision.";
+     reference
+      "RFC 6021: Common YANG Data Types";
+   }
+
+   /*** collection of counter and gauge types ***/
+
+   typedef counter32 {
+     type uint32;
+     description
+      "The counter32 type represents a non-negative integer
+       that monotonically increases until it reaches a
+       maximum value of 2^32-1 (4294967295 decimal), when it
+       wraps around and starts increasing again from zero.
+
+       Counters have no defined 'initial' value, and thus, a
+       single value of a counter has (in general) no information
+       content.  Discontinuities in the monotonically increasing
+       value normally occur at re-initialization of the
+       management system, and at other times as specified in the
+       description of a schema node using this type.  If such
+       other times can occur, for example, the creation of
+       a schema node of type counter32 at times other than
+       re-initialization, then a corresponding schema node
+       should be defined, with an appropriate type, to indicate
+       the last discontinuity.
+
+       The counter32 type should not be used for configuration
+       schema nodes.  A default statement SHOULD NOT be used in
+       combination with the type counter32.
+
+       In the value set and its semantics, this type is equivalent
+       to the Counter32 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef zero-based-counter32 {
+     type yang:counter32;
+     default "0";
+     description
+      "The zero-based-counter32 type represents a counter32
+       that has the defined 'initial' value zero.
+
+       A schema node of this type will be set to zero (0) on creation
+       and will thereafter increase monotonically until it reaches
+       a maximum value of 2^32-1 (4294967295 decimal), when it
+       wraps around and starts increasing again from zero.
+
+       Provided that an application discovers a new schema node
+       of this type within the minimum time to wrap, it can use the
+       'initial' value as a delta.  It is important for a management
+       station to be aware of this minimum time and the actual time
+       between polls, and to discard data if the actual time is too
+       long or there is no defined minimum time.
+
+       In the value set and its semantics, this type is equivalent
+       to the ZeroBasedCounter32 textual convention of the SMIv2.";
+     reference
+       "RFC 4502: Remote Network Monitoring Management Information
+                  Base Version 2";
+   }
+
+   typedef counter64 {
+     type uint64;
+     description
+      "The counter64 type represents a non-negative integer
+       that monotonically increases until it reaches a
+       maximum value of 2^64-1 (18446744073709551615 decimal),
+       when it wraps around and starts increasing again from zero.
+
+       Counters have no defined 'initial' value, and thus, a
+       single value of a counter has (in general) no information
+       content.  Discontinuities in the monotonically increasing
+       value normally occur at re-initialization of the
+       management system, and at other times as specified in the
+       description of a schema node using this type.  If such
+       other times can occur, for example, the creation of
+       a schema node of type counter64 at times other than
+       re-initialization, then a corresponding schema node
+       should be defined, with an appropriate type, to indicate
+       the last discontinuity.
+
+       The counter64 type should not be used for configuration
+       schema nodes.  A default statement SHOULD NOT be used in
+       combination with the type counter64.
+
+       In the value set and its semantics, this type is equivalent
+       to the Counter64 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef zero-based-counter64 {
+     type yang:counter64;
+     default "0";
+     description
+      "The zero-based-counter64 type represents a counter64 that
+       has the defined 'initial' value zero.
+
+       A schema node of this type will be set to zero (0) on creation
+       and will thereafter increase monotonically until it reaches
+       a maximum value of 2^64-1 (18446744073709551615 decimal),
+       when it wraps around and starts increasing again from zero.
+
+       Provided that an application discovers a new schema node
+       of this type within the minimum time to wrap, it can use the
+       'initial' value as a delta.  It is important for a management
+       station to be aware of this minimum time and the actual time
+       between polls, and to discard data if the actual time is too
+       long or there is no defined minimum time.
+
+       In the value set and its semantics, this type is equivalent
+       to the ZeroBasedCounter64 textual convention of the SMIv2.";
+     reference
+      "RFC 2856: Textual Conventions for Additional High Capacity
+                 Data Types";
+   }
+
+   typedef gauge32 {
+     type uint32;
+     description
+      "The gauge32 type represents a non-negative integer, which
+       may increase or decrease, but shall never exceed a maximum
+       value, nor fall below a minimum value.  The maximum value
+       cannot be greater than 2^32-1 (4294967295 decimal), and
+       the minimum value cannot be smaller than 0.  The value of
+       a gauge32 has its maximum value whenever the information
+       being modeled is greater than or equal to its maximum
+       value, and has its minimum value whenever the information
+       being modeled is smaller than or equal to its minimum value.
+       If the information being modeled subsequently decreases
+       below (increases above) the maximum (minimum) value, the
+       gauge32 also decreases (increases).
+
+       In the value set and its semantics, this type is equivalent
+       to the Gauge32 type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef gauge64 {
+     type uint64;
+     description
+      "The gauge64 type represents a non-negative integer, which
+       may increase or decrease, but shall never exceed a maximum
+       value, nor fall below a minimum value.  The maximum value
+       cannot be greater than 2^64-1 (18446744073709551615), and
+       the minimum value cannot be smaller than 0.  The value of
+       a gauge64 has its maximum value whenever the information
+       being modeled is greater than or equal to its maximum
+       value, and has its minimum value whenever the information
+       being modeled is smaller than or equal to its minimum value.
+       If the information being modeled subsequently decreases
+       below (increases above) the maximum (minimum) value, the
+       gauge64 also decreases (increases).
+
+       In the value set and its semantics, this type is equivalent
+       to the CounterBasedGauge64 SMIv2 textual convention defined
+       in RFC 2856";
+     reference
+      "RFC 2856: Textual Conventions for Additional High Capacity
+                 Data Types";
+   }
+
+   /*** collection of identifier related types ***/
+
+   typedef object-identifier {
+     type string {
+       pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))'
+             + '(\.(0|([1-9]\d*)))*';
+     }
+     description
+      "The object-identifier type represents administratively
+       assigned names in a registration-hierarchical-name tree.
+
+       Values of this type are denoted as a sequence of numerical
+       non-negative sub-identifier values.  Each sub-identifier
+       value MUST NOT exceed 2^32-1 (4294967295).  Sub-identifiers
+       are separated by single dots and without any intermediate
+       whitespace.
+
+       The ASN.1 standard restricts the value space of the first
+       sub-identifier to 0, 1, or 2.  Furthermore, the value space
+       of the second sub-identifier is restricted to the range
+       0 to 39 if the first sub-identifier is 0 or 1.  Finally,
+       the ASN.1 standard requires that an object identifier
+       has always at least two sub-identifier.  The pattern
+       captures these restrictions.
+
+       Although the number of sub-identifiers is not limited,
+       module designers should realize that there may be
+       implementations that stick with the SMIv2 limit of 128
+       sub-identifiers.
+
+       This type is a superset of the SMIv2 OBJECT IDENTIFIER type
+       since it is not restricted to 128 sub-identifiers.  Hence,
+       this type SHOULD NOT be used to represent the SMIv2 OBJECT
+       IDENTIFIER type, the object-identifier-128 type SHOULD be
+       used instead.";
+     reference
+      "ISO9834-1: Information technology -- Open Systems
+       Interconnection -- Procedures for the operation of OSI
+       Registration Authorities: General procedures and top
+       arcs of the ASN.1 Object Identifier tree";
+   }
+
+
+
+
+   typedef object-identifier-128 {
+     type object-identifier {
+       pattern '\d*(\.\d*){1,127}';
+     }
+     description
+      "This type represents object-identifiers restricted to 128
+       sub-identifiers.
+
+       In the value set and its semantics, this type is equivalent
+       to the OBJECT IDENTIFIER type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   /*** collection of date and time related types ***/
+
+   typedef date-and-time {
+     type string {
+       pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?'
+             + '(Z|[\+\-]\d{2}:\d{2})';
+     }
+     description
+      "The date-and-time type is a profile of the ISO 8601
+       standard for representation of dates and times using the
+       Gregorian calendar.  The profile is defined by the
+       date-time production in Section 5.6 of RFC 3339.
+
+       The date-and-time type is compatible with the dateTime XML
+       schema type with the following notable exceptions:
+
+       (a) The date-and-time type does not allow negative years.
+
+       (b) The date-and-time time-offset -00:00 indicates an unknown
+           time zone (see RFC 3339) while -00:00 and +00:00 and Z all
+           represent the same time zone in dateTime.
+
+       (c) The canonical format (see below) of data-and-time values
+           differs from the canonical format used by the dateTime XML
+           schema type, which requires all times to be in UTC using the
+           time-offset 'Z'.
+
+       This type is not equivalent to the DateAndTime textual
+       convention of the SMIv2 since RFC 3339 uses a different
+       separator between full-date and full-time and provides
+       higher resolution of time-secfrac.
+
+       The canonical format for date-and-time values with a known time
+       zone uses a numeric time zone offset that is calculated using
+       the device's configured known offset to UTC time.  A change of
+       the device's offset to UTC time will cause date-and-time values
+       to change accordingly.  Such changes might happen periodically
+       in case a server follows automatically daylight saving time
+       (DST) time zone offset changes.  The canonical format for
+       date-and-time values with an unknown time zone (usually referring
+       to the notion of local time) uses the time-offset -00:00.";
+     reference
+      "RFC 3339: Date and Time on the Internet: Timestamps
+       RFC 2579: Textual Conventions for SMIv2
+       XSD-TYPES: XML Schema Part 2: Datatypes Second Edition";
+   }
+
+   typedef timeticks {
+     type uint32;
+     description
+      "The timeticks type represents a non-negative integer that
+       represents the time, modulo 2^32 (4294967296 decimal), in
+       hundredths of a second between two epochs.  When a schema
+       node is defined that uses this type, the description of
+       the schema node identifies both of the reference epochs.
+
+       In the value set and its semantics, this type is equivalent
+       to the TimeTicks type of the SMIv2.";
+     reference
+      "RFC 2578: Structure of Management Information Version 2 (SMIv2)";
+   }
+
+   typedef timestamp {
+     type yang:timeticks;
+     description
+      "The timestamp type represents the value of an associated
+       timeticks schema node at which a specific occurrence happened.
+       The specific occurrence must be defined in the description
+       of any schema node defined using this type.  When the specific
+       occurrence occurred prior to the last time the associated
+       timeticks attribute was zero, then the timestamp value is
+       zero.  Note that this requires all timestamp values to be
+       reset to zero when the value of the associated timeticks
+       attribute reaches 497+ days and wraps around to zero.
+
+       The associated timeticks schema node must be specified
+       in the description of any schema node using this type.
+
+       In the value set and its semantics, this type is equivalent
+       to the TimeStamp textual convention of the SMIv2.";
+     reference
+      "RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   /*** collection of generic address types ***/
+
+   typedef phys-address {
+     type string {
+       pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?';
+     }
+     description
+      "Represents media- or physical-level addresses represented
+       as a sequence octets, each octet represented by two hexadecimal
+       numbers.  Octets are separated by colons.  The canonical
+       representation uses lowercase characters.
+
+       In the value set and its semantics, this type is equivalent
+       to the PhysAddress textual convention of the SMIv2.";
+     reference
+      "RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   typedef mac-address {
+     type string {
+       pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}';
+     }
+     description
+      "The mac-address type represents an IEEE 802 MAC address.
+       The canonical representation uses lowercase characters.
+
+       In the value set and its semantics, this type is equivalent
+       to the MacAddress textual convention of the SMIv2.";
+     reference
+      "IEEE 802: IEEE Standard for Local and Metropolitan Area
+                 Networks: Overview and Architecture
+       RFC 2579: Textual Conventions for SMIv2";
+   }
+
+   /*** collection of XML specific types ***/
+
+   typedef xpath1.0 {
+     type string;
+     description
+      "This type represents an XPATH 1.0 expression.
+
+       When a schema node is defined that uses this type, the
+       description of the schema node MUST specify the XPath
+       context in which the XPath expression is evaluated.";
+     reference
+      "XPATH: XML Path Language (XPath) Version 1.0";
+   }
+
+ }
index b865ebe015952d56d5368153bfb50f156c79427b..402eb63a1a9cc83cfe6351bc4b5fb5cc4be7aef9 100644 (file)
@@ -1,15 +1,22 @@
-<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">\r
-  <modelVersion>4.0.0</modelVersion>\r
-  <parent>\r
-    <groupId>org.opendaylight.controller</groupId>\r
-    <artifactId>yang</artifactId>\r
-    <version>0.5.4-SNAPSHOT</version>\r
-  </parent>\r
-  <artifactId>yang-model-util</artifactId>\r
-  <dependencies>\r
-      <dependency>\r
-          <groupId>org.opendaylight.controller</groupId>\r
-          <artifactId>yang-model-api</artifactId>\r
-      </dependency>\r
-  </dependencies>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+\r
+    <parent>\r
+        <groupId>org.opendaylight.controller</groupId>\r
+        <artifactId>yang</artifactId>\r
+        <version>0.5.4-SNAPSHOT</version>\r
+    </parent>\r
+\r
+    <modelVersion>4.0.0</modelVersion>\r
+    <artifactId>yang-model-util</artifactId>\r
+    <name>${project.artifactId}</name>\r
+    <description>${project.artifactId}</description>\r
+\r
+    <dependencies>\r
+        <dependency>\r
+            <groupId>org.opendaylight.controller</groupId>\r
+            <artifactId>yang-model-api</artifactId>\r
+        </dependency>\r
+    </dependencies>\r
+\r
 </project>\r
index ad903e9e52c45e7e0f74ad950f487fee35fb3930..a56697e97a49e6327074e2dfc614eb8c5dcd64a3 100644 (file)
@@ -41,12 +41,9 @@ public abstract class AbstractUnsignedInteger implements UnsignedIntegerTypeDefi
 
     /**
      *
-     * @param actualPath
-     * @param namespace
-     * @param revision
-     * @param name
+     * @param path uint type schema path
+     * @param name qname
      * @param description
-     * @param MIN_VALUE
      * @param maxRange
      * @param units
      */
@@ -63,7 +60,9 @@ public abstract class AbstractUnsignedInteger implements UnsignedIntegerTypeDefi
     }
 
     /**
-     * @param name
+     *
+     * @param path uint type schema path
+     * @param name qname
      * @param description
      * @param rangeStatements
      * @param units
index 94391d2288eace0dc4b6d9265d97ee06893e2dcb..60b5a43bf4c9d82b55809f9742e97472d84490e9 100644 (file)
@@ -36,6 +36,8 @@ public final class BitsType implements BitsTypeDefinition {
     /**
      * Default constructor. <br>
      * Instantiates Bits type as empty bits list.
+     *
+     * @param path
      */
     public BitsType(final SchemaPath path) {
         super();
@@ -47,11 +49,8 @@ public final class BitsType implements BitsTypeDefinition {
     /**
      * Constructor with explicit definition of bits assigned to BitsType.
      *
-     * @param actualPath
-     * @param namespace
-     * @param revision
+     * @param path
      * @param bits
-     *            The bits assigned for Bits Type
      */
     public BitsType(final SchemaPath path, final List<Bit> bits) {
         super();
@@ -159,12 +158,10 @@ public final class BitsType implements BitsTypeDefinition {
         final int prime = 31;
         int result = 1;
         result = prime * result + ((bits == null) ? 0 : bits.hashCode());
-        result = prime * result
-                + ((description == null) ? 0 : description.hashCode());
+        result = prime * result + ((description == null) ? 0 : description.hashCode());
         result = prime * result + ((name == null) ? 0 : name.hashCode());
         result = prime * result + ((path == null) ? 0 : path.hashCode());
-        result = prime * result
-                + ((reference == null) ? 0 : reference.hashCode());
+        result = prime * result + ((reference == null) ? 0 : reference.hashCode());
         result = prime * result + ((units == null) ? 0 : units.hashCode());
         return result;
     }