From: Martin Vitez Date: Fri, 19 Jul 2013 09:15:10 +0000 (+0200) Subject: Projects moved under correct parent. X-Git-Tag: yangtools-0.1.0~99 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=6e699585c180944e853de8c4efddf44c659aa541;p=yangtools.git Projects moved under correct parent. 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 --- diff --git a/maven-yang-plugin-it/.gitignore b/maven-yang-plugin-it/.gitignore new file mode 100644 index 0000000000..f63984acff --- /dev/null +++ b/maven-yang-plugin-it/.gitignore @@ -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 index 0000000000..bec1acb110 --- /dev/null +++ b/maven-yang-plugin-it/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + + yang + org.opendaylight.controller + 0.5.4-SNAPSHOT + + yang-maven-plugin-it + + + + org.apache.maven.shared + maven-verifier + 1.4 + test + + + + + + + maven-failsafe-plugin + 2.6 + + + + integration-test + verify + + + + + + + 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 index 0000000000..bbece72fd3 --- /dev/null +++ b/maven-yang-plugin-it/src/test/java/org/opendaylight/controller/yang2sources/plugin/it/YangToSourcesPluginTestIT.java @@ -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 index 0000000000..c871bb1334 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/AdditionalConfig/pom.xml @@ -0,0 +1,66 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + test + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + + + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + abcd=a.b.c.d + abcd2=a.b.c.d.2 + + /target/resourcesGenerated + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + config + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..1deb2020a9 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/Correct/pom.xml @@ -0,0 +1,53 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + test + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + + + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..5842b0bdaa --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest1/pom.xml @@ -0,0 +1,45 @@ + + 4.0.0 + + org.opendaylight.controller + generator-test1 + 0.5.4-SNAPSHOT + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ${basedir}/src/main/resources + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..5bf7ece91b --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile1.yang @@ -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 index 0000000000..7f7b3064f8 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile2.yang @@ -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 index 0000000000..8e5b86a880 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest1/src/main/resources/testfile3.yang @@ -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 index 0000000000..501fd1d903 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest2/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + generator-test2 + + + + + org.opendaylight.controller + generator-test1 + 0.5.4-SNAPSHOT + system + ${project.basedir}/../GenerateTest1/target/generator-test1-0.5.4-SNAPSHOT.jar + + + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ${project.basedir}/yang + true + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + outDir/ + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..db346ca487 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/GenerateTest2/yang/private.yang @@ -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 index 0000000000..b33abb3ed0 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/Generator/pom.xml @@ -0,0 +1,50 @@ + + 4.0.0 + + binding-generator + org.opendaylight.controller + 0.5.4-SNAPSHOT + + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + outDir/ + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..6e25e48958 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/MissingYangInDep/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + generator-test2 + + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ${project.basedir}/yang + true + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + outDir/ + + + + + + + org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl + + + outDir/ + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..8d7227b08b --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/MissingYangInDep/yang/private.yang @@ -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 index 0000000000..5349154f2b --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/NoGenerators/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + + + org.opendaylight.controller.yang2sources.spi.ResourceProviderTestImpl + + + outDir/ + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..b73a53e30c --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/NoOutputDir/pom.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..df7519ece7 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ${basedir} + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + /outDir/ + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..e8b6ecac6e --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml @@ -0,0 +1,57 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + ../files + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + /outDir/ + + + + + unknown + + + /outDir/ + + + + + + + + + + org.opendaylight.controller + yang-maven-plugin-spi + 0.5.4-SNAPSHOT + test-jar + + + + + + 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 index 0000000000..af11a69f10 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/YangRootNotExist/pom.xml @@ -0,0 +1,40 @@ + + 4.0.0 + + org.opendaylight.controller + 0.5.4-SNAPSHOT + + test + + + + + org.opendaylight.controller + yang-maven-plugin + 0.5.4-SNAPSHOT + + + + generate-sources + + + unknown + false + + + + org.opendaylight.controller.yang2sources.spi.CodeGeneratorTestImpl + + + /outDir/ + + + + + + + + + + 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 index 0000000000..5bf7ece91b --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/files/testfile1.yang @@ -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 index 0000000000..2d16b99821 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/files/testfile2.yang @@ -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 index 0000000000..8e5b86a880 --- /dev/null +++ b/maven-yang-plugin-it/src/test/resources/files/testfile3.yang @@ -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 index 0000000000..444fa1fc3f --- /dev/null +++ b/maven-yang-plugin/pom.xml @@ -0,0 +1,110 @@ + + 4.0.0 + + yang + org.opendaylight.controller + 0.5.4-SNAPSHOT + + + yang-maven-plugin + maven-plugin + + 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 + + + + + org.apache.maven + maven-core + 3.0.5 + + + org.apache.maven + maven-plugin-api + 3.0.5 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.2 + provided + + + org.apache.maven + maven-artifact + 2.0 + + + + ${project.groupId} + yang-model-parser-impl + + + org.opendaylight.controller + yang-maven-plugin-spi + + + + commons-io + commons-io + 2.4 + + + + ${project.groupId} + yang-maven-plugin-spi + ${project.version} + test-jar + test + + + org.mockito + mockito-all + 1.8.4 + test + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.2 + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.2 + + true + + + + mojo-descriptor + + descriptor + + + + + + + + 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 index 0000000000..88f4dde31a --- /dev/null +++ b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java @@ -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 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 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 index 0000000000..e3b0b31215 --- /dev/null +++ b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/Util.java @@ -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> cache = Maps + .newHashMapWithExpectedSize(10); + + /** + * List files recursively and return as array of String paths. Use cache of + * size 1. + */ + static Collection listFiles(File root) throws FileNotFoundException { + if (cache.get(root) != null) + return cache.get(root); + + if (!root.exists()) { + throw new FileNotFoundException(root.toString()); + } + + Collection yangFiles = FileUtils.listFiles(root, + new String[] { YANG_SUFFIX }, true); + + toCache(root, yangFiles); + return yangFiles; + } + + static List listFilesAsStream(File rootDir) + throws FileNotFoundException { + List is = new ArrayList(); + + Collection 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 yangFiles) { + cache.put(rootDir, yangFiles); + } + + /** + * Instantiate object from fully qualified class name + */ + static T getInstance(String codeGeneratorClass, Class 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 getClassPath(MavenProject project) { + List 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 checkNotNull(T obj, String paramName) { + return Preconditions.checkNotNull(obj, "Parameter " + paramName + + " is null"); + } + + final static class YangsInZipsResult implements Closeable { + final List yangStreams; + private final List zipInputStreams; + + private YangsInZipsResult(List yangStreams, + List 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 yangsFromDependencies = new ArrayList<>(); + List zips = new ArrayList<>(); + try { + List 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 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 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 yangModules; + + ContextHolder(SchemaContext context, Set yangModules) { + this.context = context; + this.yangModules = yangModules; + } + + SchemaContext getContext() { + return context; + } + + Set 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 index 0000000000..6e43b306cd --- /dev/null +++ b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java @@ -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: + *
    + *
  1. List yang files from {@link #yangFilesRootDir}
  2. + *
  3. Process yang files using {@link YangModelParserImpl}
  4. + *
  5. For each {@link CodeGenerator} from {@link #codeGenerators}:
  6. + *
      + *
    1. Instantiate using default constructor
    2. + *
    3. Call {@link CodeGenerator#generateSources(SchemaContext, File)}
    4. + *
    + *
+ */ +@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 + * 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 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 processCodeGenerators( + CodeGeneratorArg[] codeGenerators) { + List 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 index 0000000000..b781d72311 --- /dev/null +++ b/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesProcessor.java @@ -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 codeGenerators; + private final MavenProject project; + private final boolean inspectDependencies; + private YangProvider yangProvider; + + @VisibleForTesting + YangToSourcesProcessor(Log log, File yangFilesRootDir, + List 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 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 closeables = new ArrayList<>(); + log.info(Util.message("Inspecting %s", LOG_PREFIX, yangFilesRootDir)); + try { + List yangsInProject = Util + .listFilesAsStream(yangFilesRootDir); + List all = new ArrayList<>(yangsInProject); + closeables.addAll(yangsInProject); + Map allYangModules; + Set 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 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 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 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 index 0000000000..14e9d34b2a --- /dev/null +++ b/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/GenerateSourcesTest.java @@ -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 additionalCfg; + private static File resourceBaseDir; + private static MavenProject project; + + @Override + public Collection generateSources(SchemaContext context, + File outputBaseDir, Set currentModules) + throws IOException { + called++; + outputDir = outputBaseDir; + return Lists.newArrayList(); + } + + @Override + public void setLog(Log log) { + GeneratorMock.log = log; + } + + @Override + public void setAdditionalConfig( + Map 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 index 0000000000..240825409f --- /dev/null +++ b/maven-yang-plugin/src/test/java/org/opendaylight/controller/yang2sources/plugin/UtilTest.java @@ -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 files = Util.listFiles(new File(yang)); + Collection 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 index 0000000000..72e4d2c4d8 --- /dev/null +++ b/maven-yang-plugin/src/test/resources/yang/mock.yang @@ -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 index 0000000000..6754c8c3c4 --- /dev/null +++ b/maven-yang/pom.xml @@ -0,0 +1,51 @@ + + + + yang + org.opendaylight.controller + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-maven-plugin-spi + ${project.artifactId} + ${project.artifactId} + + + + org.opendaylight.controller + yang-model-api + + + + org.apache.maven + maven-plugin-api + 3.0.5 + + + org.apache.maven + maven-core + 3.0.5 + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + package + + test-jar + + + + + + + + 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 index 0000000000..3042160a2a --- /dev/null +++ b/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java @@ -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 generateSources(SchemaContext context, File outputBaseDir, Set 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 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 index 0000000000..3103042f99 --- /dev/null +++ b/maven-yang/src/test/java/org/opendaylight/controller/yang2sources/spi/CodeGeneratorTestImpl.java @@ -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 generateSources(SchemaContext context, + File outputBaseDir, Set 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 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 fc50604994..5c3617c988 100644 --- a/pom.xml +++ b/pom.xml @@ -21,16 +21,16 @@ yang-common yang-data-api yang-data-util - yang-data-impl + yang-data-impl yang-model-api yang-model-util yang-binding yang-ext - ../code-generator/yang-model-parser-api - ../code-generator/yang-model-parser-impl - ../code-generator/maven-yang - ../code-generator/maven-yang-plugin - ../code-generator/maven-yang-plugin-it + yang-model-parser-api + yang-model-parser-impl + maven-yang + maven-yang-plugin + maven-yang-plugin-it @@ -104,7 +104,6 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.8.1 maven @@ -119,6 +118,7 @@ + @@ -138,4 +138,5 @@ + diff --git a/src/site/site.xml b/src/site/site.xml new file mode 100644 index 0000000000..80ff3a4b99 --- /dev/null +++ b/src/site/site.xml @@ -0,0 +1,16 @@ + + + + org.apache.maven.skins + maven-fluido-skin + 1.3.0 + + + + + + + + + + diff --git a/yang-binding/pom.xml b/yang-binding/pom.xml index 79add78254..70b7a5a311 100644 --- a/yang-binding/pom.xml +++ b/yang-binding/pom.xml @@ -1,9 +1,15 @@ - - 4.0.0 - - org.opendaylight.controller - yang - 0.5.4-SNAPSHOT - - yang-binding + + + + org.opendaylight.controller + yang + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-binding + ${project.artifactId} + Java binding for YANG + diff --git a/yang-common/pom.xml b/yang-common/pom.xml index a94013b288..445e310a2a 100644 --- a/yang-common/pom.xml +++ b/yang-common/pom.xml @@ -1,16 +1,23 @@ - - 4.0.0 - - org.opendaylight.controller - yang - 0.5.4-SNAPSHOT - - yang-common - - - org.slf4j - slf4j-api - ${slf4j.version} - - + + + + org.opendaylight.controller + yang + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-common + ${project.artifactId} + ${project.artifactId} + + + + org.slf4j + slf4j-api + + + + diff --git a/yang-data-api/pom.xml b/yang-data-api/pom.xml index 28f25946ba..145daf9561 100644 --- a/yang-data-api/pom.xml +++ b/yang-data-api/pom.xml @@ -1,12 +1,16 @@ - 4.0.0 + org.opendaylight.controller yang 0.5.4-SNAPSHOT + + 4.0.0 yang-data-api + ${project.artifactId} + ${project.artifactId} @@ -14,4 +18,5 @@ yang-common - \ No newline at end of file + + diff --git a/yang-data-impl/pom.xml b/yang-data-impl/pom.xml index 7a1b756332..ca5bd5ced0 100644 --- a/yang-data-impl/pom.xml +++ b/yang-data-impl/pom.xml @@ -1,13 +1,16 @@ - - 4.0.0 + org.opendaylight.controller yang 0.5.4-SNAPSHOT + + 4.0.0 yang-data-impl + ${project.artifactId} + ${project.artifactId} 2.1.6 @@ -25,7 +28,6 @@ - org.opendaylight.controller @@ -81,4 +83,5 @@ test + diff --git a/yang-data-util/pom.xml b/yang-data-util/pom.xml index 722a379aa3..bbd6cd6382 100644 --- a/yang-data-util/pom.xml +++ b/yang-data-util/pom.xml @@ -1,16 +1,22 @@ - 4.0.0 + org.opendaylight.controller yang 0.5.4-SNAPSHOT + + 4.0.0 yang-data-util + ${project.artifactId} + ${project.artifactId} + org.opendaylight.controller yang-data-api - \ No newline at end of file + + diff --git a/yang-ext/pom.xml b/yang-ext/pom.xml index 85ecb91b33..d1d543abb5 100644 --- a/yang-ext/pom.xml +++ b/yang-ext/pom.xml @@ -1,13 +1,17 @@ - 4.0.0 + org.opendaylight.controller yang 0.5.4-SNAPSHOT + + 4.0.0 yang-ext 2013.09.07-SNAPSHOT + ${project.artifactId} + ${project.artifactId} diff --git a/yang-model-api/pom.xml b/yang-model-api/pom.xml index 8c4cb35196..14e7d20350 100644 --- a/yang-model-api/pom.xml +++ b/yang-model-api/pom.xml @@ -1,16 +1,22 @@ - 4.0.0 + org.opendaylight.controller yang 0.5.4-SNAPSHOT + + 4.0.0 yang-model-api + ${project.artifactId} + ${project.artifactId} + org.opendaylight.controller yang-common + diff --git a/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/type/DecimalTypeDefinition.java b/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/type/DecimalTypeDefinition.java index 74a420a3f8..068d4a977c 100644 --- a/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/type/DecimalTypeDefinition.java +++ b/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/type/DecimalTypeDefinition.java @@ -11,21 +11,20 @@ import java.util.List; import org.opendaylight.controller.yang.model.api.TypeDefinition; -public interface DecimalTypeDefinition extends - TypeDefinition { +public interface DecimalTypeDefinition extends TypeDefinition { List getRangeStatements(); /** * Returns integer between 1 and 18 inclusively.
*
- * + * * 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 index 0000000000..5bd261cdbd --- /dev/null +++ b/yang-model-parser-api/pom.xml @@ -0,0 +1,21 @@ + + + + org.opendaylight.controller + yang + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-model-parser-api + ${project.artifactId} + YANG parser API + + + + org.opendaylight.controller + yang-model-api + + + + 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 index 0000000000..142f199af4 --- /dev/null +++ b/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/YangModelParser.java @@ -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;
+ * 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 parseYangModels(final List yangFiles); + + /** + * Parse one or more Yang model files and return the definitions of Yang + * modules defined in *.yang files.
+ * 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 parseYangModels(final List 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 parseYangModelsMapped(final List yangFiles); + + /** + * Parse one or more Yang model streams and return the definitions of Yang + * modules defined in *.yang files;
+ * 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 parseYangModelsFromStreams(final List yangModelStreams); + + /** + * Parse one or more Yang model streams and return the definitions of Yang + * modules defined in *.yang files.
+ * 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 parseYangModelsFromStreams(final List 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 parseYangModelsFromStreamsMapped(final List 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 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 index 0000000000..2e8a029f85 --- /dev/null +++ b/yang-model-parser-api/src/main/java/org/opendaylight/controller/yang/model/parser/api/package-info.java @@ -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 index 0000000000..b40cd3c0b5 --- /dev/null +++ b/yang-model-parser-impl/pom.xml @@ -0,0 +1,135 @@ + + + + org.opendaylight.controller + yang + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-model-parser-impl + ${project.artifactId} + YANG parser + + + + org.opendaylight.controller + yang-common + + + org.opendaylight.controller + yang-model-api + + + org.opendaylight.controller + yang-model-parser-api + + + org.opendaylight.controller + yang-model-util + + + org.antlr + antlr4 + 4.0 + + + org.slf4j + slf4j-simple + 1.7.2 + + + org.mockito + mockito-all + 1.8.4 + + + com.google.guava + guava + 14.0.1 + + + junit + junit + + + + + + + org.antlr + antlr4-maven-plugin + 4.0 + + + + antlr4 + + + + + src/main/antlr + target/generated-sources/parser/org/opendaylight/controller/antlrv4/code/gen + true + true + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + generate-sources + + add-source + + + + target/generated-sources/parser + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + *.opendaylight.controller.antlrv4.code.gen + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.antlr + antlr4-maven-plugin + [4.0,) + + antlr4 + + + + + + + + + + + + + + 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 index 0000000000..1c511355e9 --- /dev/null +++ b/yang-model-parser-impl/src/main/antlr/YangLexer.g4 @@ -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 index 0000000000..c814831253 --- /dev/null +++ b/yang-model-parser-impl/src/main/antlr/YangParser.g4 @@ -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 index 0000000000..786a7ec245 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractBuilder.java @@ -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 unknownNodes; + protected final List addedUnknownNodes = new ArrayList(); + + 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 getUnknownNodeBuilders() { + return addedUnknownNodes; + } + + @Override + public void addUnknownNodeBuilder(UnknownSchemaNodeBuilder unknownNode) { + addedUnknownNodes.add(unknownNode); + } + + public void setUnknownNodes(List 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 index 0000000000..e85305dac9 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractDataNodeContainerBuilder.java @@ -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 childNodes; + protected final Set addedChildNodes = new HashSet(); + + protected Set groupings; + protected final Set addedGroupings = new HashSet(); + + 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 getChildNodes() { + if (childNodes == null) { + return Collections.emptySet(); + } + return childNodes; + } + + public void setChildNodes(Set childNodes) { + this.childNodes = childNodes; + } + + @Override + public Set 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 getGroupings() { + if (groupings == null) { + return Collections.emptySet(); + } + return groupings; + } + + public void setGroupings(final Set groupings) { + this.groupings = groupings; + } + + public Set 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 index 0000000000..2727bc9533 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractSchemaNodeBuilder.java @@ -0,0 +1,83 @@ +/* + * 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.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; + +/** + * Basic implementation of SchemaNodeBuilder. + */ +public abstract class AbstractSchemaNodeBuilder extends AbstractBuilder implements SchemaNodeBuilder { + protected final QName qname; + protected SchemaPath schemaPath; + protected String description; + protected String reference; + protected Status status = Status.CURRENT; + protected List unknownNodes; + + protected AbstractSchemaNodeBuilder(final String moduleName, final int line, final QName qname) { + super(moduleName, line); + this.qname = qname; + } + + public QName getQName() { + return qname; + } + + @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(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; + } + } + + public void setUnknownNodes(List unknownNodes) { + this.unknownNodes = unknownNodes; + } + +} 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 index 0000000000..23ded94c40 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AbstractTypeAwareBuilder.java @@ -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 index 0000000000..98cdb67e3e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationSchemaBuilder.java @@ -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 index 0000000000..639e18c3ad --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/AugmentationTargetBuilder.java @@ -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 index 0000000000..b849f20d2f --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/Builder.java @@ -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 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 index 0000000000..7a5f80de9c --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataNodeContainerBuilder.java @@ -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 getChildNodes(); + + /** + * Get builders of child nodes. + * + * @return collection child nodes builders + */ + Set 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 getGroupings(); + + /** + * Get builders of groupings defined in this node. + * + * @return collection of grouping builders + */ + Set 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 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 index 0000000000..a21775068d --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/DataSchemaNodeBuilder.java @@ -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 index 0000000000..74ee330c2e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingBuilder.java @@ -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 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 index 0000000000..c074f60a10 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/GroupingMember.java @@ -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 index 0000000000..13c96d3a22 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/SchemaNodeBuilder.java @@ -0,0 +1,88 @@ +/* + * 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.SchemaNode; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.Status; + +/** + * Interface for all builders of SchemaNode nodes. + */ +public interface SchemaNodeBuilder 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(); + + /** + * Set schema path to this node. + * + * @param schemaPath + */ + void setPath(SchemaPath schemaPath); + + /** + * Get description of this node. + * + * @return description statement + */ + String getDescription(); + + /** + * Set description to this node. + * + * @param description + */ + void setDescription(String description); + + /** + * Get reference of this node. + * + * @return reference statement + */ + String getReference(); + + /** + * Set reference to this node. + * + * @param reference + */ + void setReference(String reference); + + /** + * Get status of this node. + * + * @return status statement + */ + Status getStatus(); + + /** + * Set status to this node. + * + * @param status + */ + void setStatus(Status status); + + /** + * Build SchemaNode object from this builder. + */ + SchemaNode build(); + +} 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 index 0000000000..8b2e669f98 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeAwareBuilder.java @@ -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 index 0000000000..87c7b3c836 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/TypeDefinitionBuilder.java @@ -0,0 +1,51 @@ +/* + * 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.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; + +/** + * Interface for builders of 'typedef' statement. + */ +public interface TypeDefinitionBuilder extends TypeAwareBuilder, SchemaNodeBuilder, GroupingMember { + + TypeDefinition build(); + + List getRanges(); + + void setRanges(List ranges); + + List getLengths(); + + void setLengths(List lengths); + + List getPatterns(); + + void setPatterns(List patterns); + + Integer getFractionDigits(); + + void setFractionDigits(Integer fractionDigits); + + List getUnknownNodes(); + + Object getDefaultValue(); + + void setDefaultValue(Object defaultValue); + + String getUnits(); + + void setUnits(String units); + +} 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 index 0000000000..626f0f4607 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/api/UsesNodeBuilder.java @@ -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 getAugmentations(); + + void addAugment(AugmentationSchemaBuilder builder); + + boolean isAugmenting(); + + void setAugmenting(boolean augmenting); + + List getRefines(); + + List 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 index 0000000000..6b6063cc95 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AnyXmlBuilder.java @@ -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(); + 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 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..cdb751f81b --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/AugmentationSchemaBuilderImpl.java @@ -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 usesNodes = new HashSet(); + 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 getGroupings() { + return Collections.emptySet(); + } + + @Override + public Set 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 childs = new TreeMap(Comparators.QNAME_COMP); + for (DataSchemaNodeBuilder node : addedChildNodes) { + childs.put(node.getQName(), node.build()); + } + instance.setChildNodes(childs); + + // USES + final Set usesNodeDefinitions = new HashSet(); + for (UsesNodeBuilder builder : usesNodes) { + usesNodeDefinitions.add(builder.build()); + } + instance.setUses(usesNodeDefinitions); + + // UNKNOWN NODES + List unknownNodes = new ArrayList(); + 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 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 childNodes = Collections.emptyMap(); + private Set uses = Collections.emptySet(); + private String description; + private String reference; + private Status status; + private List 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 getChildNodes() { + final Set result = new TreeSet(Comparators.SCHEMA_NODE_COMP); + result.addAll(childNodes.values()); + return result; + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + /** + * Always returns an empty set, because augment can not contains + * grouping statement. + */ + @Override + public Set getGroupings() { + return Collections.emptySet(); + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if (uses != null) { + this.uses = uses; + } + } + + /** + * Always returns an empty set, because augment can not contains type + * definitions. + */ + @Override + public Set> 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 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 index 0000000000..291554c848 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceBuilder.java @@ -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 addedAugmentations = new HashSet(); + // ChoiceNode args + private Set cases; + private final Set addedCases = new HashSet(); + 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(Comparators.SCHEMA_NODE_COMP); + for (ChoiceCaseBuilder caseBuilder : addedCases) { + cases.add(caseBuilder.build()); + } + } + instance.setCases(cases); + + // AUGMENTATIONS + final Set augmentations = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugmentations) { + augmentations.add(builder.build()); + } + instance.setAvailableAugmentations(augmentations); + + // UNKNOWN NODES + if (unknownNodes == null) { + unknownNodes = new ArrayList(); + 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 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 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 getAugmentations() { + return addedAugmentations; + } + + @Override + public void addAugmentation(AugmentationSchemaBuilder augment) { + addedAugmentations.add(augment); + } + + public List 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 cases = Collections.emptySet(); + private Set augmentations = Collections.emptySet(); + private List 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 getAvailableAugmentations() { + return augmentations; + } + + private void setAvailableAugmentations(Set availableAugmentations) { + if (availableAugmentations != null) { + this.augmentations = availableAugmentations; + } + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List unknownSchemaNodes) { + if (unknownSchemaNodes != null) { + this.unknownNodes = unknownSchemaNodes; + } + } + + @Override + public Set 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 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 index 0000000000..c5282bc0ea --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ChoiceCaseBuilder.java @@ -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 addedUsesNodes = new HashSet(); + // AugmentationTarget args + private final Set addedAugmentations = new HashSet(); + + 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 childs = new TreeMap(Comparators.QNAME_COMP); + for (DataSchemaNodeBuilder node : addedChildNodes) { + childs.put(node.getQName(), node.build()); + } + instance.setChildNodes(childs); + + // USES + final Set uses = new HashSet(); + for (UsesNodeBuilder builder : addedUsesNodes) { + uses.add(builder.build()); + } + instance.setUses(uses); + + // UNKNOWN NODES + final List unknownNodes = new ArrayList(); + for (UnknownSchemaNodeBuilder b : addedUnknownNodes) { + unknownNodes.add(b.build()); + } + Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP); + instance.setUnknownSchemaNodes(unknownNodes); + + // AUGMENTATIONS + final Set augmentations = new HashSet(); + 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 getUsesNodes() { + return addedUsesNodes; + } + + @Override + public void addUsesNode(UsesNodeBuilder usesNodeBuilder) { + addedUsesNodes.add(usesNodeBuilder); + } + + @Override + public Set 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 childNodes = Collections.emptyMap(); + private Set augmentations = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private List 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List unknownNodes) { + if (unknownNodes != null) { + this.unknownNodes = unknownNodes; + } + } + + /** + * Always returns an empty set, because case node can not contains type + * definitions. + */ + @Override + public Set> getTypeDefinitions() { + return Collections.emptySet(); + } + + @Override + public Set getChildNodes() { + return new HashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set 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 entry : childNodes.entrySet()) { + if (entry.getKey().getLocalName().equals(name)) { + result = entry.getValue(); + break; + } + } + return result; + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if (uses != null) { + this.uses = uses; + } + } + + @Override + public Set getAvailableAugmentations() { + return augmentations; + } + + private void setAvailableAugmentations(Set 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 index 0000000000..b2f1dff3a5 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ConstraintsBuilder.java @@ -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 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(); + } + + @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 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 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 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 getMustConstraints() { + if (mustConstraints == null) { + return Collections.emptySet(); + } else { + return mustConstraints; + } + } + + private void setMustConstraints(Set 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 index 0000000000..0bc56d430a --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ContainerSchemaNodeBuilder.java @@ -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> typedefs; + private final Set addedTypedefs = new HashSet(); + private Set usesNodes; + private final Set addedUsesNodes = new HashSet(); + // AugmentationTarget args + private Set augmentations; + private final Set addedAugmentations = new HashSet(); + // 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 childs = new TreeMap(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(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder builder : addedGroupings) { + groupings.add(builder.build()); + } + } + instance.setGroupings(groupings); + + // TYPEDEFS + if (typedefs == null) { + typedefs = new TreeSet>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder entry : addedTypedefs) { + typedefs.add(entry.build()); + } + } + instance.setTypeDefinitions(typedefs); + + // USES + if (usesNodes == null) { + usesNodes = new HashSet(); + for (UsesNodeBuilder builder : addedUsesNodes) { + usesNodes.add(builder.build()); + } + } + instance.setUses(usesNodes); + + // AUGMENTATIONS + if (augmentations == null) { + augmentations = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugmentations) { + augmentations.add(builder.build()); + } + } + instance.setAvailableAugmentations(augmentations); + + // UNKNOWN NODES + if (unknownNodes == null) { + unknownNodes = new ArrayList(); + 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 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> typedefs) { + this.typedefs = typedefs; + } + + public Set getAugmentations() { + return addedAugmentations; + } + + @Override + public void addAugmentation(AugmentationSchemaBuilder augment) { + addedAugmentations.add(augment); + } + + public void setAugmentations(final Set 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 getUsesNodes() { + return addedUsesNodes; + } + + @Override + public void addUsesNode(UsesNodeBuilder usesNodeBuilder) { + addedUsesNodes.add(usesNodeBuilder); + } + + public void setUsesnodes(final Set 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 augmentations = Collections.emptySet(); + private Map childNodes = Collections.emptyMap(); + private Set groupings = Collections.emptySet(); + private Set> typeDefinitions = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private List 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 getAvailableAugmentations() { + return augmentations; + } + + private void setAvailableAugmentations(Set augmentations) { + if (augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public Set getChildNodes() { + return new HashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set 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 entry : childNodes.entrySet()) { + if (entry.getKey().getLocalName().equals(name)) { + result = entry.getValue(); + break; + } + } + return result; + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if (uses != null) { + this.uses = uses; + } + } + + @Override + public boolean isPresenceContainer() { + return presence; + } + + private void setPresenceContainer(boolean presence) { + this.presence = presence; + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + if (typeDefinitions != null) { + this.typeDefinitions = typeDefinitions; + } + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..3bc9879de7 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/DeviationBuilder.java @@ -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 addedUnknownNodes = new ArrayList(); + + 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 unknownNodes = new ArrayList(); + 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..93a34e1050 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ExtensionBuilder.java @@ -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(); + 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..dd3fd11e92 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/FeatureBuilder.java @@ -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(); + 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(final List 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 index 0000000000..8a8f1211cb --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/GroupingBuilderImpl.java @@ -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> typedefs; + private final Set addedTypedefs = new HashSet(); + + private Set usesNodes; + private final Set addedUsesNodes = new HashSet(); + + 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 childs = new TreeMap(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(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder builder : addedGroupings) { + groupings.add(builder.build()); + } + } + instance.setGroupings(groupings); + + // TYPEDEFS + if (typedefs == null) { + typedefs = new TreeSet>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder entry : addedTypedefs) { + typedefs.add(entry.build()); + } + } + instance.setTypeDefinitions(typedefs); + + // USES + if (usesNodes == null) { + usesNodes = new HashSet(); + for (UsesNodeBuilder builder : addedUsesNodes) { + usesNodes.add(builder.build()); + } + } + instance.setUses(usesNodes); + + // UNKNOWN NODES + if (unknownNodes == null) { + unknownNodes = new ArrayList(); + 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 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> 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 getUses() { + return addedUsesNodes; + } + + @Override + public void addUsesNode(final UsesNodeBuilder usesBuilder) { + addedUsesNodes.add(usesBuilder); + } + + public void setUsesnodes(final Set 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 childNodes = Collections.emptyMap(); + private Set groupings = Collections.emptySet(); + private Set> typeDefinitions = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private List 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 getChildNodes() { + final Set result = new TreeSet(Comparators.SCHEMA_NODE_COMP); + result.addAll(childNodes.values()); + return result; + } + + private void setChildNodes(Map childNodes) { + this.childNodes = childNodes; + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + this.groupings = groupings; + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + this.uses = uses; + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + this.typeDefinitions = typeDefinitions; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 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 index 0000000000..2e7c495d9e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentitySchemaNodeBuilder.java @@ -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(); + 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..ca6002930e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/IdentityrefTypeBuilder.java @@ -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 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 getRanges() { + return Collections.emptyList(); + } + + @Override + public void setRanges(List ranges) { + throw new YangParseException(moduleName, line, "Can not set ranges to " + NAME); + } + + @Override + public List getLengths() { + return Collections.emptyList(); + } + + @Override + public void setLengths(List lengths) { + throw new YangParseException(moduleName, line, "Can not set lengths to " + NAME); + } + + @Override + public List getPatterns() { + return Collections.emptyList(); + } + + @Override + public void setPatterns(List 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 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 index 0000000000..8e11ad2217 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafListSchemaNodeBuilder.java @@ -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(); + 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 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> type) { + this.type = type; + } + + @Override + public boolean isUserOrdered() { + return userOrdered; + } + + private void setUserOrdered(boolean userOrdered) { + this.userOrdered = userOrdered; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..5c1da11afa --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/LeafSchemaNodeBuilder.java @@ -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(); + 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 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> type) { + this.type = type; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..5e369d0826 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ListSchemaNodeBuilder.java @@ -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> typedefs; + private final Set addedTypedefs = new HashSet(); + private Set usesNodes; + private final Set addedUsesNodes = new HashSet(); + // AugmentationTarget args + private Set augmentations; + private final Set addedAugmentations = new HashSet(); + // ListSchemaNode args + private List 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 childs = new TreeMap(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>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder entry : addedTypedefs) { + typedefs.add(entry.build()); + } + } + instance.setTypeDefinitions(typedefs); + + // USES + if (usesNodes == null) { + usesNodes = new HashSet(); + for (UsesNodeBuilder builder : addedUsesNodes) { + usesNodes.add(builder.build()); + } + } + instance.setUses(usesNodes); + + // GROUPINGS + if (groupings == null) { + groupings = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder builder : addedGroupings) { + groupings.add(builder.build()); + } + } + instance.setGroupings(groupings); + + // AUGMENTATIONS + if (augmentations == null) { + augmentations = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugmentations) { + augmentations.add(builder.build()); + } + } + instance.setAvailableAugmentations(augmentations); + + // UNKNOWN NODES + if (unknownNodes == null) { + unknownNodes = new ArrayList(); + 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 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> 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 getUsesNodes() { + return addedUsesNodes; + } + + @Override + public void addUsesNode(final UsesNodeBuilder usesBuilder) { + addedUsesNodes.add(usesBuilder); + } + + public void setUsesnodes(final Set usesNodes) { + this.usesNodes = usesNodes; + } + + public Set getAugmentations() { + return addedAugmentations; + } + + @Override + public void addAugmentation(AugmentationSchemaBuilder augment) { + addedAugmentations.add(augment); + } + + public void setAugmentations(final Set augmentations) { + this.augmentations = augmentations; + } + + public List getKeyDefinition() { + return keyDefinition; + } + + public void setKeyDefinition(final List 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 keyDefinition = Collections.emptyList(); + private boolean augmenting; + private boolean addedByUses; + private boolean configuration; + private ConstraintDefinition constraints; + private Set augmentations = Collections.emptySet(); + private Map childNodes = Collections.emptyMap(); + private Set> typeDefinitions = Collections.emptySet(); + private Set groupings = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private boolean userOrdered; + private List 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 getKeyDefinition() { + return keyDefinition; + } + + private void setKeyDefinition(List 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 getAvailableAugmentations() { + return augmentations; + } + + private void setAvailableAugmentations(Set augmentations) { + if (augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public Set getChildNodes() { + return new HashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + if (groupings != null) { + this.groupings = groupings; + } + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + if (typeDefinitions != null) { + this.typeDefinitions = typeDefinitions; + } + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..80fe524fed --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/ModuleBuilder.java @@ -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 actualPath = new LinkedList(); + private final Set dirtyNodes = new HashSet(); + + private final Set imports = new HashSet(); + private final List addedAugments = new ArrayList(); + private final List allAugments = new ArrayList(); + private final Set addedUsesNodes = new HashSet(); + private final List allUsesNodes = new ArrayList(); + private final Set addedRpcs = new HashSet(); + private final Set addedNotifications = new HashSet(); + private final Set addedIdentities = new HashSet(); + private final Set addedFeatures = new HashSet(); + private final Set addedDeviations = new HashSet(); + private final Set addedTypedefs = new HashSet(); + private final List addedExtensions = new ArrayList(); + private final List allUnknownNodes = new ArrayList(); + + 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> typedefs = new TreeSet>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder tdb : addedTypedefs) { + typedefs.add(tdb.build()); + } + instance.setTypeDefinitions(typedefs); + + // CHILD NODES + final Map children = new TreeMap(Comparators.QNAME_COMP); + for (DataSchemaNodeBuilder child : addedChildNodes) { + children.put(child.getQName(), child.build()); + } + instance.setChildNodes(children); + + // GROUPINGS + final Set groupings = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder gb : addedGroupings) { + groupings.add(gb.build()); + } + instance.setGroupings(groupings); + + // USES + final Set usesDefinitions = new HashSet(); + for (UsesNodeBuilder unb : addedUsesNodes) { + usesDefinitions.add(unb.build()); + } + instance.setUses(usesDefinitions); + + // FEATURES + final Set features = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (FeatureBuilder fb : addedFeatures) { + features.add(fb.build()); + } + instance.setFeatures(features); + + // NOTIFICATIONS + final Set notifications = new TreeSet( + Comparators.SCHEMA_NODE_COMP); + for (NotificationBuilder entry : addedNotifications) { + notifications.add(entry.build()); + } + instance.setNotifications(notifications); + + // AUGMENTATIONS + final Set augmentations = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugments) { + augmentations.add(builder.build()); + } + instance.setAugmentations(augmentations); + + // RPCs + final Set rpcs = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (RpcDefinitionBuilder rpc : addedRpcs) { + rpcs.add(rpc.build()); + } + instance.setRpcs(rpcs); + + // DEVIATIONS + final Set deviations = new HashSet(); + for (DeviationBuilder entry : addedDeviations) { + deviations.add(entry.build()); + } + instance.setDeviations(deviations); + + // EXTENSIONS + final List extensions = new ArrayList(); + for (ExtensionBuilder eb : addedExtensions) { + extensions.add(eb.build()); + } + Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP); + instance.setExtensionSchemaNodes(extensions); + + // IDENTITIES + final Set identities = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (IdentitySchemaNodeBuilder id : addedIdentities) { + identities.add(id.build()); + } + instance.setIdentities(identities); + + // UNKNOWN NODES + final List unknownNodes = new ArrayList(); + 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 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 getDirtyNodes() { + return dirtyNodes; + } + + public List getAllAugments() { + return allAugments; + } + + public Set getIdentities() { + return addedIdentities; + } + + public List getAllUsesNodes() { + return allUsesNodes; + } + + public Set getDeviations() { + return addedDeviations; + } + + public List 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 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 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 imports = Collections.emptySet(); + private Set features = Collections.emptySet(); + private Set> typeDefinitions = Collections.emptySet(); + private Set notifications = Collections.emptySet(); + private Set augmentations = Collections.emptySet(); + private Set rpcs = Collections.emptySet(); + private Set deviations = Collections.emptySet(); + private Map childNodes = Collections.emptyMap(); + private Set groupings = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private List extensionNodes = Collections.emptyList(); + private Set identities = Collections.emptySet(); + private List 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 getImports() { + return imports; + } + + private void setImports(Set imports) { + if (imports != null) { + this.imports = imports; + } + } + + @Override + public Set getFeatures() { + return features; + } + + private void setFeatures(Set features) { + if (features != null) { + this.features = features; + } + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + if (typeDefinitions != null) { + this.typeDefinitions = typeDefinitions; + } + } + + @Override + public Set getNotifications() { + return notifications; + } + + private void setNotifications(Set notifications) { + if (notifications != null) { + this.notifications = notifications; + } + } + + @Override + public Set getAugmentations() { + return augmentations; + } + + private void setAugmentations(Set augmentations) { + if (augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public Set getRpcs() { + return rpcs; + } + + private void setRpcs(Set rpcs) { + if (rpcs != null) { + this.rpcs = rpcs; + } + } + + @Override + public Set getDeviations() { + return deviations; + } + + private void setDeviations(Set deviations) { + if (deviations != null) { + this.deviations = deviations; + } + } + + @Override + public Set getChildNodes() { + return new LinkedHashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + if (groupings != null) { + this.groupings = groupings; + } + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if (uses != null) { + this.uses = uses; + } + } + + @Override + public List getExtensionSchemaNodes() { + return extensionNodes; + } + + private void setExtensionSchemaNodes(final List extensionNodes) { + if (extensionNodes != null) { + this.extensionNodes = extensionNodes; + } + } + + @Override + public Set getIdentities() { + return identities; + } + + private void setIdentities(final Set identities) { + if (identities != null) { + this.identities = identities; + } + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(final List 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 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 index 0000000000..eab1cffceb --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/NotificationBuilder.java @@ -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 addedTypedefs = new HashSet(); + private final Set addedUsesNodes = new HashSet(); + private Set augmentations; + private final Set addedAugmentations = new HashSet(); + + 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 childs = new TreeMap(Comparators.QNAME_COMP); + for (DataSchemaNodeBuilder node : addedChildNodes) { + childs.put(node.getQName(), node.build()); + } + instance.setChildNodes(childs); + + // GROUPINGS + final Set groupingDefs = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder builder : addedGroupings) { + groupingDefs.add(builder.build()); + } + instance.setGroupings(groupingDefs); + + // TYPEDEFS + final Set> typedefs = new TreeSet>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder entry : addedTypedefs) { + typedefs.add(entry.build()); + } + instance.setTypeDefinitions(typedefs); + + // USES + final Set uses = new HashSet(); + for (UsesNodeBuilder builder : addedUsesNodes) { + uses.add(builder.build()); + } + instance.setUses(uses); + + // AUGMENTATIONS + if (augmentations == null) { + augmentations = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugmentations) { + augmentations.add(builder.build()); + } + } + instance.setAvailableAugmentations(augmentations); + + // UNKNOWN NODES + final List unknownNodes = new ArrayList(); + 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 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 getAugmentations() { + return addedAugmentations; + } + + @Override + public void addAugmentation(AugmentationSchemaBuilder augment) { + addedAugmentations.add(augment); + } + + public void setAugmentations(final Set 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 childNodes = Collections.emptyMap(); + private Set groupings = Collections.emptySet(); + private Set> typeDefinitions = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private Set augmentations = Collections.emptySet(); + private List 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 getChildNodes() { + return new HashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if (childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + if (groupings != null) { + this.groupings = groupings; + } + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if (uses != null) { + this.uses = uses; + } + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(final Set> typeDefinitions) { + if (typeDefinitions != null) { + this.typeDefinitions = typeDefinitions; + } + } + + @Override + public Set getAvailableAugmentations() { + return augmentations; + } + + private void setAvailableAugmentations(Set augmentations) { + if (augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(final List 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 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 index 0000000000..53190d0bb6 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/RpcDefinitionBuilder.java @@ -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 addedTypedefs = new HashSet(); + private final Set addedGroupings = new HashSet(); + + 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> typedefs = new TreeSet>(Comparators.SCHEMA_NODE_COMP); + for (TypeDefinitionBuilder entry : addedTypedefs) { + typedefs.add(entry.build()); + } + instance.setTypeDefinitions(typedefs); + + // GROUPINGS + final Set groupings = new TreeSet(Comparators.SCHEMA_NODE_COMP); + for (GroupingBuilder entry : addedGroupings) { + groupings.add(entry.build()); + } + instance.setGroupings(groupings); + + // UNKNOWN NODES + if (unknownNodes == null) { + unknownNodes = new ArrayList(); + 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 getTypeDefinitions() { + return addedTypedefs; + } + + public void addTypedef(final TypeDefinitionBuilder type) { + addedTypedefs.add(type); + } + + public Set 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> typeDefinitions; + private Set groupings; + private List 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> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + this.typeDefinitions = typeDefinitions; + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + this.groupings = groupings; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List 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 index 0000000000..5f2ca1c028 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/TypeDefinitionBuilderImpl.java @@ -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 ranges = Collections.emptyList(); + private List lengths = Collections.emptyList(); + private List 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> 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(); + 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 getUnknownNodes() { + return Collections.emptyList(); + } + + @Override + public List getRanges() { + return ranges; + } + + @Override + public void setRanges(final List ranges) { + if (ranges != null) { + this.ranges = ranges; + } + } + + @Override + public List getLengths() { + return lengths; + } + + @Override + public void setLengths(final List lengths) { + if (lengths != null) { + this.lengths = lengths; + } + } + + @Override + public List getPatterns() { + return patterns; + } + + @Override + public void setPatterns(final List 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 index 0000000000..6c57c25b98 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnionTypeBuilder.java @@ -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> types; + private final List 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>(); + typedefs = new ArrayList(); + } + + public List> getTypes() { + return types; + } + + @Override + public TypeDefinition getType() { + return null; + } + + public List 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 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 getRanges() { + return Collections.emptyList(); + } + + @Override + public void setRanges(List ranges) { + throw new YangParseException(moduleName, line, "Can not set ranges to " + NAME); + } + + @Override + public List getLengths() { + return Collections.emptyList(); + } + + @Override + public void setLengths(List lengths) { + throw new YangParseException(moduleName, line, "Can not set lengths to " + NAME); + } + + @Override + public List getPatterns() { + return Collections.emptyList(); + } + + @Override + public void setPatterns(List 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 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 index 0000000000..e7b344b6fd --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UnknownSchemaNodeBuilder.java @@ -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(); + 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 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 getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(final List 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 index 0000000000..ee07e8be46 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/builder/impl/UsesNodeBuilderImpl.java @@ -0,0 +1,335 @@ +/* + * 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.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.yang.model.api.AugmentationSchema; +import org.opendaylight.controller.yang.model.api.SchemaNode; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.api.UsesNode; +import org.opendaylight.controller.yang.parser.builder.api.AbstractBuilder; +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.SchemaNodeBuilder; +import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder; +import org.opendaylight.controller.yang.parser.util.RefineHolder; +import org.opendaylight.controller.yang.parser.util.YangParseException; + +public final class UsesNodeBuilderImpl extends AbstractBuilder implements UsesNodeBuilder { + private boolean isBuilt; + private UsesNodeImpl instance; + private DataNodeContainerBuilder parent; + private final String groupingName; + private SchemaPath groupingPath; + private boolean augmenting; + private boolean addedByUses; + private final Set addedAugments = new HashSet(); + private final List refineBuilders = new ArrayList(); + private final List refines = new ArrayList(); + + public UsesNodeBuilderImpl(final String moduleName, final int line, final String groupingName) { + super(moduleName, line); + this.groupingName = groupingName; + } + + public UsesNodeBuilderImpl(UsesNodeBuilder b) { + super(b.getModuleName(), b.getLine()); + groupingName = b.getGroupingName(); + parent = b.getParent(); + groupingPath = b.getGroupingPath(); + augmenting = b.isAugmenting(); + addedByUses = b.isAddedByUses(); + addedAugments.addAll(b.getAugmentations()); + refineBuilders.addAll(b.getRefineNodes()); + refines.addAll(b.getRefines()); + } + + @Override + public UsesNode build() { + if (!isBuilt) { + instance = new UsesNodeImpl(groupingPath); + instance.setAugmenting(augmenting); + instance.setAddedByUses(addedByUses); + + // AUGMENTATIONS + final Set augments = new HashSet(); + for (AugmentationSchemaBuilder builder : addedAugments) { + augments.add(builder.build()); + } + instance.setAugmentations(augments); + + // REFINES + final Map refineNodes = new HashMap(); + for (SchemaNodeBuilder refineBuilder : refineBuilders) { + SchemaNode refineNode = refineBuilder.build(); + refineNodes.put(refineNode.getPath(), refineNode); + } + instance.setRefines(refineNodes); + + // UNKNOWN NODES + List unknownNodes = new ArrayList(); + for (UnknownSchemaNodeBuilder b : addedUnknownNodes) { + unknownNodes.add(b.build()); + } + instance.setUnknownSchemaNodes(unknownNodes); + + isBuilt = true; + } + return instance; + } + + @Override + public DataNodeContainerBuilder getParent() { + return parent; + } + + @Override + public void setParent(Builder parent) { + if (!(parent instanceof DataNodeContainerBuilder)) { + throw new YangParseException(moduleName, line, "Unresolved parent of uses '" + groupingName + "'."); + } + this.parent = (DataNodeContainerBuilder) parent; + } + + @Override + public SchemaPath getGroupingPath() { + return groupingPath; + } + + @Override + public void setGroupingPath(SchemaPath groupingPath) { + this.groupingPath = groupingPath; + } + + @Override + public String getGroupingName() { + return groupingName; + } + + @Override + public Set getAugmentations() { + return addedAugments; + } + + @Override + public void addAugment(final AugmentationSchemaBuilder augmentBuilder) { + addedAugments.add(augmentBuilder); + } + + @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 List getRefineNodes() { + return refineBuilders; + } + + @Override + public void addRefineNode(SchemaNodeBuilder refineNode) { + refineBuilders.add(refineNode); + } + + @Override + public List getRefines() { + return refines; + } + + @Override + public void addRefine(RefineHolder refine) { + refines.add(refine); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((groupingName == null) ? 0 : groupingName.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; + UsesNodeBuilderImpl other = (UsesNodeBuilderImpl) obj; + if (groupingName == null) { + if (other.groupingName != null) + return false; + } else if (!groupingName.equals(other.groupingName)) + return false; + + if (parent == null) { + if (other.parent != null) + return false; + } else if (!parent.equals(other.parent)) + return false; + if (refines == null) { + if (other.refines != null) + return false; + } else if (!refines.equals(other.refines)) + return false; + return true; + } + + @Override + public String toString() { + return "uses '" + groupingName + "'"; + } + + public final class UsesNodeImpl implements UsesNode { + private final SchemaPath groupingPath; + private Set augmentations = Collections.emptySet(); + private boolean augmenting; + private boolean addedByUses; + private Map refines = Collections.emptyMap(); + private List unknownNodes = Collections.emptyList(); + + private UsesNodeImpl(final SchemaPath groupingPath) { + this.groupingPath = groupingPath; + } + + @Override + public SchemaPath getGroupingPath() { + return groupingPath; + } + + @Override + public Set getAugmentations() { + return augmentations; + } + + private void setAugmentations(final Set augmentations) { + if (augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public boolean isAugmenting() { + return augmenting; + } + + private void setAugmenting(final boolean augmenting) { + this.augmenting = augmenting; + } + + @Override + public boolean isAddedByUses() { + return addedByUses; + } + + private void setAddedByUses(final boolean addedByUses) { + this.addedByUses = addedByUses; + } + + @Override + public Map getRefines() { + return refines; + } + + private void setRefines(Map refines) { + if (refines != null) { + this.refines = refines; + } + } + + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + private void setUnknownSchemaNodes(List unknownSchemaNodes) { + if (unknownSchemaNodes != null) { + this.unknownNodes = unknownSchemaNodes; + } + } + + public UsesNodeBuilder toBuilder() { + return UsesNodeBuilderImpl.this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((groupingPath == null) ? 0 : groupingPath.hashCode()); + result = prime * result + ((augmentations == null) ? 0 : augmentations.hashCode()); + result = prime * result + (augmenting ? 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; + } + final UsesNodeImpl other = (UsesNodeImpl) obj; + if (groupingPath == null) { + if (other.groupingPath != null) { + return false; + } + } else if (!groupingPath.equals(other.groupingPath)) { + return false; + } + if (augmentations == null) { + if (other.augmentations != null) { + return false; + } + } else if (!augmentations.equals(other.augmentations)) { + return false; + } + if (augmenting != other.augmenting) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(UsesNodeImpl.class.getSimpleName()); + sb.append("[groupingPath=" + groupingPath + "]"); + return sb.toString(); + } + } + +} 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 index 0000000000..611d2ce1bd --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/SchemaContextImpl.java @@ -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 modules; + + SchemaContextImpl(final Set modules) { + this.modules = modules; + } + + @Override + public Set getDataDefinitions() { + final Set dataDefs = new HashSet(); + for (Module m : modules) { + dataDefs.addAll(m.getChildNodes()); + } + return dataDefs; + } + + @Override + public Set getModules() { + return modules; + } + + @Override + public Set getNotifications() { + final Set notifications = new HashSet(); + for (Module m : modules) { + notifications.addAll(m.getNotifications()); + } + return notifications; + } + + @Override + public Set getOperations() { + final Set rpcs = new HashSet(); + for (Module m : modules) { + rpcs.addAll(m.getRpcs()); + } + return rpcs; + } + + @Override + public Set getExtensions() { + final Set extensions = new HashSet(); + 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 index 0000000000..2725162d0a --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangErrorListener.java @@ -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 index 0000000000..065d270f09 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserImpl.java @@ -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 parseYangModels(final List yangFiles) { + return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values()); + } + + @Override + public Set parseYangModels(final List yangFiles, final SchemaContext context) { + if (yangFiles != null) { + final Map 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 builderToStreamMap = Maps.newHashMap(); + + final Map> 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(buildWithContext(modules, context).values()); + } + return Collections.emptySet(); + } + + @Override + public Set parseYangModelsFromStreams(final List yangModelStreams) { + return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values()); + } + + @Override + public Set parseYangModelsFromStreams(final List yangModelStreams, SchemaContext context) { + if (yangModelStreams != null) { + Map builderToStreamMap = Maps.newHashMap(); + final Map> modules = resolveModuleBuildersWithContext( + yangModelStreams, builderToStreamMap, context); + return new LinkedHashSet(buildWithContext(modules, context).values()); + } + return Collections.emptySet(); + } + + @Override + public Map parseYangModelsMapped(List yangFiles) { + if (yangFiles != null) { + final Map 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 builderToStreamMap = Maps.newHashMap(); + final Map> 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 retVal = Maps.newLinkedHashMap(); + Map builderToModuleMap = build(modules); + + for (Entry builderToModule : builderToModuleMap.entrySet()) { + retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())), + builderToModule.getValue()); + } + + return retVal; + } + return Collections.emptyMap(); + } + + @Override + public Map parseYangModelsFromStreamsMapped(final List yangModelStreams) { + Map builderToStreamMap = Maps.newHashMap(); + + final Map> modules = resolveModuleBuilders(yangModelStreams, + builderToStreamMap); + Map retVal = Maps.newLinkedHashMap(); + Map builderToModuleMap = build(modules); + + for (Entry builderToModule : builderToModuleMap.entrySet()) { + retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue()); + } + return retVal; + } + + @Override + public SchemaContext resolveSchemaContext(final Set modules) { + return new SchemaContextImpl(modules); + } + + private ModuleBuilder[] parseModuleBuilders(List inputStreams, + Map streamToBuilderMap) { + + final ParseTreeWalker walker = new ParseTreeWalker(); + final List 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> resolveModuleBuilders(final List yangFileStreams, + Map streamToBuilderMap) { + return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null); + } + + private Map> resolveModuleBuildersWithContext( + final List yangFileStreams, final Map 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> modules = new LinkedHashMap>(); + + // module dependency graph sorted + List 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 builderByRevision = modules.get(builderName); + if (builderByRevision == null) { + builderByRevision = new TreeMap(); + } + builderByRevision.put(builderRevision, builder); + modules.put(builderName, builderByRevision); + } + return modules; + } + + private List parseStreams(final List yangStreams) { + final List trees = new ArrayList(); + 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 build(final Map> modules) { + // fix unresolved nodes + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry 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 result = new LinkedHashMap(); + for (Map.Entry> entry : modules.entrySet()) { + final Map modulesByRevision = new HashMap(); + for (Map.Entry 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 buildWithContext(final Map> modules, + SchemaContext context) { + // fix unresolved nodes + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry 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 result = new LinkedHashMap(); + for (Map.Entry> entry : modules.entrySet()) { + final Map modulesByRevision = new HashMap(); + for (Map.Entry 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> modules, final ModuleBuilder builder) { + resolveDirtyNodes(modules, builder); + resolveIdentities(modules, builder); + resolveUsesRefine(modules, builder); + resolveUnknownNodes(modules, builder); + } + + private void fixUnresolvedNodesWithContext(final Map> 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> modules, final ModuleBuilder module) { + final Set 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> modules, + final ModuleBuilder module, SchemaContext context) { + final Set 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> 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> 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> 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> modules, final ModuleBuilder builder) { + + final List> unionTypes = union.getTypes(); + final List> toRemove = new ArrayList>(); + 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> modules, final ModuleBuilder builder, + final SchemaContext context) { + + final List> unionTypes = union.getTypes(); + final List> toRemove = new ArrayList>(); + 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> 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> 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> modules) { + final List allModulesList = new ArrayList(); + final Set allModulesSet = new HashSet(); + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry 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 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> 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 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> modules, + final SchemaContext context) { + final List allModulesList = new ArrayList(); + final Set allModulesSet = new HashSet(); + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry 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 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> 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 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> modules, final ModuleBuilder module) { + final Set 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 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> modules, + final ModuleBuilder module, final SchemaContext context) { + final Set 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 dependentModuleIdentities = dependentModule.getIdentities(); + for (IdentitySchemaNode idNode : dependentModuleIdentities) { + if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) { + identity.setBaseIdentity(idNode); + } + } + } else { + final Set 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> modules, final ModuleBuilder module) { + final List 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> modules, + final ModuleBuilder module, final SchemaContext context) { + final List 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> 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 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 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 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> 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> 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> 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> modules) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { + ModuleBuilder b = inner.getValue(); + resolveDeviation(modules, b); + } + } + } + + private void resolveDeviation(final Map> modules, final ModuleBuilder module) { + for (DeviationBuilder dev : module.getDeviations()) { + int line = dev.getLine(); + SchemaPath targetPath = dev.getTargetPath(); + List 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> modules, + final SchemaContext context) { + for (Map.Entry> entry : modules.entrySet()) { + for (Map.Entry inner : entry.getValue().entrySet()) { + ModuleBuilder b = inner.getValue(); + resolveDeviationWithContext(modules, b, context); + } + } + } + + private void resolveDeviationWithContext(final Map> modules, + final ModuleBuilder module, final SchemaContext context) { + for (DeviationBuilder dev : module.getDeviations()) { + int line = dev.getLine(); + SchemaPath targetPath = dev.getTargetPath(); + List 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 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 index 0000000000..b6944d1a70 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/impl/YangParserListenerImpl.java @@ -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 actualPath = new Stack(); + + @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 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 index 0000000000..c6bbc6557e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/BitImpl.java @@ -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 unknownNodes = Collections.emptyList(); + + BitImpl(final Long position, final QName qname, + final SchemaPath schemaPath, final String description, + final String reference, final Status status, + final List 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 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 index 0000000000..ea87eec4e9 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/Comparators.java @@ -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 { + @Override + public int compare(QName o1, QName o2) { + return o1.getLocalName().compareTo(o2.getLocalName()); + } + } + + private static final class SchemaNodeComparator implements Comparator { + @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 index 0000000000..aea9409714 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySort.java @@ -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 sort(ModuleBuilder... builders) { + List sorted = sortInternal(Arrays.asList(builders)); + // Cast to ModuleBuilder from Node and return + return Lists.transform(sorted, new Function() { + + @Override + public ModuleBuilder apply(Node input) { + return (ModuleBuilder) ((ModuleNodeImpl) input).getReference(); + } + }); + } + + public static List sortWithContext(SchemaContext context, ModuleBuilder... builders) { + List modules = new ArrayList(); + Collections.addAll(modules, builders); + modules.addAll(context.getModules()); + + List sorted = sortInternal(modules); + // Cast to ModuleBuilder from Node if possible and return + return Lists.transform(sorted, new Function() { + + @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 sort(Module... modules) { + List sorted = sortInternal(Arrays.asList(modules)); + // Cast to Module from Node and return + return Lists.transform(sorted, new Function() { + + @Override + public Module apply(Node input) { + return (Module) ((ModuleNodeImpl) input).getReference(); + } + }); + } + + private static List sortInternal(List modules) { + Map> moduleGraph = createModuleGraph(modules); + + Set nodes = Sets.newHashSet(); + for (Map map : moduleGraph.values()) { + for (ModuleNodeImpl node : map.values()) { + nodes.add(node); + } + } + + return TopologicalSort.sort(nodes); + } + + @VisibleForTesting + static Map> createModuleGraph(List builders) { + Map> moduleGraph = Maps.newHashMap(); + + processModules(moduleGraph, builders); + processDependencies(moduleGraph, builders); + + return moduleGraph; + } + + /** + * Extract module:revision from module builders + */ + private static void processDependencies(Map> moduleGraph, List builders) { + Map imported = Maps.newHashMap(); + + // Create edges in graph + for (Object mb : builders) { + + String fromName = null; + Date fromRevision = null; + Set 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> 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> 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. 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 index 0000000000..977b3fffcd --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/MustDefinitionImpl.java @@ -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 index 0000000000..d2ca3a7695 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserListenerUtils.java @@ -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 actualPath, final URI namespace, + final Date revision, final String prefix, final String... names) { + final List path = new ArrayList(); + 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 path = new ArrayList(); + 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 createListKey(final String keyDefinition, final URI namespace, final Date revision, + final String prefix) { + List key = new ArrayList(); + 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 getEnumConstants(final Type_body_stmtsContext ctx, + final List path, final String moduleName, final URI namespace, final Date revision, final String prefix) { + List enumConstants = new ArrayList(); + + 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 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 enumPairPath = new ArrayList(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 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 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 getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) { + List 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 parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) { + final int line = ctx.getStart().getLine(); + List rangeConstraints = new ArrayList(); + 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 getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) { + List 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 parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) { + final int line = ctx.getStart().getLine(); + List lengthConstraints = new ArrayList(); + 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 getPatternConstraint(final Type_body_stmtsContext ctx) { + List patterns = new ArrayList(); + + 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 getBits(Type_body_stmtsContext ctx, List actualPath, + String moduleName, URI namespace, Date revision, String prefix) { + final List bits = new ArrayList(); + 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 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 bitPath = new Stack(); + 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 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 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 rangeStatements = getRangeConstraints(ctx, moduleName); + List lengthStatements = getLengthConstraints(ctx, moduleName); + List 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 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 lengthStatements = getLengthConstraints(typeBody, moduleName); + List patternStatements = getPatternConstraint(typeBody); + List 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 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 actualPath, final URI namespace, + final Date revision, final String prefix, final String typeName, final boolean isBaseYangType, + final boolean isBaseYangTypeFinal) { + List typePath = new ArrayList(actualPath); + if (isBaseYangType && !isBaseYangTypeFinal) { + typePath.add(typeName); + } + + final List path = new ArrayList(); + 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 index 0000000000..4fc58b3d98 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/ParserUtils.java @@ -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 path = new ArrayList(); + 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> 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 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 modulesByRevision = new TreeMap(); + + 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 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 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 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> 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 path = new ArrayList(); + 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 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 grps = grouping.getGroupingBuilders(); + for (GroupingBuilder gr : grps) { + if (gr.getQName().getLocalName().equals(refineNodeName)) { + result = gr; + break; + } + } + } + // search typedefs + if (result == null) { + Set 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 grps = builder.getGroupings(); + for (GroupingDefinition gr : grps) { + if (gr.getQName().getLocalName().equals(refineNodeName)) { + result = gr; + break; + } + } + } + if (result == null) { + Set> 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 targetNodePath = new ArrayList(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 lengths = null; + List patterns = null; + List 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 lengths, + final List patterns, final List 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 bytes = (List) binType.getDefaultValue(); + // workaround to get rid of 'Unchecked cast' warning + List bytes = new ArrayList(); + 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 path = schemaPath.getPath(); + final List newPath = new ArrayList(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 newPath = new ArrayList(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 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 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 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 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> 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> 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 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 index 0000000000..9e57d80aa9 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineHolder.java @@ -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 index 0000000000..11d00cc05c --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/RefineUtils.java @@ -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. + *

+ * 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}. + *

+ * + * @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 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 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 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 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 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 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: + *
    + *
  • description
  • + *
  • reference
  • + *
  • config
  • + *
+ * + * 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 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 index 0000000000..2ea289a0f7 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TopologicalSort.java @@ -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 sort(Set nodes) { + List sortedNodes = Lists.newArrayList(); + + Set 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 getDependentNodes(Set nodes) { + Set S = Sets.newHashSet(); + for (Node n : nodes) { + if (n.getOutEdges().size() == 0) { + S.add(n); + } + } + return S; + } + + private static void detectCycles(Set 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 getInEdges(); + + Set 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 inEdges; + private final Set outEdges; + + @Override + public Set getInEdges() { + return inEdges; + } + + @Override + public Set 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 index 0000000000..08422c8392 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/TypeConstraints.java @@ -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> ranges = new ArrayList>(); + private final List> lengths = new ArrayList>(); + private final List> patterns = new ArrayList>(); + private final List fractionDigits = new ArrayList(); + + public TypeConstraints(final String moduleName, final int line) { + this.moduleName = moduleName; + this.line = line; + } + + List> getAllRanges() { + return ranges; + } + + public List getRange() { + if (ranges.size() < 2) { + return Collections.emptyList(); + } + + final List 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 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 act = ranges.get(i); + max = act.get(act.size() - 1).getMax(); + i++; + } + return max; + } + + public void addRanges(final List ranges) { + if (ranges != null && !(ranges.isEmpty())) { + this.ranges.add(ranges); + } + } + + public List> getAllLengths() { + return lengths; + } + + public List getLength() { + if (lengths.size() < 2) { + return Collections.emptyList(); + } + + final List 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 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 act = lengths.get(i); + max = act.get(act.size() - 1).getMax(); + i++; + } + return max; + } + + public void addLengths(final List lengths) { + if (lengths != null && !(lengths.isEmpty())) { + this.lengths.add(lengths); + } + } + + public List getPatterns() { + if(patterns.isEmpty()) { + return Collections.emptyList(); + } + return patterns.get(0); + } + + public void addPatterns(final List 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 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 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 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 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 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 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 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 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 index 0000000000..c095bba484 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/UnknownBoundaryNumber.java @@ -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 index 0000000000..6939261a57 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangParseException.java @@ -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 index 0000000000..070692612e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/parser/util/YangValidationException.java @@ -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 index 0000000000..762b910910 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/BasicValidations.java @@ -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 childType1, + Class 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 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 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> 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 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> expectedChildTypeSet = Sets + .newHashSet(); + expectedChildTypeSet.add(expectedChildType); + + checkPresentChildOfTypeInternal(parent, expectedChildTypeSet, message, + atMostOne); + } + + static void checkPresentChildOfTypes(final ParseTree parent, + final Set> 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 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> 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 expectedChildType, boolean atMostOne) { + + int foundChildrenOfType = ValidationUtil.countPresentChildrenOfType( + parent, expectedChildType); + + return atMostOne ? foundChildrenOfType == 1 ? true : false + : foundChildrenOfType != 0 ? true : false; + } + + static List getAndCheckUniqueKeys(ParseTree ctx) { + String key = ValidationUtil.getName(ctx); + ParseTree parent = ctx.getParent(); + String rootParentName = ValidationUtil.getRootParentName(ctx); + + List keyList = ValidationUtil.listKeysFromId(key); + Set 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 index 0000000000..cb5af9f349 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/ValidationUtil.java @@ -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 getDuplicates(Collection keyList) { + Set all = new HashSet(); + Set duplicates = new HashSet(); + + for (String key : keyList) { + if (!all.add(key)) + duplicates.add(key); + } + return duplicates; + } + + static List 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 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> expectedChildTypes) { + int foundChildrenOfType = 0; + + for (Class type : expectedChildTypes) { + foundChildrenOfType += countPresentChildrenOfType(parent, type); + } + return foundChildrenOfType; + } + + static int countPresentChildrenOfType(ParseTree parent, + Class 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 index 0000000000..7f270fe08e --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidationListener.java @@ -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 uniquePrefixes; + private final Set uniqueImports; + private final Set uniqueIncludes; + + private String globalModuleId; + + YangModelBasicValidationListener() { + super(); + uniquePrefixes = Sets.newHashSet(); + uniqueImports = Sets.newHashSet(); + uniqueIncludes = Sets.newHashSet(); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Header statements present(mandatory prefix and namespace statements + * are in header)
  4. + *
  5. Only one module or submodule per file
  6. + *
+ */ + @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: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Header statements present(mandatory belongs-to statement is in + * header)
  4. + *
  5. Only one module or submodule per file
  6. + *
+ */ + @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: + *
    + *
  1. One Belongs-to statement present
  2. + *
+ */ + @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: + *
    + *
  1. One Namespace statement present
  2. + *
  3. One Prefix statement present
  4. + *
+ */ + @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: + *
    + *
  1. Date is in valid format
  2. + *
+ */ + @Override + public void enterRevision_stmt(Revision_stmtContext ctx) { + BasicValidations.checkDateFormat(ctx, + YangParserListenerImpl.simpleDateFormat); + + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. One Prefix statement child
  4. + *
+ */ + @Override + public void enterBelongs_to_stmt(Belongs_to_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, + true); + } + + /** + * Constraints: + *
    + *
  1. Namespace string can be parsed as URI
  2. + *
+ */ + @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: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Every import(identified by identifier) within a module/submodule is + * present only once
  4. + *
  5. One prefix statement child
  6. + *
+ */ + @Override + public void enterImport_stmt(Import_stmtContext ctx) { + + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkUniquenessInNamespace(ctx, uniqueImports); + + BasicValidations.checkPresentChildOfType(ctx, Prefix_stmtContext.class, + true); + + } + + /** + * Constraints: + *
    + *
  1. Date is in valid format
  2. + *
+ */ + @Override + public void enterRevision_date_stmt(Revision_date_stmtContext ctx) { + BasicValidations.checkDateFormat(ctx, + YangParserListenerImpl.simpleDateFormat); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Every include(identified by identifier) within a module/submodule is + * present only once
  4. + *
+ */ + @Override + public void enterInclude_stmt(Include_stmtContext ctx) { + + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkUniquenessInNamespace(ctx, uniqueIncludes); + } + + /** + * Constraints: + *
    + *
  1. Yang-version is specified as 1
  2. + *
+ */ + @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: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Every prefix(identified by identifier) within a module/submodule is + * presented only once
  4. + *
+ */ + @Override + public void enterPrefix_stmt(Prefix_stmtContext ctx) { + + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkUniquenessInNamespace(ctx, uniquePrefixes); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. One type statement child
  4. + *
+ */ + @Override + public void enterTypedef_stmt(Typedef_stmtContext ctx) { + + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, + true); + } + + /** + * Constraints: + *
    + *
  1. (Prefix):Identifier is in required format
  2. + *
+ */ + @Override + public void enterType_stmt(Type_stmtContext ctx) { + BasicValidations.checkPrefixedIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterContainer_stmt(Container_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. One type statement child
  4. + *
  5. Default statement must not be present if mandatory statement is
  6. + *
+ */ + @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: + *
    + *
  1. Identifier is in required format
  2. + *
  3. One type statement child
  4. + *
+ */ + @Override + public void enterLeaf_list_stmt(Leaf_list_stmtContext ctx) { + + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkPresentChildOfType(ctx, Type_stmtContext.class, + true); + } + + private static final Set permittedOrderByArgs = Sets.newHashSet( + "system", "user"); + + /** + * Constraints: + *
    + *
  1. Value must be one of: system, user
  2. + *
+ */ + @Override + public void enterOrdered_by_arg(Ordered_by_argContext ctx) { + BasicValidations.checkOnlyPermittedValues(ctx, permittedOrderByArgs); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @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: + *
    + *
  1. No duplicate keys
  2. + *
+ */ + @Override + public void enterKey_stmt(Key_stmtContext ctx) { + BasicValidations.getAndCheckUniqueKeys(ctx); + } + + /** + * Constraints: + *
    + * + *
+ */ + @Override + public void enterUnique_stmt(Unique_stmtContext ctx) { + BasicValidations.getAndCheckUniqueKeys(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
  3. Default statement must not be present if mandatory statement is
  4. + *
+ */ + @Override + public void enterChoice_stmt(Choice_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + + BasicValidations.checkNotPresentBoth(ctx, Mandatory_stmtContext.class, + Default_stmtContext.class); + + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterCase_stmt(Case_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + private static final Set permittedBooleanArgs = Sets.newHashSet( + "true", "false"); + + /** + * Constraints: + *
    + *
  1. Value must be one of: true, false
  2. + *
+ */ + @Override + public void enterMandatory_arg(Mandatory_argContext ctx) { + BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterAnyxml_stmt(Anyxml_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterGrouping_stmt(Grouping_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. (Prefix):Identifier is in required format
  2. + *
+ */ + @Override + public void enterUses_stmt(Uses_stmtContext ctx) { + BasicValidations.checkPrefixedIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterRefine_stmt(Refine_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterRpc_stmt(Rpc_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterNotification_stmt(Notification_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Schema Node Identifier is in required format
  2. + *
+ */ + @Override + public void enterAugment_stmt(Augment_stmtContext ctx) { + BasicValidations.checkSchemaNodeIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterIdentity_stmt(Identity_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. (Prefix):Identifier is in required format
  2. + *
+ */ + @Override + public void enterBase_stmt(Base_stmtContext ctx) { + BasicValidations.checkPrefixedIdentifier(ctx); + + } + + /** + * Constraints: + *
    + *
  1. Value must be one of: true, false
  2. + *
+ */ + @Override + public void enterYin_element_arg(Yin_element_argContext ctx) { + BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterExtension_stmt(Extension_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterArgument_stmt(Argument_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Identifier is in required format
  2. + *
+ */ + @Override + public void enterFeature_stmt(Feature_stmtContext ctx) { + BasicValidations.checkIdentifier(ctx); + + } + + /** + * Constraints: + *
    + *
  1. (Prefix):Identifier is in required format
  2. + *
+ */ + @Override + public void enterIf_feature_stmt(If_feature_stmtContext ctx) { + BasicValidations.checkPrefixedIdentifier(ctx); + } + + /** + * Constraints: + *
    + *
  1. Schema Node Identifier is in required format
  2. + *
  3. At least one deviate-* statement child
  4. + *
+ */ + @Override + public void enterDeviation_stmt(Deviation_stmtContext ctx) { + BasicValidations.checkSchemaNodeIdentifier(ctx); + + Set> types = Sets.newHashSet(); + types.add(Deviate_add_stmtContext.class); + types.add(Deviate_add_stmtContext.class); + BasicValidations.checkPresentChildOfTypes(ctx, types, false); + } + + /** + * Constraints: + *
    + *
  1. Value must be one of: true, false
  2. + *
+ */ + @Override + public void enterConfig_arg(Config_argContext ctx) { + BasicValidations.checkOnlyPermittedValues(ctx, permittedBooleanArgs); + } + + private static final Set permittedStatusArgs = Sets.newHashSet( + "current", "deprecated", "obsolete"); + + /** + * Constraints: + *
    + *
  1. Value must be one of: "current", "deprecated", "obsolete"
  2. + *
+ */ + @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 index 0000000000..ac00bc1340 --- /dev/null +++ b/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/validator/YangModelBasicValidator.java @@ -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 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 index 0000000000..d6f635650f --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/AugmentTest.java @@ -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 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 augmentations = module1.getAugmentations(); + assertEquals(1, augmentations.size()); + AugmentationSchema augment = augmentations.iterator().next(); + + Set 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 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 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 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 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 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 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 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 index 0000000000..e62fdb6f37 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/GroupingTest.java @@ -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 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 usesNodes = destination.getUses(); + assertEquals(1, usesNodes.size()); + UsesNode usesNode = usesNodes.iterator().next(); + Map 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 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 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 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 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 groupings = testModule.getGroupings(); + assertEquals(1, groupings.size()); + GroupingDefinition grouping = groupings.iterator().next(); + Set 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 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 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 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 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 nodes_u = destination.getUnknownSchemaNodes(); + assertEquals(1, nodes_u.size()); + UnknownSchemaNode node_u = nodes_u.get(0); + assertTrue(node_u.isAddedByUses()); + + List 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 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 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 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 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 nodes_u = destination.getUnknownSchemaNodes(); + assertEquals(1, nodes_u.size()); + UnknownSchemaNode node_u = nodes_u.get(0); + assertTrue(node_u.isAddedByUses()); + + List 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 usesAugments = un.getAugmentations(); + assertEquals(1, usesAugments.size()); + AugmentationSchema augment = usesAugments.iterator().next(); + assertEquals("inner augment", augment.getDescription()); + Set 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 index 0000000000..fed8cde965 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TestUtils.java @@ -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 loadModules(String resourceDirectory) throws FileNotFoundException { + YangModelParser parser = new YangParserImpl(); + final File testDir = new File(resourceDirectory); + final String[] fileList = testDir.list(); + final List testFiles = new ArrayList(); + 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 loadModules(List input) throws IOException { + final YangModelParser parser = new YangParserImpl(); + final Set modules = new HashSet( + 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 input = Collections.singletonList(stream); + final Set modules = new HashSet( + 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 input = Collections.singletonList(stream); + final Set modules = new HashSet(parser.parseYangModelsFromStreams(input, context)); + stream.close(); + return modules.iterator().next(); + } + + public static Set loadModulesWithContext(final List input, final SchemaContext context) throws IOException { + final YangModelParser parser = new YangParserImpl(); + final Set modules = new HashSet(parser.parseYangModelsFromStreams(input, context)); + for(InputStream is : input) { + if(is != null) { + is.close(); + } + } + return modules; + } + + public static Module findModule(Set 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 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> 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 path = new ArrayList(); + 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 index 0000000000..d9f256caae --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/TypesResolutionTest.java @@ -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 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> 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 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> typedefs = tested.getTypeDefinitions(); + + TypeDefinition type = TestUtils.findTypedef(typedefs, "ip-version"); + EnumerationType enumType = (EnumerationType) type.getBaseType(); + List 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> typedefs = tested.getTypeDefinitions(); + TypeDefinition type = TestUtils.findTypedef(typedefs, "ip-address"); + UnionType baseType = (UnionType) type.getBaseType(); + List> 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 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> typedefs = tested.getTypeDefinitions(); + ExtendedType type = (ExtendedType) TestUtils.findTypedef(typedefs, "domain-name"); + assertTrue(type.getBaseType() instanceof StringTypeDefinition); + List 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 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 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 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> typedefs = tested.getTypeDefinitions(); + TypeDefinition testedType = TestUtils.findTypedef(typedefs, "access-operations-type"); + + BitsType bitsType = (BitsType) testedType.getBaseType(); + List 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> 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 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> typedefs = tested.getTypeDefinitions(); + ExtendedType testedType = (ExtendedType) TestUtils.findTypedef(typedefs, "object-identifier-128"); + + List 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> 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 index 0000000000..0f5a82ff48 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserNegativeTest.java @@ -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 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 index 0000000000..bc0ccbd730 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserTest.java @@ -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 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 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> 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 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 groupings = test.getGroupings(); + assertEquals(1, groupings.size()); + GroupingDefinition target = groupings.iterator().next(); + + Set 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 availableAugmentations = ifEntry.getAvailableAugmentations(); + assertEquals(2, availableAugmentations.size()); + // test ListSchemaNode args + List expectedKey = new ArrayList(); + 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 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 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 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 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 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 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 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 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 patterns = baseType2.getPatterns(); + assertEquals(1, patterns.size()); + PatternConstraint pattern = patterns.iterator().next(); + assertEquals("[a-k]*", pattern.getRegularExpression()); + List 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> 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 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> 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> 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> 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 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 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 deviations = testModule.getDeviations(); + assertEquals(1, deviations.size()); + Deviation dev = deviations.iterator().next(); + + assertEquals("system/user ref", dev.getReference()); + + List path = new ArrayList(); + 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 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 features = testModule.getFeatures(); + assertEquals(1, features.size()); + } + + @Test + public void testExtension() { + Module testModule = TestUtils.findModule(modules, "custom"); + List 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 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 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> 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 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 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> 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 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 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 index 0000000000..846b09c339 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/impl/YangParserWithContextTest.java @@ -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 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 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 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 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 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 nodes_u = destination.getUnknownSchemaNodes(); + assertEquals(1, nodes_u.size()); + UnknownSchemaNode node_u = nodes_u.get(0); + assertTrue(node_u.isAddedByUses()); + + List 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 usesNodes = destination.getUses(); + assertEquals(1, usesNodes.size()); + UsesNode usesNode = usesNodes.iterator().next(); + + // test grouping path + List path = new ArrayList(); + 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 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 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 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 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 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 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 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 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 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 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 modules = null; + try (InputStream stream = new FileInputStream(getClass().getResource("/context-test/deviation-test.yang") + .getPath())) { + List input = Lists.newArrayList(stream); + modules = TestUtils.loadModulesWithContext(input, context); + } + assertNotNull(modules); + + // test deviation + Module testModule = TestUtils.findModule(modules, "deviation-test"); + Set 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 path = new ArrayList(); + 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 index 0000000000..70bf404996 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/ModuleDependencySortTest.java @@ -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 l = ModuleDependencySort.sort(builders); + + assertDependencyGraph(ModuleDependencySort.createModuleGraph(Arrays.asList(builders))); + + @SuppressWarnings("unchecked") + Matcher 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 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> moduleGraph) { + for (Entry> node : moduleGraph.entrySet()) { + String name = node.getKey(); + + // Expects only one module revision + + Set inEdges = node.getValue().values().iterator().next().getInEdges(); + Set 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 inEdges, int i, Set 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 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 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 index 0000000000..1cd97bfcec --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/parser/util/TopologicalSortTest.java @@ -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 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 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 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 index 0000000000..1db855c1b1 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationListTest.java @@ -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 index 0000000000..3f9a53fe68 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationModuleTest.java @@ -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 index 0000000000..d3276fac25 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationSubModuleTest.java @@ -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 index 0000000000..d15a7a24f8 --- /dev/null +++ b/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/validator/YangModelValidationTest.java @@ -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 ids = new ArrayList(); + // 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> 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 mockStatement(Class 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 index 0000000000..04468fbffc --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-augment-test/test1.yang @@ -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 index 0000000000..44bdf66fbf --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-augment-test/test2.yang @@ -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 index 0000000000..f954153714 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-augment-test/test3.yang @@ -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 index 0000000000..9d57a9e6e2 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-augment-test/test4.yang @@ -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 index 0000000000..eafcb56f89 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-test/deviation-test.yang @@ -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 index 0000000000..1ba514279d --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-test/test1.yang @@ -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 index 0000000000..4cff19259e --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-test/test2.yang @@ -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 index 0000000000..b597aab478 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/context-test/test3.yang @@ -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 index 0000000000..d8d6054b59 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/model/custom.yang @@ -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 index 0000000000..2cde38598b --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/model/nodes.yang @@ -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 index 0000000000..bff9543009 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/model/types.yang @@ -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 index 0000000000..ff8519ccdb --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment0.yang @@ -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 index 0000000000..6afb493a5b --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment1.yang @@ -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 index 0000000000..4d87619ae2 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/augment2.yang @@ -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 index 0000000000..9679385ccc --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-leaf.yang @@ -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 index 0000000000..08d90af0b0 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container-list.yang @@ -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 index 0000000000..8e347a17b7 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/container.yang @@ -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 index 0000000000..f81e6e5fb9 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/identity.yang @@ -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 index 0000000000..b4ec5907ba --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/duplicity/typedef.yang @@ -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 index 0000000000..6e6377e881 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile0.yang @@ -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 index 0000000000..fdc7e71965 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile1.yang @@ -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 index 0000000000..ea5a11fd56 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile2.yang @@ -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 index 0000000000..187e9dd6d8 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile3.yang @@ -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 index 0000000000..c327de314a --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile4.yang @@ -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 index 0000000000..0d8de38e1b --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile5.yang @@ -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 index 0000000000..31a4c1ec1e --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/negative-scenario/testfile6.yang @@ -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 index 0000000000..c365228273 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang @@ -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 index 0000000000..5d5bdd0f70 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/iana-afn-safi@2012-06-04.yang @@ -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. + + "; + } + + 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. + "; + } +} 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 index 0000000000..c5ce80c50c --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/iana-if-type@2012-06-05.yang @@ -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. + "; + } +} 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 index 0000000000..7fc15779ee --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/iana-timezones@2012-07-09.yang @@ -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 index 0000000000..de20febbb7 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/ietf-inet-types@2010-09-24.yang @@ -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: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + 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 . + + 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 index 0000000000..51d9f8b887 --- /dev/null +++ b/yang-model-parser-impl/src/test/resources/types/ietf-yang-types@2010-09-24.yang @@ -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: + WG List: + + WG Chair: David Partain + + + WG Chair: David Kessens + + + Editor: Juergen Schoenwaelder + "; + + 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"; + } + + } diff --git a/yang-model-util/pom.xml b/yang-model-util/pom.xml index b865ebe015..402eb63a1a 100644 --- a/yang-model-util/pom.xml +++ b/yang-model-util/pom.xml @@ -1,15 +1,22 @@ - - 4.0.0 - - org.opendaylight.controller - yang - 0.5.4-SNAPSHOT - - yang-model-util - - - org.opendaylight.controller - yang-model-api - - + + + + org.opendaylight.controller + yang + 0.5.4-SNAPSHOT + + + 4.0.0 + yang-model-util + ${project.artifactId} + ${project.artifactId} + + + + org.opendaylight.controller + yang-model-api + + + diff --git a/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java b/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java index ad903e9e52..a56697e97a 100644 --- a/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java +++ b/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/AbstractUnsignedInteger.java @@ -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 diff --git a/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/BitsType.java b/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/BitsType.java index 94391d2288..60b5a43bf4 100644 --- a/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/BitsType.java +++ b/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/BitsType.java @@ -36,6 +36,8 @@ public final class BitsType implements BitsTypeDefinition { /** * Default constructor.
* 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 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; }