Merge "Bug 3051: Fixed pattern checks in generated DTOs"
authorRobert Varga <nite@hq.sk>
Fri, 24 Apr 2015 11:03:54 +0000 (11:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 24 Apr 2015 11:03:54 +0000 (11:03 +0000)
132 files changed:
benchmarks/pom.xml
code-generator/binding-data-codec/pom.xml
code-generator/binding-generator-api/pom.xml
code-generator/binding-generator-impl/pom.xml
code-generator/binding-generator-spi/pom.xml
code-generator/binding-generator-util/pom.xml
code-generator/binding-java-api-generator/pom.xml
code-generator/binding-model-api/pom.xml
code-generator/binding-parent/pom.xml
code-generator/binding-test-model/pom.xml
code-generator/binding-type-provider/pom.xml
code-generator/maven-sal-api-gen-plugin/pom.xml
code-generator/pom.xml
code-generator/samples/maven-code-gen-sample/pom.xml
code-generator/samples/modeling-sample/pom.xml
common/artifacts/pom.xml
common/checkstyle-logging/pom.xml
common/concepts/pom.xml
common/features-test/pom.xml
common/features/pom.xml
common/mockito-configuration/pom.xml
common/object-cache-api/pom.xml
common/object-cache-guava/pom.xml
common/object-cache-noop/pom.xml
common/parent/pom.xml
common/pom.xml
common/util/pom.xml
integration-test/bug1196-test-model/pom.xml
integration-test/bug527-test-model/pom.xml
integration-test/bundle-test/pom.xml
integration-test/pom.xml
integration-test/regression-test-model/pom.xml
integration-test/test-models/pom.xml
integration-test/yang-runtime-tests/pom.xml
model/iana/iana-afn-safi/pom.xml
model/iana/iana-if-type-2014-05-08/pom.xml
model/iana/iana-if-type/pom.xml
model/iana/pom.xml
model/ietf/ietf-inet-types/pom.xml
model/ietf/ietf-interfaces/pom.xml
model/ietf/ietf-restconf/pom.xml
model/ietf/ietf-ted/pom.xml
model/ietf/ietf-topology-isis/pom.xml
model/ietf/ietf-topology-l3-unicast-igp/pom.xml
model/ietf/ietf-topology-ospf/pom.xml
model/ietf/ietf-topology/pom.xml
model/ietf/ietf-yang-types-20130715/pom.xml
model/ietf/ietf-yang-types/pom.xml
model/ietf/pom.xml
model/l2-types/pom.xml
model/pom.xml
model/yang-ext/pom.xml
pom.xml
restconf/pom.xml
restconf/restconf-client-api/pom.xml
restconf/restconf-client-impl/pom.xml
restconf/restconf-common/pom.xml
restconf/restconf-jaxrs-api/pom.xml
restconf/restconf-test-service/pom.xml
restconf/restconf-util/pom.xml
third-party/antlr4-runtime-osgi/pom.xml
third-party/pom.xml
websocket/pom.xml
websocket/websocket-client/pom.xml
yang-validation-tool/pom.xml
yang/pom.xml
yang/yang-binding/pom.xml
yang/yang-common/pom.xml
yang/yang-data-api/pom.xml
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/schema/tree/DataTreeCandidates.java
yang/yang-data-codec-gson/pom.xml
yang/yang-data-impl/pom.xml
yang/yang-data-impl/src/main/antlr/LeafRefPathLexer.g4 [new file with mode: 0644]
yang/yang-data-impl/src/main/antlr/LeafRefPathParser.g4 [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContext.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextBuilder.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextTreeBuilder.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextUtils.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefDataValidationFailedException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPath.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathErrorListener.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParseException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserImpl.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserListenerImpl.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathSyntaxErrorException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefUtils.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidatation.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefYangSyntaxErrorException.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicate.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateBuilder.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateImpl.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicate.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateBuilder.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateImpl.java [new file with mode: 0644]
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/AbstractDataTreeTip.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest2.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest3.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTest.java [new file with mode: 0644]
yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTreeBuilderTest.java [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/import-mod.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test2.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-context-test/incorrect-modules/leafref-test.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation2.yang [new file with mode: 0644]
yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation3.yang [new file with mode: 0644]
yang/yang-data-operations/pom.xml
yang/yang-data-util/pom.xml
yang/yang-maven-plugin-it/pom.xml
yang/yang-maven-plugin-spi/pom.xml
yang/yang-maven-plugin/pom.xml
yang/yang-model-api/pom.xml
yang/yang-model-export/pom.xml
yang/yang-model-parent/pom.xml
yang/yang-model-util/pom.xml
yang/yang-parser-api/pom.xml
yang/yang-parser-impl/pom.xml
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangStatementParserListenerImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/PrefixToModuleMap.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/QNameToStatementDefinitionMap.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ExtensionStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UnknownStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangStatementSourceImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/YangFileStmtTest.java
yang/yang-parser-impl/src/test/resources/semantic-statement-parser/foobar.yang [moved from yang/yang-parser-impl/src/test/resources/semantic-statement-parser/foo.yang with 87% similarity]
yang/yang-parser-impl/src/test/resources/semantic-statement-parser/simple-nodes-semantic.yang

index 1c5b45ef603938fb728381de38df4292b5941f42..242a71d2fc40a23cdc7e8f06b0ef9321197347f2 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../common/parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -21,8 +21,8 @@
     <artifactId>benchmarks</artifactId>
 
     <properties>
-        <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
-        <yang.maven.plugin.version>0.7.0-SNAPSHOT</yang.maven.plugin.version>
+        <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
+        <yang.maven.plugin.version>0.8.0-SNAPSHOT</yang.maven.plugin.version>
         <java.source.version>1.7</java.source.version>
         <java.target.version>1.7</java.target.version>
         <jmh.version>0.9.7</jmh.version>
index ad611d2d2dfc1240fae07f6c87be09669143058d..f6a179fd88c33bc8b7db142e54d36e123640bf3b 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 691f8e5a84a9826b1f152db62d4bdc5f57f3a046..b475ad3e3fbd64c6dd73e9059f152fbeb4180718 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index c5ed3cfdb6e8028c117216799a60177ead59d70b..d446c82c1ff9c864467863d4b5034f8e137ddf43 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 185fd691430bce9927158397f159886d10870fd9..4ed76cc1f76e798d35697e4fd1cac4cb592de5b0 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 367aaff67bee2e38b019940bad8e87ce535863e2..80e09f2382ec27e0ab6c4bc3cdf8c0f5d1040151 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 51aa5c7629c587f4ef3310e688d9044adaf504eb..541d2f5859b6ae45e98267d2ab991aa3c5f3ef20 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index 2403d6e958d22803fae866a505821de1b9658468..235167ef7d6353fe93d83a071c31d11419c919d7 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index c38481e8d499af78d692e66f4c70d63ac1e3ed8c..cc1013ac8aefe52231c9e7a8d38be3e945de8ae6 100644 (file)
     <parent>
         <groupId>org.opendaylight.odlparent</groupId>
         <artifactId>bundle-parent</artifactId>
-        <version>1.5.0-SNAPSHOT</version>
+        <version>1.6.0-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opendaylight.yangtools</groupId>
     <artifactId>binding-parent</artifactId>
-    <version>0.7.0-SNAPSHOT</version>
+    <version>0.8.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
-        <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
+        <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
         <salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
     </properties>
 
index c93a84c7c133e1133a4443aad2c86743e69f9958..b759f86bdd0665cde31c98bd40e45d04043b3dd0 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
index f496868a3f49f4f22e7fa738e6a59f0cfab864cf..f19246475434ef75944dc9136ae55881826cf3ec 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index d7d20c1489e13b118f711b34815436f2cff7ae96..c82c75a8f4dcbf3d68210d798b48770252fbc630 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>maven-sal-api-gen-plugin</artifactId>
index 324088dc7d3cffba53ada40b6ead92b7cf8f5f2e..2ce6df0c2a0c3c9e4980a6bd8450f60f8f45c404 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../common/parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index 52daaac3b81ab05af8626d7069b9909db9c0c804..765ebe254414fc1e4402af327c088d9482275ffc 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <artifactId>maven-code-gen-sample</artifactId>
 
index 4e1adde8af111b752b3b7f108a8d96dc8a8a5a31..ef68f03e62beffb93ade5a143f18339d259fdea5 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>binding-generator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <artifactId>modeling-sample</artifactId>
 
index 6d862f667510322cf84809552947cbb1802b054a..3f532b469da4d9317c8d0f5a14545091dad06109 100644 (file)
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.opendaylight.yangtools</groupId>
     <artifactId>yangtools-artifacts</artifactId>
-    <version>0.7.0-SNAPSHOT</version>
+    <version>0.8.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
         <!-- Model versions -->
-        <ietf.topology.version>2013.10.21.7-SNAPSHOT</ietf.topology.version>
+        <ietf.topology.version>2013.10.21.8-SNAPSHOT</ietf.topology.version>
     </properties>
 
     <dependencyManagement>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>iana-if-type-2014-05-08</artifactId>
-                <version>2014.05.08.7-SNAPSHOT</version>
+                <version>2014.05.08.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>ietf-inet-types</artifactId>
-                <version>2010.09.24.7-SNAPSHOT</version>
+                <version>2010.09.24.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>ietf-yang-types</artifactId>
-                <version>2010.09.24.7-SNAPSHOT</version>
+                <version>2010.09.24.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>ietf-yang-types-20130715</artifactId>
-                <version>2013.07.15.7-SNAPSHOT</version>
+                <version>2013.07.15.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>ietf-interfaces</artifactId>
-                <version>2014.05.08.7-SNAPSHOT</version>
+                <version>2014.05.08.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>ietf-restconf</artifactId>
-                <version>2013.10.19.7-SNAPSHOT</version>
+                <version>2013.10.19.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>opendaylight-l2-types</artifactId>
-                <version>2013.08.27.7-SNAPSHOT</version>
+                <version>2013.08.27.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools.model</groupId>
                 <artifactId>yang-ext</artifactId>
-                <version>2013.09.07.7-SNAPSHOT</version>
+                <version>2013.09.07.8-SNAPSHOT</version>
             </dependency>
             <dependency>
                 <groupId>org.opendaylight.yangtools</groupId>
index a29a3fe38372ab5aae8bc21628b9487e8cb5fac0..889ef2b65822fdf050644d8fc97af4c80318985e 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
   <artifactId>checkstyle-logging</artifactId>
index d2b0867d8cb680838202e21192532e87b393dd86..c702ae1e51a7d31e481dc5239f2c55dc84caaf60 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 50ff2715034365bf65876ad73328533e238b8ae6..0e5dbf09735d061c376dcad8f4d18e4e6511b32d 100644 (file)
@@ -13,7 +13,7 @@
    <parent>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yangtools-parent</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
+      <version>0.8.0-SNAPSHOT</version>
       <relativePath>../parent/pom.xml</relativePath>
    </parent>
    <artifactId>features-test</artifactId>
@@ -27,7 +27,7 @@
      <relocation>
        <groupId>org.opendaylight.odlparent</groupId>
        <artifactId>features-test</artifactId>
-       <version>1.5.0-SNAPSHOT</version>
+       <version>1.6.0-SNAPSHOT</version>
        <message>This artifact has been migrated to odlparent and will be removed in Lithium release</message>
      </relocation>
    </distributionManagement>
index d59c952d30cbdf611cdfcb4c808d7df5d4b12c87..d6d1647e40cd3a74bbe4c9816b907001e0a8c54f 100644 (file)
     <parent>
         <groupId>org.opendaylight.odlparent</groupId>
         <artifactId>features-parent</artifactId>
-        <version>1.5.0-SNAPSHOT</version>
+        <version>1.6.0-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <groupId>org.opendaylight.yangtools</groupId>
     <artifactId>features-yangtools</artifactId>
-    <version>0.7.0-SNAPSHOT</version>
+    <version>0.8.0-SNAPSHOT</version>
     <packaging>jar</packaging>
 
     <dependencyManagement>
index 1637e1f9cbc3ccdde018767b948a28fc700a1094..7788fe49f1366896e4012976c6eac19c985f8602 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 568834cdd80d2c26c2c1b064097022eb20ab8e81..0fc11fc5580e0eed09f806c3f841969fed8bb373 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
     <packaging>bundle</packaging>
index ed837d1ace1d9c2cf838bc7493b0112c23bccec3..e198df3ecf4e745f05efff92dbb9bfb505defd32 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 2105738dd66ec9b2aea519792c10135f68075055..7e4268c37b09b98659059d6d85ba75c02eb62f8d 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
     <packaging>bundle</packaging>
index 6341f11cfb30960cbbed594077692c14c13642d3..da7b5eacbc2bb2ca9b991034e57cd4c49a9f3108 100644 (file)
     <parent>
         <groupId>org.opendaylight.odlparent</groupId>
         <artifactId>odlparent</artifactId>
-        <version>1.5.0-SNAPSHOT</version>
+        <version>1.6.0-SNAPSHOT</version>
         <relativePath></relativePath>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>yangtools-parent</artifactId>
     <groupId>org.opendaylight.yangtools</groupId>
-    <version>0.7.0-SNAPSHOT</version>
+    <version>0.8.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
-        <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
+        <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
 
         <!-- FIXME: these will be upstreamed -->
         <maven.depends.version>1.2</maven.depends.version>
                 <plugin>
                     <groupId>org.opendaylight.yangtools</groupId>
                     <artifactId>yang-maven-plugin</artifactId>
-                    <version>0.7.0-SNAPSHOT</version>
+                    <version>0.8.0-SNAPSHOT</version>
                     <executions>
                         <execution>
                             <goals>
                         <dependency>
                             <groupId>org.opendaylight.yangtools</groupId>
                             <artifactId>maven-sal-api-gen-plugin</artifactId>
-                            <version>0.7.0-SNAPSHOT</version>
+                            <version>0.8.0-SNAPSHOT</version>
                             <type>jar</type>
                         </dependency>
                     </dependencies>
index 8c0bf84b1bcfeb4183fc1474e8ef45feff2b9d0d..cff1d1feff58046bf946446ba7e863d0d101a2d8 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yangtools-parent</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
+      <version>0.8.0-SNAPSHOT</version>
       <relativePath>parent</relativePath>
     </parent>
 
index 9c9ab40246a8c12b87347792a62a01d4492c1d5c..c32b829dce8ec2c1749cc4b375e8f6b246871970 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
     <packaging>bundle</packaging>
index c2d2746263d5a24d6cb6f48934ab7ec0674fb84a..447b1fb2fb8351b05a6bbe52ec5a64fea6ee5c41 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>yang-binding</artifactId>
-                        <version>0.7.0-SNAPSHOT</version>
+                        <version>0.8.0-SNAPSHOT</version>
                     </dependency>
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>yang-common</artifactId>
-                        <version>0.7.0-SNAPSHOT</version>
+                        <version>0.8.0-SNAPSHOT</version>
                     </dependency>
                 </dependencies>
             </plugin>
index 9a7177229b87fd0b55d8d976c0098abe655ecae8..f65011a00299f0a36626ece49cd9e282c6951472 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 42235ace5c538515a5a26f7758e4fc5cb337f41e..7f16ef284b918ea1fed93aa7c8085c5946ececbf 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <artifactId>yangtools-parent</artifactId>
         <groupId>org.opendaylight.yangtools</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 0871e056e70544e2a207d4fd5daa8a73f3a7bb8d..8c1331dc552fa89acfc7d783c047e98412c9a316 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../common/parent</relativePath>
     </parent>
 
index 4b0a4f1d7f6a99858c3d8024934ca1f73ce7d0a6..ad25fcc8bbf87833e3d776541b4dafc45bd7cbd2 100644 (file)
@@ -9,7 +9,7 @@
 
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <artifactId>yangtools-parent</artifactId>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
index 656ed68187738ca04c3e010d71eb518a97f53720..749217dbc4a69d032a4fc4ed13a9241bc731191d 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
@@ -60,7 +60,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.7.0-SNAPSHOT</version>
+                        <version>0.8.0-SNAPSHOT</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index c145dc54ffa19de9a9f83f97f5e2c58a0a4aa5fe..89c0b68fbacae1b35cf068b8383487bf463bcd97 100644 (file)
@@ -11,7 +11,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 57bd56c9be34eae1848c01c97ecd40916b20ed27..de82000313359b0b9a45d764d11123ed969a07c5 100644 (file)
     <parent>
         <artifactId>model-iana</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>iana-afn-safi</artifactId>
-    <version>2013.07.04.7-SNAPSHOT</version>
+    <version>2013.07.04.8-SNAPSHOT</version>
 
     <build>
         <plugins>
index 979dfdf819dca75e3688a3ccf287a5ea87d6077f..3815db3fc5dc94d23eb673913e99850ec3c39168 100644 (file)
     <parent>
         <artifactId>model-iana</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>iana-if-type-2014-05-08</artifactId>
-    <version>2014.05.08.7-SNAPSHOT</version>
+    <version>2014.05.08.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index b354c1c7cab3d46479b8f31afe5ccf05acaed39a..fb011b8145af34f2a7d2894345684749d3824e7a 100644 (file)
     <parent>
         <artifactId>model-iana</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>iana-if-type</artifactId>
-    <version>2013.07.04.7-SNAPSHOT</version>
+    <version>2013.07.04.8-SNAPSHOT</version>
 
     <build>
         <plugins>
index 13eb5db290d5645de0684c1b0d80652b30e98234..843c084db3211070576c3a4672ea2307132cc1e2 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <artifactId>model-parent</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
index 9759f5ce93a98b7351f8b2762aa1f04ac77578d7..cad85086202a35ccbdfc659a814879c0f45f4970 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-inet-types</artifactId>
-    <version>2010.09.24.7-SNAPSHOT</version>
+    <version>2010.09.24.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index f1bc48457d309772e32222cd001edd3ddda64f47..ac561979dc3694e62d7a5ca3dcccf259b39a0b3f 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-interfaces</artifactId>
-    <version>2014.05.08.7-SNAPSHOT</version>
+    <version>2014.05.08.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index e9ce3701373f407357650f202c1ad09ee3543653..f25ffe79468a13578d665c21f3a3e82262f7a46d 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-restconf</artifactId>
-    <version>2013.10.19.7-SNAPSHOT</version>
+    <version>2013.10.19.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index d8f758d8783473e94a151943f9ea813678dd585a..f060fe23f506aefb9b2ec20a75cf1c95ed2b206d 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-ted</artifactId>
-    <version>2013.10.21.7-SNAPSHOT</version>
+    <version>2013.10.21.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 77c026bf4cc652531e53f3aa267e7580e3430878..9063160570836bffbba39e424bb67c15d66b862b 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-topology-isis</artifactId>
-    <version>2013.10.21.7-SNAPSHOT</version>
+    <version>2013.10.21.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 6d00b7814b7bced60b344438696f38be43e4b17a..071d5aadb2168d6cb4bad1744b576bea1eb7d432 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-topology-l3-unicast-igp</artifactId>
-    <version>2013.10.21.7-SNAPSHOT</version>
+    <version>2013.10.21.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 64f2eb5dfa067109074c8d6447278be96ce00728..7344aab89bbc2c977e16a7a2c32169240d26b88e 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-topology-ospf</artifactId>
-    <version>2013.10.21.7-SNAPSHOT</version>
+    <version>2013.10.21.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index ea135bbb88bbb9977c42b1a6da4c6c027b457266..1954710a68a5e2eafc93bfdca49174e9985961e0 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-topology</artifactId>
-    <version>2013.10.21.7-SNAPSHOT</version>
+    <version>2013.10.21.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 25df3cebcaf72566136ac31e49f952116246de04..9d6c5eeba4220935f12b560c8989619b1f4ee7bd 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-yang-types-20130715</artifactId>
-    <version>2013.07.15.7-SNAPSHOT</version>
+    <version>2013.07.15.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 685d70daff2ed1adc8d0a02402b682a2c11e68c2..9c20f894354eabc56dc7dc76bc4816077ef0131a 100644 (file)
     <parent>
         <artifactId>model-ietf</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ietf-yang-types</artifactId>
-    <version>2010.09.24.7-SNAPSHOT</version>
+    <version>2010.09.24.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
index 5677b0c11bd687a46b0a487bc18a24d6f6242e6a..0e958f85c2a7745ba53d20513f2044af7f7b514b 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <artifactId>model-parent</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
index c47cc0a90e3494baab6438743a3ae3e9bd3c1346..0b27bcd067fdd24707e30a7b9063554f4817010d 100644 (file)
     <parent>
         <artifactId>model-parent</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>opendaylight-l2-types</artifactId>
-    <version>2013.08.27.7-SNAPSHOT</version>
+    <version>2013.08.27.8-SNAPSHOT</version>
 
     <build>
         <plugins>
index 206d1b288601b9a6c7f974a14bec51facaf75d07..cc77098d0d383cd59d080e156e7791cc9f7c9c95 100644 (file)
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../common/parent</relativePath>
     </parent>
     <groupId>org.opendaylight.yangtools.model</groupId>
-    <!--<version>0.7.0-SNAPSHOT</version>-->
+    <!--<version>0.8.0-SNAPSHOT</version>-->
     <modelVersion>4.0.0</modelVersion>
     <artifactId>model-parent</artifactId>
     <packaging>pom</packaging>
@@ -68,7 +68,7 @@
                     <dependency>
                         <groupId>org.opendaylight.yangtools</groupId>
                         <artifactId>maven-sal-api-gen-plugin</artifactId>
-                        <version>0.7.0-SNAPSHOT</version>
+                        <version>0.8.0-SNAPSHOT</version>
                         <type>jar</type>
                     </dependency>
                 </dependencies>
index 2bb3db677f40f85af0c3b6ab6006e3638fcfd344..3cbe1766fd3c7eda4480c989a2f8fc6c6df366b0 100644 (file)
     <parent>
         <artifactId>model-parent</artifactId>
         <groupId>org.opendaylight.yangtools.model</groupId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
 
     <modelVersion>4.0.0</modelVersion>
     <artifactId>yang-ext</artifactId>
-    <version>2013.09.07.7-SNAPSHOT</version>
+    <version>2013.09.07.8-SNAPSHOT</version>
     <name>${project.artifactId}</name>
     <description>${project.artifactId}</description>
 
diff --git a/pom.xml b/pom.xml
index e64f5c3bfe9bf6c56bfbea7efc8f9b2105c8011c..395da84e1b98f839ead10c4284afa644b7e5e98b 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
     <parent>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yangtools-parent</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
+      <version>0.8.0-SNAPSHOT</version>
       <relativePath>common/parent</relativePath>
     </parent>
 
index fba0fb7d03ba2e67d937a9126f5b4c516277e216..084719b9979d79cc51257d7ad50f3536e1984b87 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../common/parent</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
index 130e7dffbbbb1532dded88ad00f9ccb1dead98cc..2f2f003255a19c959ef9e35dfe7fa6ac90411885 100644 (file)
@@ -15,7 +15,7 @@
    <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <dependencies>
         <dependency>
index fe46d36d92b218e7e7db529914e726635580ac11..690c391d251b8bd572ce5f0a8efd9ffa277a0a82 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
   <artifactId>restconf-client-impl</artifactId>
index dbb4819085c9cf225890047d2d415d95bdefcc26..89926c8af84a5e4a6092e8f8629939b0067f45d4 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>restconf-common</artifactId>
index aa91bc614bed2c1fdb70357fa9b2073a515ab6fc..3ea648c92783ca5e0ee03af3fa9604fd550d6852 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <artifactId>restconf-jaxrs-api</artifactId>
     <name>restconf-jaxrs-api</name>
index 7c079b9c0f31bd9af6245a7f0ba994bcfce41317..9f36d6f9351b77ffe0c790543a6ac5cfe2d0b25b 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>restconf-test-service</artifactId>
index 9ebb9ba3a4e47ad18055bcf22a06a9ae16e7bc8b..3110382acae9bdaea82f838dcaa2efc73d78f465 100644 (file)
@@ -11,7 +11,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>restconf-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>restconf-util</artifactId>
index 7442f99b3a8205f92a85394e2cb97142e5badb5a..95ef64179c4aa186e0eb0fce30bcdf19f5051c8c 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>third-party-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
index c22c469cc2f12640b191530b351e5e98d44ab405..1727bdba7db9728d1c24c431f80dfc043a5fb228 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>../parent/pom.xml</relativePath>
     </parent>
 
index 8acd61daaffd8783a2a79b4b7731e98b1a7490dd..ab7fdff9d4d3f725ea05e17ef4b12addbb8748c7 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yangtools-parent</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
+      <version>0.8.0-SNAPSHOT</version>
       <relativePath>../common/parent</relativePath>
     </parent>
 
index 341099985966b42f5bf6985d8c7bae426651bbfd..5ed7bf67479054a387307f560c3b52f2ca4453d5 100644 (file)
@@ -14,7 +14,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 8dbaa1df2373af2b0b5a88fa4d9919aeb6859852..cbbc6ce6ea745b357efa347cd79aa4d2785a6159 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-aggregator</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
     </parent>
     <artifactId>yang-validation-tool</artifactId>
 
index 01e71bd5477661fc2afa507ff58fb3cfaa7a909a..546339a2abe179af3806e7b963d98d2edd3ce5d4 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yangtools-parent</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
+      <version>0.8.0-SNAPSHOT</version>
       <relativePath>../common/parent</relativePath>
     </parent>
 
index ada7f5a89ddd2a74a95f6d30a1f79c16af367a58..0d03ad751a775f524ff4700c6c2209a52613330a 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index dc732e3dab4aaf34e357bf2b469472b27a03ed21..19a2656d88d96fbc63b164f220743247b1c30571 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 688dbb1fdbe2757fdfe7c8cd5b9c0bfb368558cf..73505cd9977ba7c4f4ed73583946bd19df13d779 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 5863b31168a0d1a21323a88091dfe90041581e7e..53b8343cd18760a5977a2681c879672c10dcbfde 100644 (file)
@@ -71,12 +71,16 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
  * @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
  */
 public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
+    /**
+     * An empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual
+     * root of the YANG namespace.
+     */
+    public static final YangInstanceIdentifier EMPTY = trustedCreate(Collections.<PathArgument>emptyList());
     @SuppressWarnings("rawtypes")
     private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
             AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
     private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
             AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
-    private static final YangInstanceIdentifier EMPTY = trustedCreate(Collections.<PathArgument>emptyList());
     private static final Field PATHARGUMENTS_FIELD;
 
     private static final long serialVersionUID = 3L;
index 441f92776373383156f78479ff9838a91e578cc1..04e3b204bcbc12f7ae3ab795bb558810e066559b 100644 (file)
@@ -10,12 +10,15 @@ package org.opendaylight.yangtools.yang.data.api.schema.tree;
 import com.google.common.annotations.Beta;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Utility class holding methods useful when dealing with {@link DataTreeCandidate} instances.
  */
 @Beta
 public final class DataTreeCandidates {
+    private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidates.class);
     private DataTreeCandidates() {
         throw new UnsupportedOperationException();
     }
@@ -36,17 +39,21 @@ public final class DataTreeCandidates {
         switch (node.getModificationType()) {
         case DELETE:
             modification.delete(path);
+            LOG.debug("Modification {} deleted path {}", modification, path);
             break;
         case SUBTREE_MODIFIED:
+            LOG.debug("Modification {} modified path {}", modification, path);
             for (DataTreeCandidateNode child : node.getChildNodes()) {
                 applyNode(modification, path.node(child.getIdentifier()), child);
             }
             break;
         case UNMODIFIED:
+            LOG.debug("Modification {} unmodified path {}", modification, path);
             // No-op
             break;
         case WRITE:
             modification.write(path, node.getDataAfter().get());
+            LOG.debug("Modification {} written path {}", modification, path);
             break;
         default:
             throw new IllegalArgumentException("Unsupported modification " + node.getModificationType());
index fd7481133768f0e605af26ad45b15cd741c1cbc0..f366cc1ebf227372e26255a3cbc8525dbd3909be 100644 (file)
@@ -11,7 +11,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 0953073f529a66582b9b9537aa560d0f1d92572b..ca55ad025516d66f82dd670031ee6104b3e1ae4c 100644 (file)
@@ -10,7 +10,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
 
     <build>
         <plugins>
+            <plugin>
+                <groupId>org.antlr</groupId>
+                <artifactId>antlr4-maven-plugin</artifactId>
+                <version>4.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>antlr4</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <sourceDirectory>src/main/antlr</sourceDirectory>
+                    <outputDirectory>target/generated-sources/parser/org/opendaylight/yangtools/yang/data/impl/leafref</outputDirectory>
+                    <visitor>true</visitor>
+                    <listener>true</listener>
+                </configuration>
+            </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
                 </configuration>
             </plugin>
         </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>org.antlr</groupId>
+                                        <artifactId>antlr4-maven-plugin</artifactId>
+                                        <versionRange>[4.0,)</versionRange>
+                                        <goals>
+                                            <goal>antlr4</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <execute />
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
     </build>
 
     <dependencies>
             <groupId>com.google.code.findbugs</groupId>
             <artifactId>jsr305</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>4.0</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/yang/yang-data-impl/src/main/antlr/LeafRefPathLexer.g4 b/yang/yang-data-impl/src/main/antlr/LeafRefPathLexer.g4
new file mode 100644 (file)
index 0000000..526c7ca
--- /dev/null
@@ -0,0 +1,20 @@
+lexer grammar LeafRefPathLexer;\r
+\r
+@header {\r
+package org.opendaylight.yangtools.yang.data.impl.leafref;\r
+}\r
+\r
+COLON : ':' ;\r
+SLASH : '/' ;\r
+DOTS : '..' ;\r
+EQUAL : '=' ;\r
+LEFT_SQUARE_BRACKET : '[' ;\r
+RIGHT_SQUARE_BRACKET : ']' ;\r
+LEFT_PARENTHESIS : '(' ;\r
+RIGHT_PARENTHESIS : ')' ;\r
+\r
+CURRENT_KEYWORD : 'current';\r
+\r
+SEP: [ \n\r\t]+ ;\r
+IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_\-.]*;\r
+\r
diff --git a/yang/yang-data-impl/src/main/antlr/LeafRefPathParser.g4 b/yang/yang-data-impl/src/main/antlr/LeafRefPathParser.g4
new file mode 100644 (file)
index 0000000..535d040
--- /dev/null
@@ -0,0 +1,39 @@
+parser grammar LeafRefPathParser;\r
+\r
+@header {\r
+package org.opendaylight.yangtools.yang.data.impl.leafref;\r
+}\r
+\r
+options{\r
+ tokenVocab = LeafRefPathLexer;\r
+}\r
+\r
+path_arg : absolute_path | relative_path;\r
+\r
+absolute_path : (SLASH node_identifier (path_predicate)*)+; \r
+\r
+relative_path : (DOTS SLASH)* descendant_path;\r
+\r
+descendant_path : node_identifier ((path_predicate)* absolute_path)?;\r
+\r
+path_predicate : LEFT_SQUARE_BRACKET SEP? path_equality_expr SEP? RIGHT_SQUARE_BRACKET;\r
+\r
+path_equality_expr : node_identifier SEP? EQUAL SEP? path_key_expr;\r
+\r
+path_key_expr : current_function_invocation SEP? SLASH SEP? rel_path_keyexpr;\r
+\r
+rel_path_keyexpr : (DOTS SEP? SLASH SEP?)* (node_identifier SEP? SLASH SEP?)* node_identifier;\r
+\r
+node_identifier : (prefix COLON)? identifier;\r
+\r
+current_function_invocation : CURRENT_KEYWORD SEP? LEFT_PARENTHESIS SEP? RIGHT_PARENTHESIS;\r
+\r
+descendant_schema_nodeid :  node_identifier\r
+                            absolute_schema_nodeid;\r
+\r
+absolute_schema_nodeid : (SLASH node_identifier)+;\r
+\r
+prefix : identifier;\r
+\r
+identifier: IDENTIFIER | CURRENT_KEYWORD;\r
+\r
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContext.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContext.java
new file mode 100644 (file)
index 0000000..4762290
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+final public class LeafRefContext {
+
+    private final QName currentNodeQName;
+    private final SchemaPath currentNodePath;
+    private final SchemaContext schemaContext;
+    private final Module module;
+
+    private final LeafRefPath leafRefTargetPath;
+    private final LeafRefPath absoluteLeafRefTargetPath ;
+    private final String leafRefTargetPathString;
+
+    private final boolean isReferencedBy;
+    private final boolean isReferencing;
+
+    private final Map<QName, LeafRefContext> referencingChilds;
+    private final Map<QName, LeafRefContext> referencedByChilds;
+    private final Map<QName, LeafRefContext> referencedByLeafRefCtx;
+
+    LeafRefContext(final LeafRefContextBuilder leafRefContextBuilder) {
+        this.currentNodeQName = leafRefContextBuilder.getCurrentNodeQName();
+        this.currentNodePath = leafRefContextBuilder.getCurrentNodePath();
+        this.schemaContext = leafRefContextBuilder.getSchemaContext();
+        this.leafRefTargetPath = leafRefContextBuilder.getLeafRefTargetPath();
+        this.absoluteLeafRefTargetPath = leafRefContextBuilder
+                .getAbsoluteLeafRefTargetPath();
+        this.leafRefTargetPathString = leafRefContextBuilder
+                .getLeafRefTargetPathString();
+        this.isReferencedBy = leafRefContextBuilder.isReferencedBy();
+        this.isReferencing = leafRefContextBuilder.isReferencing();
+        this.referencingChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencingChilds());
+        this.referencedByChilds = ImmutableMap.copyOf(leafRefContextBuilder.getReferencedByChilds());
+        this.referencedByLeafRefCtx = ImmutableMap.copyOf(leafRefContextBuilder
+                .getAllReferencedByLeafRefCtxs());
+        this.module = leafRefContextBuilder.getLeafRefContextModule();
+    }
+
+    public static final LeafRefContext create(final SchemaContext ctx) {
+        try {
+            return new LeafRefContextTreeBuilder(ctx).buildLeafRefContextTree();
+        } catch (IOException | LeafRefYangSyntaxErrorException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public boolean hasLeafRefContextChild() {
+        return hasReferencedChild() || hasReferencingChild();
+    }
+
+    public boolean hasReferencedChild() {
+        return !referencedByChilds.isEmpty();
+    }
+
+    public boolean hasReferencingChild() {
+        return !referencingChilds.isEmpty();
+    }
+
+    public boolean isReferenced() {
+        return isReferencedBy;
+    }
+
+    public boolean isReferencing() {
+        return isReferencing;
+    }
+
+    public LeafRefContext getReferencingChildByName(final QName name) {
+        return referencingChilds.get(name);
+    }
+
+    public Map<QName, LeafRefContext> getReferencingChilds() {
+        return referencingChilds;
+    }
+
+    public LeafRefContext getReferencedChildByName(final QName name) {
+        return referencedByChilds.get(name);
+    }
+
+    public Map<QName, LeafRefContext> getReferencedByChilds() {
+        return referencedByChilds;
+    }
+
+    public SchemaPath getCurrentNodePath() {
+        return currentNodePath;
+    }
+
+    public LeafRefPath getLeafRefTargetPath() {
+        return leafRefTargetPath;
+    }
+
+    public String getLeafRefTargetPathString() {
+        return leafRefTargetPathString;
+    }
+
+    public QName getNodeName() {
+        return currentNodeQName;
+    }
+
+    SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    public LeafRefPath getAbsoluteLeafRefTargetPath() {
+        return absoluteLeafRefTargetPath;
+    }
+
+    public Module getLeafRefContextModule() {
+        return module;
+    }
+
+    public LeafRefContext getReferencedByLeafRefCtxByName(final QName qname) {
+        return referencedByLeafRefCtx.get(qname);
+    }
+
+    public Map<QName, LeafRefContext> getAllReferencedByLeafRefCtxs() {
+        return referencedByLeafRefCtx;
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextBuilder.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextBuilder.java
new file mode 100644 (file)
index 0000000..4349bd5
--- /dev/null
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+class LeafRefContextBuilder {
+
+    private QName currentNodeQName;
+    private SchemaPath currentNodePath;
+    private SchemaContext schemaContext;
+
+    private LeafRefPath leafRefTargetPath = null;
+    private LeafRefPath absoluteLeafRefTargetPath = null;
+    private String leafRefTargetPathString = "";
+
+    private boolean isReferencedBy = false;
+    private boolean isReferencing = false;
+
+    private Map<QName, LeafRefContext> referencingChilds = new HashMap<QName, LeafRefContext>();
+    private Map<QName, LeafRefContext> referencedByChilds = new HashMap<QName, LeafRefContext>();
+    private Map<QName, LeafRefContext> referencedByLeafRefCtx = new HashMap<QName, LeafRefContext>();
+
+    public LeafRefContextBuilder(final QName currentNodeQName,
+            final SchemaPath currentNodePath, final SchemaContext schemaContext) {
+        this.currentNodeQName = currentNodeQName;
+        this.currentNodePath = currentNodePath;
+        this.schemaContext = schemaContext;
+    }
+
+    public LeafRefContext build() {
+        final LeafRefContext leafRefContext = new LeafRefContext(this);
+
+        referencingChilds = new HashMap<QName, LeafRefContext>();
+        referencedByChilds = new HashMap<QName, LeafRefContext>();
+        referencedByLeafRefCtx = new HashMap<QName, LeafRefContext>();
+
+        return leafRefContext;
+    }
+
+    public boolean hasLeafRefContextChild() {
+        return hasReferencedByChild() || hasReferencingChild();
+    }
+
+    public boolean hasReferencedByChild() {
+        return !referencedByChilds.isEmpty();
+    }
+
+    public boolean hasReferencingChild() {
+        return !referencingChilds.isEmpty();
+    }
+
+    public boolean isReferencedBy() {
+        return isReferencedBy;
+    }
+
+    public void setReferencedBy(final boolean isReferencedBy) {
+        this.isReferencedBy = isReferencedBy;
+    }
+
+    public boolean isReferencing() {
+        return isReferencing;
+    }
+
+    public void setReferencing(final boolean isReferencing) {
+        this.isReferencing = isReferencing;
+    }
+
+    public void addReferencingChild(final LeafRefContext child, final QName childQName) {
+        referencingChilds.put(childQName, child);
+    }
+
+    public LeafRefContext getReferencingChildByName(final QName name) {
+        return referencingChilds.get(name);
+    }
+
+    public Map<QName, LeafRefContext> getReferencingChilds() {
+        return referencingChilds;
+    }
+
+    public void addReferencedByChild(final LeafRefContext child, final QName childQName) {
+        referencedByChilds.put(childQName, child);
+    }
+
+    public LeafRefContext getReferencedByChildByName(final QName name) {
+        return referencedByChilds.get(name);
+    }
+
+    public Map<QName, LeafRefContext> getReferencedByChilds() {
+        return referencedByChilds;
+    }
+
+    public SchemaPath getCurrentNodePath() {
+        return currentNodePath;
+    }
+
+    public void setCurrentNodePath(final SchemaPath currentNodePath) {
+        this.currentNodePath = currentNodePath;
+    }
+
+    public LeafRefPath getLeafRefTargetPath() {
+        return leafRefTargetPath;
+    }
+
+    public void setLeafRefTargetPath(final LeafRefPath leafRefPath) {
+        this.leafRefTargetPath = leafRefPath;
+    }
+
+    public String getLeafRefTargetPathString() {
+        return leafRefTargetPathString;
+    }
+
+    public void setLeafRefTargetPathString(final String leafRefPathString) {
+        this.leafRefTargetPathString = leafRefPathString;
+    }
+
+    public QName getCurrentNodeQName() {
+        return currentNodeQName;
+    }
+
+    public void setCurrentNodeQName(final QName currentNodeQName) {
+        this.currentNodeQName = currentNodeQName;
+    }
+
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    public void setSchemaContext(final SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+    }
+
+    public LeafRefPath getAbsoluteLeafRefTargetPath() {
+
+        if (isReferencing && absoluteLeafRefTargetPath == null) {
+            if (leafRefTargetPath.isAbsolute()) {
+                absoluteLeafRefTargetPath = leafRefTargetPath;
+            } else {
+                absoluteLeafRefTargetPath = LeafRefUtils
+                        .createAbsoluteLeafRefPath(leafRefTargetPath,
+                                currentNodePath, getLeafRefContextModule());
+            }
+        }
+
+        return absoluteLeafRefTargetPath;
+    }
+
+    public Module getLeafRefContextModule() {
+        final QNameModule qnameModule = currentNodeQName.getModule();
+
+        return schemaContext.findModuleByNamespaceAndRevision(
+                qnameModule.getNamespace(), qnameModule.getRevision());
+    }
+
+    public void addReferencedByLeafRefCtx(final QName qname, final LeafRefContext leafRef) {
+        referencedByLeafRefCtx.put(qname, leafRef);
+    }
+
+    public LeafRefContext getReferencedByLeafRefCtxByName(final QName qname) {
+        return referencedByLeafRefCtx.get(qname);
+    }
+
+    public Map<QName, LeafRefContext> getAllReferencedByLeafRefCtxs() {
+        return referencedByLeafRefCtx;
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextTreeBuilder.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextTreeBuilder.java
new file mode 100644 (file)
index 0000000..38dfb75
--- /dev/null
@@ -0,0 +1,257 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.Leafref;
+
+class LeafRefContextTreeBuilder {
+    private final SchemaContext schemaContext;
+    private final LinkedList<LeafRefContext> leafRefs;
+
+    public LeafRefContextTreeBuilder(final SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+        this.leafRefs = new LinkedList<LeafRefContext>();
+    }
+
+    public LeafRefContext buildLeafRefContextTree() throws IOException,
+            LeafRefYangSyntaxErrorException {
+        final LeafRefContextBuilder rootBuilder = new LeafRefContextBuilder(
+                schemaContext.getQName(), schemaContext.getPath(),
+                schemaContext);
+
+        final Set<Module> modules = schemaContext.getModules();
+        for (final Module module : modules) {
+            final Collection<DataSchemaNode> childNodes = module.getChildNodes();
+            for (final DataSchemaNode childNode : childNodes) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+                        childNode, module);
+
+                if (childLeafRefContext.hasReferencingChild()
+                        || childLeafRefContext.isReferencing()) {
+                    rootBuilder.addReferencingChild(childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+        }
+
+        for (final Module module : modules) {
+            final Collection<DataSchemaNode> childNodes = module.getChildNodes();
+            for (final DataSchemaNode childNode : childNodes) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+                        childNode, module);
+
+                if (childLeafRefContext.hasReferencedChild()
+                        || childLeafRefContext.isReferenced()) {
+                    rootBuilder.addReferencedByChild(childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+        }
+
+        // FIXME: it might be useful to merge these subtrees (i.e. referencing
+        // and referencedBy subtree)
+
+        return rootBuilder.build();
+    }
+
+    private LeafRefContext buildLeafRefContextReferencingTree(
+            final DataSchemaNode node, final Module currentModule) throws IOException,
+            LeafRefYangSyntaxErrorException {
+
+        final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
+                node.getQName(), node.getPath(), schemaContext);
+
+        if (node instanceof DataNodeContainer) {
+            final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
+            final Collection<DataSchemaNode> childNodes = dataNodeContainer
+                    .getChildNodes();
+
+            for (final DataSchemaNode childNode : childNodes) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+                        childNode, currentModule);
+
+                if (childLeafRefContext.hasReferencingChild()
+                        || childLeafRefContext.isReferencing()) {
+                    currentLeafRefContextBuilder.addReferencingChild(
+                            childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+        } else if (node instanceof ChoiceSchemaNode) {
+
+            final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
+            final Set<ChoiceCaseNode> cases = choice.getCases();
+            // :FIXME choice without case
+
+            for (final ChoiceCaseNode caseNode : cases) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencingTree(
+                        caseNode, currentModule);
+
+                if (childLeafRefContext.hasReferencingChild()
+                        || childLeafRefContext.isReferencing()) {
+                    currentLeafRefContextBuilder.addReferencingChild(
+                            childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+
+        } else if (node instanceof LeafSchemaNode
+                || node instanceof LeafListSchemaNode) {
+
+            TypeDefinition<?> type = null;
+
+            if (node instanceof LeafSchemaNode) {
+                type = ((LeafSchemaNode) node).getType();
+            } else {
+                type = ((LeafListSchemaNode) node).getType();
+            }
+
+            // FIXME: fix case when type is e.g. typdef -> typedef -> leafref
+            if (type instanceof Leafref) {
+                final Leafref leafrefType = (Leafref) type;
+                final String leafRefPathString = leafrefType.getPathStatement()
+                        .toString();
+
+                currentLeafRefContextBuilder
+                        .setLeafRefTargetPathString(leafRefPathString);
+                currentLeafRefContextBuilder.setReferencing(true);
+
+                final LeafRefPathParserImpl leafRefPathParser = new LeafRefPathParserImpl(
+                        schemaContext, currentModule, node);
+
+                final ByteArrayInputStream leafRefPathInputStream = new ByteArrayInputStream(
+                        leafRefPathString.getBytes(Charset.forName("UTF-8")));
+                final LeafRefPath leafRefPath = leafRefPathParser
+                        .parseLeafRefPathSourceToSchemaPath(leafRefPathInputStream);
+
+                currentLeafRefContextBuilder.setLeafRefTargetPath(leafRefPath);
+
+                final LeafRefContext currentLeafRefContext = currentLeafRefContextBuilder
+                        .build();
+                leafRefs.add(currentLeafRefContext);
+                return currentLeafRefContext;
+            }
+        }
+
+        return currentLeafRefContextBuilder.build();
+    }
+
+    private LeafRefContext buildLeafRefContextReferencedByTree(
+            final DataSchemaNode node, final Module currentModule) throws IOException,
+            LeafRefYangSyntaxErrorException {
+
+        final LeafRefContextBuilder currentLeafRefContextBuilder = new LeafRefContextBuilder(
+                node.getQName(), node.getPath(), schemaContext);
+
+        if (node instanceof DataNodeContainer) {
+            final DataNodeContainer dataNodeContainer = (DataNodeContainer) node;
+            final Collection<DataSchemaNode> childNodes = dataNodeContainer
+                    .getChildNodes();
+
+            for (final DataSchemaNode childNode : childNodes) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+                        childNode, currentModule);
+
+                if (childLeafRefContext.hasReferencedChild()
+                        || childLeafRefContext.isReferenced()) {
+                    currentLeafRefContextBuilder.addReferencedByChild(
+                            childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+        } else if (node instanceof ChoiceSchemaNode) {
+
+            final ChoiceSchemaNode choice = (ChoiceSchemaNode) node;
+            final Set<ChoiceCaseNode> cases = choice.getCases();
+
+            for (final ChoiceCaseNode caseNode : cases) {
+                final LeafRefContext childLeafRefContext = buildLeafRefContextReferencedByTree(
+                        caseNode, currentModule);
+
+                if (childLeafRefContext.hasReferencedChild()
+                        || childLeafRefContext.isReferenced()) {
+                    currentLeafRefContextBuilder.addReferencedByChild(
+                            childLeafRefContext,
+                            childLeafRefContext.getNodeName());
+                }
+            }
+
+        } else if (node instanceof LeafSchemaNode
+                || node instanceof LeafListSchemaNode) {
+
+            final LinkedList<LeafRefContext> foundLeafRefs = getLeafRefsFor(node,
+                    currentModule);
+            if (!foundLeafRefs.isEmpty()) {
+                currentLeafRefContextBuilder.setReferencedBy(true);
+                for (final LeafRefContext leafRef : foundLeafRefs) {
+                    currentLeafRefContextBuilder.addReferencedByLeafRefCtx(
+                            leafRef.getNodeName(), leafRef);
+                }
+            }
+        }
+
+        return currentLeafRefContextBuilder.build();
+    }
+
+    private LinkedList<LeafRefContext> getLeafRefsFor(final DataSchemaNode node,
+            final Module module) {
+        final LeafRefPath nodeXPath = LeafRefUtils.schemaPathToLeafRefPath(
+                node.getPath(), module);
+
+        final LinkedList<LeafRefContext> foundLeafRefs = new LinkedList<LeafRefContext>();
+
+        for (final LeafRefContext leafref : leafRefs) {
+            final LeafRefPath leafRefTargetPath = leafref
+                    .getAbsoluteLeafRefTargetPath();
+            if (leafRefTargetPath.equals(nodeXPath)) {
+                foundLeafRefs.add(leafref);
+            }
+        }
+
+        return foundLeafRefs;
+    }
+
+    // private LeafRefContext buildLeafRefContextTreeFor(LeafRefContext parent,
+    // Module module) {
+    //
+    // Collection<DataSchemaNode> childNodes = module.getChildNodes();
+    // for (DataSchemaNode childNode : childNodes) {
+    // LeafRefContext childLeafRefContext = buildLeafRefContextTreeFor(parent,
+    // childNode);
+    //
+    // if(childLeafRefContext.hasReferencedByChild() ||
+    // childLeafRefContext.isReferencedBy()) {
+    // parent.addReferencedByChild(childLeafRefContext,
+    // childLeafRefContext.getCurrentNodeQName());
+    // }
+    // if(childLeafRefContext.hasReferencingChild() ||
+    // childLeafRefContext.isReferencing()) {
+    // parent.addReferencingChild(childLeafRefContext,
+    // childLeafRefContext.getCurrentNodeQName());
+    // }
+    // }
+    //
+    // return node;
+    // }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefContextUtils.java
new file mode 100644 (file)
index 0000000..6206df8
--- /dev/null
@@ -0,0 +1,250 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public final class LeafRefContextUtils {
+
+    private LeafRefContextUtils() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static LeafRefContext getLeafRefReferencingContext(final SchemaNode node,
+            final LeafRefContext root) {
+        final SchemaPath schemaPath = node.getPath();
+        return getLeafRefReferencingContext(schemaPath, root);
+    }
+
+    public static LeafRefContext getLeafRefReferencingContext(
+            final SchemaPath schemaPath, final LeafRefContext root) {
+        final Iterable<QName> pathFromRoot = schemaPath.getPathFromRoot();
+        return getLeafRefReferencingContext(pathFromRoot, root);
+    }
+
+    public static LeafRefContext getLeafRefReferencingContext(
+            final Iterable<QName> pathFromRoot, LeafRefContext root) {
+
+        LeafRefContext leafRefCtx = null;
+        final Iterator<QName> iterator = pathFromRoot.iterator();
+        while (iterator.hasNext() && root != null) {
+            final QName qname = iterator.next();
+            leafRefCtx = root.getReferencingChildByName(qname);
+            if (iterator.hasNext()) {
+                root = leafRefCtx;
+            }
+        }
+
+        return leafRefCtx;
+    }
+
+    public static LeafRefContext getLeafRefReferencedByContext(final SchemaNode node,
+            final LeafRefContext root) {
+        final SchemaPath schemaPath = node.getPath();
+        return getLeafRefReferencedByContext(schemaPath, root);
+    }
+
+    public static LeafRefContext getLeafRefReferencedByContext(
+            final SchemaPath schemaPath, final LeafRefContext root) {
+        final Iterable<QName> pathFromRoot = schemaPath.getPathFromRoot();
+        return getLeafRefReferencedByContext(pathFromRoot, root);
+    }
+
+    public static LeafRefContext getLeafRefReferencedByContext(
+            final Iterable<QName> pathFromRoot, LeafRefContext root) {
+
+        LeafRefContext leafRefCtx = null;
+        final Iterator<QName> iterator = pathFromRoot.iterator();
+        while (iterator.hasNext() && root != null) {
+            final QName qname = iterator.next();
+            leafRefCtx = root.getReferencedChildByName(qname);
+            if (iterator.hasNext()) {
+                root = leafRefCtx;
+            }
+        }
+
+        return leafRefCtx;
+    }
+
+    public static boolean isLeafRef(final SchemaNode node, final LeafRefContext root) {
+
+        if ((node == null) || (root == null))
+            return false;
+
+        final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+                node, root);
+        if (leafRefReferencingContext == null)
+            return false;
+
+        return leafRefReferencingContext.isReferencing();
+    }
+
+    public static boolean hasLeafRefChild(final SchemaNode node, final LeafRefContext root) {
+
+        if ((node == null) || (root == null))
+            return false;
+
+        final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+                node, root);
+        if (leafRefReferencingContext == null)
+            return false;
+
+        return leafRefReferencingContext.hasReferencingChild();
+    }
+
+    public static boolean isReferencedByLeafRef(final SchemaNode node,
+            final LeafRefContext root) {
+
+        if ((node == null) || (root == null))
+            return false;
+
+        final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+                node, root);
+        if (leafRefReferencedByContext == null)
+            return false;
+
+        return leafRefReferencedByContext.isReferenced();
+    }
+
+    public static boolean hasChildReferencedByLeafRef(final SchemaNode node,
+            final LeafRefContext root) {
+
+        if ((node == null) || (root == null))
+            return false;
+
+        final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+                node, root);
+        if (leafRefReferencedByContext == null)
+            return false;
+
+        return leafRefReferencedByContext.hasReferencedChild();
+    }
+
+    public static List<LeafRefContext> findAllLeafRefChilds(final SchemaNode node,
+            final LeafRefContext root) {
+
+        return findAllLeafRefChilds(node.getPath(), root);
+    }
+
+    public static List<LeafRefContext> findAllLeafRefChilds(
+            final SchemaPath schemaPath, final LeafRefContext root) {
+
+        return findAllLeafRefChilds(schemaPath.getPathFromRoot(), root);
+    }
+
+    public static List<LeafRefContext> findAllLeafRefChilds(
+            final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+        final LeafRefContext leafRefReferencingContext = getLeafRefReferencingContext(
+                pathFromRoot, root);
+        final List<LeafRefContext> allLeafRefsChilds = findAllLeafRefChilds(leafRefReferencingContext);
+
+        return allLeafRefsChilds;
+    }
+
+    public static List<LeafRefContext> findAllLeafRefChilds(
+            final LeafRefContext parent) {
+
+        final LinkedList<LeafRefContext> leafRefChilds = new LinkedList<LeafRefContext>();
+
+        if (parent == null) {
+            return leafRefChilds;
+        }
+
+        if (parent.isReferencing()) {
+            leafRefChilds.add(parent);
+            return leafRefChilds;
+        } else {
+            final Set<Entry<QName, LeafRefContext>> childs = parent
+                    .getReferencingChilds().entrySet();
+            for (final Entry<QName, LeafRefContext> child : childs) {
+                leafRefChilds.addAll(findAllLeafRefChilds(child.getValue()));
+            }
+        }
+        return leafRefChilds;
+    }
+
+    public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+            final SchemaNode node, final LeafRefContext root) {
+
+        return findAllChildsReferencedByLeafRef(node.getPath(), root);
+    }
+
+    public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+            final SchemaPath schemaPath, final LeafRefContext root) {
+
+        return findAllChildsReferencedByLeafRef(schemaPath.getPathFromRoot(),
+                root);
+    }
+
+    public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+            final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+        final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+                pathFromRoot, root);
+        final List<LeafRefContext> allChildsReferencedByLeafRef = findAllChildsReferencedByLeafRef(leafRefReferencedByContext);
+
+        return allChildsReferencedByLeafRef;
+    }
+
+    public static List<LeafRefContext> findAllChildsReferencedByLeafRef(
+            final LeafRefContext parent) {
+
+        final LinkedList<LeafRefContext> childsReferencedByLeafRef = new LinkedList<LeafRefContext>();
+
+        if (parent == null) {
+            return childsReferencedByLeafRef;
+        }
+
+        if (parent.isReferenced()) {
+            childsReferencedByLeafRef.add(parent);
+            return childsReferencedByLeafRef;
+        } else {
+            final Set<Entry<QName, LeafRefContext>> childs = parent
+                    .getReferencedByChilds().entrySet();
+            for (final Entry<QName, LeafRefContext> child : childs) {
+                childsReferencedByLeafRef
+                        .addAll(findAllChildsReferencedByLeafRef(child
+                                .getValue()));
+            }
+        }
+        return childsReferencedByLeafRef;
+    }
+
+    public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+            final SchemaNode node, final LeafRefContext root) {
+        return getAllLeafRefsReferencingThisNode(node.getPath(), root);
+    }
+
+    public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+            final SchemaPath path, final LeafRefContext root) {
+        return getAllLeafRefsReferencingThisNode(path.getPathFromRoot(), root);
+    }
+
+    public static Map<QName, LeafRefContext> getAllLeafRefsReferencingThisNode(
+            final Iterable<QName> pathFromRoot, final LeafRefContext root) {
+
+        final LeafRefContext leafRefReferencedByContext = getLeafRefReferencedByContext(
+                pathFromRoot, root);
+
+        if (leafRefReferencedByContext == null)
+            return new HashMap<QName, LeafRefContext>();
+
+        return leafRefReferencedByContext.getAllReferencedByLeafRefCtxs();
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefDataValidationFailedException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefDataValidationFailedException.java
new file mode 100644 (file)
index 0000000..3ddb01e
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+public class LeafRefDataValidationFailedException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+    private int errorsCount = 1;
+
+    public LeafRefDataValidationFailedException(String message) {
+        super(message);
+    }
+
+    public LeafRefDataValidationFailedException(String message, int errorsCount) {
+        super(message);
+        this.errorsCount = errorsCount;
+    }
+
+    public LeafRefDataValidationFailedException(String message,
+            final Throwable cause) {
+        super(message, cause);
+    }
+
+    public int getValidationsErrorsCount() {
+        return errorsCount;
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPath.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPath.java
new file mode 100644 (file)
index 0000000..649d911
--- /dev/null
@@ -0,0 +1,374 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.concepts.Immutable;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+public abstract class LeafRefPath implements Immutable {
+
+    /**
+     * An absolute LeafRefPath.
+     */
+    private static final class AbsoluteLeafRefPath extends LeafRefPath {
+        private AbsoluteLeafRefPath(final LeafRefPath parent,
+                final QNameWithPredicate qname) {
+            super(parent, qname);
+        }
+
+        @Override
+        public boolean isAbsolute() {
+            return true;
+        }
+
+        @Override
+        protected LeafRefPath createInstance(final LeafRefPath parent,
+                final QNameWithPredicate qname) {
+            return new AbsoluteLeafRefPath(parent, qname);
+        }
+    }
+
+    /**
+     * A relative LeafRefPath.
+     */
+    private static final class RelativeLeafRefPath extends LeafRefPath {
+        private RelativeLeafRefPath(final LeafRefPath parent,
+                final QNameWithPredicate qname) {
+            super(parent, qname);
+        }
+
+        @Override
+        public boolean isAbsolute() {
+            return false;
+        }
+
+        @Override
+        protected LeafRefPath createInstance(final LeafRefPath parent,
+                final QNameWithPredicate qname) {
+            return new RelativeLeafRefPath(parent, qname);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static final AtomicReferenceFieldUpdater<LeafRefPath, ImmutableList> LEGACYPATH_UPDATER = AtomicReferenceFieldUpdater
+            .newUpdater(LeafRefPath.class, ImmutableList.class, "legacyPath");
+
+    /**
+     * Shared instance of the conceptual root schema node.
+     */
+    public static final LeafRefPath ROOT = new AbsoluteLeafRefPath(null, null);
+
+    /**
+     * Shared instance of the "same" relative schema node.
+     */
+    public static final LeafRefPath SAME = new RelativeLeafRefPath(null, null);
+
+    /**
+     * Parent path.
+     */
+    private final LeafRefPath parent;
+
+    /**
+     * This component.
+     */
+    private final QNameWithPredicate qname;
+
+    /**
+     * Cached hash code. We can use this since we are immutable.
+     */
+    private final int hash;
+
+    /**
+     * Cached legacy path, filled-in when {@link #getPath()} or
+     * {@link #getPathTowardsRoot()} is invoked.
+     */
+    private volatile ImmutableList<QNameWithPredicate> legacyPath;
+
+    private ImmutableList<QNameWithPredicate> getLegacyPath() {
+        ImmutableList<QNameWithPredicate> ret = legacyPath;
+        if (ret == null) {
+            ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse();
+            LEGACYPATH_UPDATER.lazySet(this, ret);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Returns the complete path to schema node.
+     *
+     * @return list of <code>QNameWithPredicate</code> instances which
+     *         represents complete path to schema node
+     *
+     * @deprecated Use {@link #getPathFromRoot()} instead.
+     */
+    @Deprecated
+    public List<QNameWithPredicate> getPath() {
+        return getLegacyPath();
+    }
+
+    protected LeafRefPath(final LeafRefPath parent,
+            final QNameWithPredicate qname) {
+        this.parent = parent;
+        this.qname = qname;
+
+        int h = parent == null ? 0 : parent.hashCode();
+        if (qname != null) {
+            h = h * 31 + qname.hashCode();
+        }
+
+        hash = h;
+    }
+
+    /**
+     * Constructs new instance of this class with the concrete path.
+     *
+     * @param path
+     *            list of QNameWithPredicate instances which specifies exact
+     *            path to the module node
+     * @param absolute
+     *            boolean value which specifies if the path is absolute or
+     *            relative
+     *
+     * @return A LeafRefPath instance.
+     */
+    public static LeafRefPath create(final Iterable<QNameWithPredicate> path,
+            final boolean absolute) {
+        final LeafRefPath parent = absolute ? ROOT : SAME;
+        return parent.createChild(path);
+    }
+
+    /**
+     * Constructs new instance of this class with the concrete path.
+     *
+     * @param absolute
+     *            boolean value which specifies if the path is absolute or
+     *            relative
+     * @param path
+     *            one or more QNameWithPredicate instances which specifies exact
+     *            path to the module node
+     *
+     * @return A LeafRefPath instance.
+     */
+    public static LeafRefPath create(final boolean absolute,
+            final QNameWithPredicate... path) {
+        return create(Arrays.asList(path), absolute);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param parent
+     *            Parent LeafRefPath
+     * @param qname
+     *            next path element
+     * @return A new LeafRefPath instance
+     */
+    protected abstract LeafRefPath createInstance(LeafRefPath parent,
+            QNameWithPredicate qname);
+
+    /**
+     * Create a child path based on concatenation of this path and a relative
+     * path.
+     *
+     * @param relative
+     *            Relative path
+     * @return A new child path
+     */
+    public LeafRefPath createChild(final Iterable<QNameWithPredicate> relative) {
+        if (Iterables.isEmpty(relative)) {
+            return this;
+        }
+
+        LeafRefPath parent = this;
+        for (QNameWithPredicate qname : relative) {
+            parent = parent.createInstance(parent, qname);
+        }
+
+        return parent;
+    }
+
+    /**
+     * Create a child path based on concatenation of this path and a relative
+     * path.
+     *
+     * @param relative
+     *            Relative LeafRefPath
+     * @return A new child path
+     */
+    public LeafRefPath createChild(final LeafRefPath relative) {
+        Preconditions.checkArgument(!relative.isAbsolute(),
+                "Child creation requires relative path");
+
+        LeafRefPath parent = this;
+        for (QNameWithPredicate qname : relative.getPathFromRoot()) {
+            parent = parent.createInstance(parent, qname);
+        }
+
+        return parent;
+    }
+
+    /**
+     * Create a child path based on concatenation of this path and additional
+     * path elements.
+     *
+     * @param elements
+     *            Relative LeafRefPath elements
+     * @return A new child path
+     */
+    public LeafRefPath createChild(final QNameWithPredicate... elements) {
+        return createChild(Arrays.asList(elements));
+    }
+
+    /**
+     * Returns the list of nodes which need to be traversed to get from the
+     * starting point (root for absolute LeafRefPaths) to the node represented
+     * by this object.
+     *
+     * @return list of <code>qname</code> instances which represents path from
+     *         the root to the schema node.
+     */
+    public Iterable<QNameWithPredicate> getPathFromRoot() {
+        return getLegacyPath();
+    }
+
+    /**
+     * Returns the list of nodes which need to be traversed to get from this
+     * node to the starting point (root for absolute LeafRefPaths).
+     *
+     * @return list of <code>qname</code> instances which represents path from
+     *         the schema node towards the root.
+     */
+    public Iterable<QNameWithPredicate> getPathTowardsRoot() {
+        return new Iterable<QNameWithPredicate>() {
+            @Override
+            public Iterator<QNameWithPredicate> iterator() {
+                return new Iterator<QNameWithPredicate>() {
+                    private LeafRefPath current = LeafRefPath.this;
+
+                    @Override
+                    public boolean hasNext() {
+                        return current.parent != null;
+                    }
+
+                    @Override
+                    public QNameWithPredicate next() {
+                        if (current.parent != null) {
+                            final QNameWithPredicate ret = current.qname;
+                            current = current.parent;
+                            return ret;
+                        } else {
+                            throw new NoSuchElementException(
+                                    "No more elements available");
+                        }
+                    }
+
+                    @Override
+                    public void remove() {
+                        throw new UnsupportedOperationException(
+                                "Component removal not supported");
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Returns the immediate parent LeafRefPath.
+     *
+     * @return Parent path, null if this LeafRefPath is already toplevel.
+     */
+    public LeafRefPath getParent() {
+        return parent;
+    }
+
+    /**
+     * Get the last component of this path.
+     *
+     * @return The last component of this path.
+     */
+    public final QNameWithPredicate getLastComponent() {
+        return qname;
+    }
+
+    /**
+     * Describes whether schema path is|isn't absolute.
+     *
+     * @return boolean value which is <code>true</code> if schema path is
+     *         absolute.
+     */
+    public abstract boolean isAbsolute();
+
+    @Override
+    public final int hashCode() {
+        return hash;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final LeafRefPath other = (LeafRefPath) obj;
+
+        if (qname != null) {
+            if (!qname.equals(other.qname)) {
+                return false;
+            }
+        } else {
+            if (other.qname != null) {
+                return false;
+            }
+        }
+
+        if (parent == null) {
+            return other.parent == null;
+        }
+        return parent.equals(other.parent);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        Iterable<QNameWithPredicate> pathFromRoot = this.getPathFromRoot();
+
+        sb.append(isAbsolute() ? "Absolute path:" : "Relative path:");
+
+        for (QNameWithPredicate qName : pathFromRoot) {
+            sb.append("/" + qName);
+        }
+
+        return sb.toString();
+
+    }
+
+    // @Override
+    // public final String toString() {
+    // return addToStringAttributes(Objects.toStringHelper(this)).toString();
+    // }
+    //
+    // protected ToStringHelper addToStringAttributes(final ToStringHelper
+    // toStringHelper) {
+    // return toStringHelper.add("path", getPathFromRoot());
+    // }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathErrorListener.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathErrorListener.java
new file mode 100644 (file)
index 0000000..c8098e2
--- /dev/null
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class LeafRefPathErrorListener extends BaseErrorListener {
+    private static final Logger LOG = LoggerFactory
+            .getLogger(LeafRefPathErrorListener.class);
+    private final List<LeafRefPathSyntaxErrorException> exceptions = new ArrayList<>();
+    private final Module module;
+
+    public LeafRefPathErrorListener(final Module module) {
+        this.module = module;
+    }
+
+    @Override
+    public void syntaxError(final Recognizer<?, ?> recognizer,
+            final Object offendingSymbol, final int line,
+            final int charPositionInLine, final String msg,
+            final RecognitionException e) {
+        LOG.debug("Syntax error in module {} at {}:{}: {}", module.getName(), line, charPositionInLine, msg, e);
+
+        exceptions.add(new LeafRefPathSyntaxErrorException(module.getName(), line,
+                charPositionInLine, msg, e));
+    }
+
+    public void validate() throws LeafRefPathSyntaxErrorException {
+        if (exceptions.isEmpty()) {
+            return;
+        }
+
+        // Single exception: just throw it
+        if (exceptions.size() == 1) {
+            throw exceptions.get(0);
+        }
+
+        final StringBuilder sb = new StringBuilder();
+        String module = null;
+        boolean first = true;
+        for (final LeafRefPathSyntaxErrorException e : exceptions) {
+            if (module == null) {
+                module = e.getModule();
+            }
+            if (first) {
+                first = false;
+            } else {
+                sb.append('\n');
+            }
+
+            sb.append(e.getFormattedMessage());
+        }
+
+        throw new LeafRefPathSyntaxErrorException(module, 0, 0, sb.toString());
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParseException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParseException.java
new file mode 100644 (file)
index 0000000..55f6030
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+class LeafRefPathParseException extends RuntimeException {
+
+    private static final long serialVersionUID = 7819033841757805240L;
+
+    public LeafRefPathParseException(final String errorMsg) {
+        super(errorMsg);
+
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserImpl.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserImpl.java
new file mode 100644 (file)
index 0000000..e7d03c1
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.IOException;
+import java.io.InputStream;
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_argContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+final class LeafRefPathParserImpl {
+    private final SchemaContext schemaContext;
+    private final Module module;
+    private final SchemaNode node;
+
+     public LeafRefPathParserImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
+        this.schemaContext = schemaContext;
+        this.module = currentModule;
+        this.node = currentNode;
+    }
+
+    public LeafRefPath parseLeafRefPathSourceToSchemaPath(final InputStream stream) throws IOException, LeafRefYangSyntaxErrorException {
+
+        final Path_argContext pathCtx = parseLeafRefPathSource(stream);
+
+        final ParseTreeWalker walker = new ParseTreeWalker();
+        final LeafRefPathParserListenerImpl leafRefPathParserListenerImpl = new LeafRefPathParserListenerImpl(schemaContext, module, node);
+        walker.walk(leafRefPathParserListenerImpl,pathCtx);
+
+        final LeafRefPath leafRefPath = leafRefPathParserListenerImpl.getLeafRefPath();
+
+        return leafRefPath;
+    }
+
+
+    private Path_argContext parseLeafRefPathSource(final InputStream stream) throws IOException, LeafRefYangSyntaxErrorException {
+        final LeafRefPathLexer lexer = new LeafRefPathLexer(new ANTLRInputStream(stream));
+        final CommonTokenStream tokens = new CommonTokenStream(lexer);
+        final LeafRefPathParser parser = new LeafRefPathParser(tokens);
+        parser.removeErrorListeners();
+
+        final LeafRefPathErrorListener errorListener = new LeafRefPathErrorListener(module);
+        parser.addErrorListener(errorListener);
+
+        final Path_argContext result = parser.path_arg();
+        errorListener.validate();
+
+        return result;
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserListenerImpl.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathParserListenerImpl.java
new file mode 100644 (file)
index 0000000..4589fb4
--- /dev/null
@@ -0,0 +1,215 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import java.net.URI;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.IdentifierContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Node_identifierContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_argContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_equality_exprContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Path_predicateContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.PrefixContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Rel_path_keyexprContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefPathParser.Relative_pathContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+
+
+final class LeafRefPathParserListenerImpl extends LeafRefPathParserBaseListener{
+
+    private final SchemaContext schemaContext;
+    private final Module module;
+    private LeafRefPath leafRefPath;
+    private boolean relativePath=false;
+    private QNameWithPredicateBuilder currentLeafRefPathQName;
+    private QNamePredicateBuilder currentPredicate;
+    private QNameModule currentQnameModule;
+    private String currentQNameLocalName;
+    private final LinkedList<QNameWithPredicateBuilder> leafRefPathQnameList;
+    private LinkedList<QNameWithPredicateBuilder> predicatePathKeyQnameList;
+    private final SchemaNode node; //FIXME use for identifier path completion
+    private ParsingState currentParsingState;
+
+    Function<QNameWithPredicateBuilder, QNameWithPredicate> build = new Function<QNameWithPredicateBuilder, QNameWithPredicate>() {
+        @Override
+        public QNameWithPredicate apply(final QNameWithPredicateBuilder builder) {
+           return builder.build();
+        }
+     };
+
+    private enum ParsingState {
+        LEAF_REF_PATH, PATH_PREDICATE, PREDICATE_PATH_EQUALITY_EXPR, PATH_KEY_EXPR
+    }
+
+    public LeafRefPathParserListenerImpl(final SchemaContext schemaContext, final Module currentModule, final SchemaNode currentNode) {
+       this.schemaContext = schemaContext;
+       this.module = currentModule;
+       this.leafRefPathQnameList = new LinkedList<QNameWithPredicateBuilder>();
+       this.node=currentNode;
+       this.currentParsingState = ParsingState.LEAF_REF_PATH;
+    }
+
+    @Override
+    public void enterPath_predicate(final Path_predicateContext ctx) {
+        currentParsingState=ParsingState.PATH_PREDICATE;
+        currentPredicate = new QNamePredicateBuilder();
+    }
+
+
+    @Override
+    public void exitPath_predicate(final Path_predicateContext ctx) {
+        currentLeafRefPathQName.addQNamePredicate(currentPredicate.build());
+        currentPredicate = null;
+        currentParsingState=ParsingState.LEAF_REF_PATH;
+    }
+
+
+    @Override
+    public void enterRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
+        currentParsingState=ParsingState.PATH_KEY_EXPR;
+        predicatePathKeyQnameList = new LinkedList<QNameWithPredicateBuilder>();
+        final List<TerminalNode> dots = ctx.DOTS();
+        for (final TerminalNode parent : dots) {
+            predicatePathKeyQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
+        }
+    }
+
+
+    @Override
+    public void exitRel_path_keyexpr(final Rel_path_keyexprContext ctx) {
+
+        final LeafRefPath pathKeyExpression = LeafRefPath.create(Lists.transform(predicatePathKeyQnameList,build), false);
+        currentPredicate.setPathKeyExpression(pathKeyExpression);
+
+        currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
+    }
+
+    @Override
+    public void enterRelative_path(final Relative_pathContext ctx) {
+
+        relativePath = true;
+        final List<TerminalNode> dots = ctx.DOTS();
+        for (final TerminalNode parent : dots) {
+            leafRefPathQnameList.add(QNameWithPredicateBuilder.UP_PARENT_BUILDER);
+        }
+
+    }
+
+    @Override
+    public void enterPath_equality_expr(final Path_equality_exprContext ctx) {
+        currentParsingState=ParsingState.PREDICATE_PATH_EQUALITY_EXPR;
+    }
+
+
+    @Override
+    public void exitPath_equality_expr(final Path_equality_exprContext ctx) {
+
+        currentParsingState=ParsingState.PATH_PREDICATE;
+    }
+
+    @Override
+    public void enterPrefix(final PrefixContext ctx) {
+
+        if (module.getPrefix().equals(ctx.getText())) {
+            currentQnameModule = module.getQNameModule();
+        } else {
+            currentQnameModule = getQNameModuleForImportPrefix(ctx.getText());
+        }
+    }
+
+    @Override
+    public void exitPath_arg(final Path_argContext ctx) {
+        leafRefPath = LeafRefPath.create(Lists.transform(leafRefPathQnameList,build), !relativePath);
+    }
+
+
+    @Override
+    public void enterIdentifier(final IdentifierContext ctx) {
+        currentQNameLocalName = ctx.getText();
+    }
+
+    @Override
+    public void exitNode_identifier(final Node_identifierContext ctx) {
+
+        if (currentQnameModule == null) {
+            currentQnameModule = module.getQNameModule();
+        }
+
+        if (currentParsingState == ParsingState.PREDICATE_PATH_EQUALITY_EXPR) {
+            final QName qname = QName.create(currentQnameModule,
+                    currentQNameLocalName);
+            currentPredicate.setIdentifier(qname);
+        } else {
+
+            final QNameWithPredicateBuilder qnameBuilder = new QNameWithPredicateBuilder(
+                    currentQnameModule, currentQNameLocalName);
+
+            if (currentParsingState == ParsingState.PATH_KEY_EXPR) {
+                predicatePathKeyQnameList.add(qnameBuilder);
+            } else if (currentParsingState == ParsingState.LEAF_REF_PATH) {
+                currentLeafRefPathQName = qnameBuilder;
+                leafRefPathQnameList.add(qnameBuilder);
+            }
+        }
+        currentQnameModule = null;
+        currentQNameLocalName = null;
+    }
+
+    public LeafRefPath getLeafRefPath() {
+        return leafRefPath;
+    }
+
+
+    private URI getNamespaceForImportPrefix(final String prefix){
+        final ModuleImport moduleImport = getModuleImport(prefix);
+        final Module findedModule = schemaContext.findModuleByName(moduleImport.getModuleName(), moduleImport.getRevision());
+
+        return findedModule.getNamespace();
+    }
+
+    private QNameModule getQNameModuleForImportPrefix(final String prefix) {
+        final ModuleImport moduleImport = getModuleImport(prefix);
+
+        if (moduleImport == null) {
+            throw new LeafRefPathParseException("No module import for prefix: "
+                    + prefix + " in module: " + module.getName());
+        }
+
+        final String moduleName = moduleImport.getModuleName();
+        final Date revision = moduleImport.getRevision();
+        final Module findedModule = schemaContext.findModuleByName(moduleName,
+                revision);
+
+        return findedModule.getQNameModule();
+    }
+
+
+    private ModuleImport getModuleImport(final String prefix) {
+        final Set<ModuleImport> imports = module.getImports();
+
+        for (final ModuleImport moduleImport : imports) {
+            if(moduleImport.getPrefix().equals(prefix)) {
+                return moduleImport;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathSyntaxErrorException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefPathSyntaxErrorException.java
new file mode 100644 (file)
index 0000000..01e68ac
--- /dev/null
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+public class LeafRefPathSyntaxErrorException extends LeafRefYangSyntaxErrorException{
+
+    private static final long serialVersionUID = 1L;
+
+    public LeafRefPathSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+            final String message) {
+        super(module, line, charPositionInLine, message, null);
+    }
+
+    public LeafRefPathSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+            final String message, final Throwable cause) {
+        super(module,line,charPositionInLine,message,cause);
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefUtils.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefUtils.java
new file mode 100644 (file)
index 0000000..ec06075
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public class LeafRefUtils {
+
+    /**
+     * @param leafRefPath
+     * @param contextNodeSchemaPath
+     * @return
+     */
+    public static LeafRefPath createAbsoluteLeafRefPath(
+            final LeafRefPath leafRefPath, final SchemaPath contextNodeSchemaPath,
+            final Module module) {
+
+        if (leafRefPath.isAbsolute())
+            return leafRefPath;
+
+        final LinkedList<QNameWithPredicate> absoluteLeafRefTargetPathList = schemaPathToXPathQNames(
+                contextNodeSchemaPath, module);
+
+        final Iterable<QNameWithPredicate> leafRefTargetPathFromRoot = leafRefPath
+                .getPathFromRoot();
+        final Iterator<QNameWithPredicate> leafRefTgtPathFromRootIterator = leafRefTargetPathFromRoot
+                .iterator();
+
+        while (leafRefTgtPathFromRootIterator.hasNext()) {
+            final QNameWithPredicate qname = leafRefTgtPathFromRootIterator.next();
+            if (qname.equals(QNameWithPredicate.UP_PARENT)) {
+                absoluteLeafRefTargetPathList.removeLast();
+            } else {
+                absoluteLeafRefTargetPathList.add(qname);
+            }
+        }
+
+        return LeafRefPath.create(absoluteLeafRefTargetPathList, true);
+    }
+
+    /**
+     * @param currentNodePath
+     * @param module
+     * @param absoluteLeafRefTargetPathList
+     */
+    private static LinkedList<QNameWithPredicate> schemaPathToXPathQNames(
+            final SchemaPath nodePath, final Module module) {
+
+        final LinkedList<QNameWithPredicate> xpath = new LinkedList<QNameWithPredicate>();
+
+        final Iterator<QName> nodePathIterator = nodePath.getPathFromRoot()
+                .iterator();
+
+        DataNodeContainer currenDataNodeContainer = module;
+        while (nodePathIterator.hasNext()) {
+            final QName qname = nodePathIterator.next();
+            final DataSchemaNode child = currenDataNodeContainer
+                    .getDataChildByName(qname);
+
+            if (child instanceof DataNodeContainer) {
+                if (!(child instanceof ChoiceCaseNode)) {
+                    final QNameWithPredicate newQName = new QNameWithPredicateBuilder(
+                            qname.getModule(), qname.getLocalName()).build();
+                    xpath.add(newQName);
+                }
+                currenDataNodeContainer = (DataNodeContainer) child;
+            } else if (child instanceof ChoiceSchemaNode) {
+                if (nodePathIterator.hasNext()) {
+                    currenDataNodeContainer = ((ChoiceSchemaNode) child)
+                            .getCaseNodeByName(nodePathIterator.next());
+                } else {
+                    break;
+                }
+            } else if (child instanceof LeafSchemaNode
+                    || child instanceof LeafListSchemaNode) {
+
+                final QNameWithPredicate newQName = new QNameWithPredicateBuilder(
+                        qname.getModule(), qname.getLocalName()).build();
+                xpath.add(newQName);
+                break;
+
+            } else if (child == null) {
+                throw new IllegalArgumentException("No child " + qname
+                        + " found in node container " + currenDataNodeContainer
+                        + " in module " + module.getName());
+            } else {
+                throw new IllegalStateException(
+                        "Illegal schema node type in the path: "
+                                + child.getClass());
+            }
+        }
+
+        return xpath;
+    }
+
+    public static LeafRefPath schemaPathToLeafRefPath(final SchemaPath nodePath,
+            final Module module) {
+        final LinkedList<QNameWithPredicate> xpathQNames = schemaPathToXPathQNames(
+                nodePath, module);
+        return LeafRefPath.create(xpathQNames, true);
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidatation.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefValidatation.java
new file mode 100644 (file)
index 0000000..4200615
--- /dev/null
@@ -0,0 +1,699 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LeafRefValidatation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LeafRefValidatation.class);
+    private static final String NEW_LINE = System.getProperty("line.separator");
+
+    private final DataTreeCandidate tree;
+    private final LinkedList<String> errorsMessages =  new LinkedList<String>();
+    private final HashSet<LeafRefContext> validatedLeafRefCtx =  new HashSet<LeafRefContext>();
+
+    private LeafRefValidatation(final DataTreeCandidate tree) {
+        this.tree = tree;
+    }
+
+    public static void validate(final DataTreeCandidate tree, final LeafRefContext rootLeafRefCtx)
+            throws LeafRefDataValidationFailedException {
+        new LeafRefValidatation(tree).validate0(rootLeafRefCtx);
+    }
+    private void validate0(final LeafRefContext rootLeafRefCtx)
+            throws LeafRefDataValidationFailedException {
+
+        final DataTreeCandidateNode rootNode = tree.getRootNode();
+
+        final Collection<DataTreeCandidateNode> childNodes = rootNode.getChildNodes();
+        for (final DataTreeCandidateNode dataTreeCandidateNode : childNodes) {
+
+            final ModificationType modificationType = dataTreeCandidateNode
+                    .getModificationType();
+            if (modificationType != ModificationType.UNMODIFIED) {
+
+                final PathArgument identifier = dataTreeCandidateNode.getIdentifier();
+                final QName childQName = identifier.getNodeType();
+
+                final LeafRefContext referencedByCtx = rootLeafRefCtx
+                        .getReferencedChildByName(childQName);
+                final LeafRefContext referencingCtx = rootLeafRefCtx
+                        .getReferencingChildByName(childQName);
+                if (referencedByCtx != null || referencingCtx != null) {
+                    final YangInstanceIdentifier yangInstanceIdentifier = YangInstanceIdentifier
+                            .create(dataTreeCandidateNode.getIdentifier());
+                    validateNode(dataTreeCandidateNode, referencedByCtx,
+                            referencingCtx, yangInstanceIdentifier);
+                }
+            }
+
+        }
+
+        if (!errorsMessages.isEmpty()) {
+            final StringBuilder message = new StringBuilder();
+            int errCount = 0;
+            for (final String errorMessage : errorsMessages) {
+                message.append(errorMessage);
+                errCount++;
+            }
+            throw new LeafRefDataValidationFailedException(message.toString(),
+                    errCount);
+        }
+
+    }
+
+    private void validateNode(final DataTreeCandidateNode node,
+            final LeafRefContext referencedByCtx, final LeafRefContext referencingCtx,
+            final YangInstanceIdentifier current) {
+
+        if ((node.getModificationType() == ModificationType.WRITE)
+                && node.getDataAfter().isPresent()) {
+            final Optional<NormalizedNode<?, ?>> dataAfter = node.getDataAfter();
+            final NormalizedNode<?, ?> normalizedNode = dataAfter.get();
+            validateNodeData(normalizedNode, referencedByCtx, referencingCtx,
+                    node.getModificationType(), current);
+            return;
+        }
+
+        if (node.getModificationType() == ModificationType.DELETE
+                && referencedByCtx != null) {
+            final Optional<NormalizedNode<?, ?>> dataBefor = node.getDataBefore();
+            final NormalizedNode<?, ?> normalizedNode = dataBefor.get();
+            validateNodeData(normalizedNode, referencedByCtx, null,
+                    node.getModificationType(), current);
+            return;
+        }
+
+        final Collection<DataTreeCandidateNode> childNodes = node.getChildNodes();
+        for (final DataTreeCandidateNode childNode : childNodes) {
+            final ModificationType modificationType = childNode.getModificationType();
+
+            if (modificationType != ModificationType.UNMODIFIED) {
+
+                final LeafRefContext childReferencedByCtx = getReferencedByCtxChild(
+                        referencedByCtx, childNode);
+                final LeafRefContext childReferencingCtx = getReferencingCtxChild(
+                        referencingCtx, childNode);
+
+                if (childReferencedByCtx != null || childReferencingCtx != null) {
+                    final YangInstanceIdentifier childYangInstanceIdentifier = current
+                            .node(childNode.getIdentifier());
+                    validateNode(childNode, childReferencedByCtx,
+                            childReferencingCtx, childYangInstanceIdentifier);
+                }
+            }
+
+        }
+
+    }
+
+    private LeafRefContext getReferencingCtxChild(
+            final LeafRefContext referencingCtx, final DataTreeCandidateNode childNode) {
+
+        LeafRefContext childReferencingCtx = null;
+        if (referencingCtx != null) {
+            final PathArgument identifier = childNode.getIdentifier();
+            final QName childQName = identifier.getNodeType();
+
+            childReferencingCtx = referencingCtx
+                    .getReferencingChildByName(childQName);
+
+            if (childReferencingCtx == null) {
+                final NormalizedNode<?, ?> data = childNode.getDataAfter().get();
+                if (data instanceof MapEntryNode
+                        || data instanceof UnkeyedListEntryNode) {
+                    childReferencingCtx = referencingCtx;
+                }
+            }
+        }
+
+        return childReferencingCtx;
+    }
+
+    private LeafRefContext getReferencedByCtxChild(
+            final LeafRefContext referencedByCtx, final DataTreeCandidateNode childNode) {
+
+        LeafRefContext childReferencedByCtx = null;
+        if (referencedByCtx != null) {
+            final PathArgument identifier = childNode.getIdentifier();
+            final QName childQName = identifier.getNodeType();
+
+            childReferencedByCtx = referencedByCtx
+                    .getReferencedChildByName(childQName);
+            if (childReferencedByCtx == null) {
+                final NormalizedNode<?, ?> data = childNode.getDataAfter().get();
+                if (data instanceof MapEntryNode
+                        || data instanceof UnkeyedListEntryNode) {
+                    childReferencedByCtx = referencedByCtx;
+                }
+            }
+        }
+
+        return childReferencedByCtx;
+    }
+
+    private void validateNodeData(final NormalizedNode<?, ?> node,
+            final LeafRefContext referencedByCtx, final LeafRefContext referencingCtx,
+            final ModificationType modificationType, final YangInstanceIdentifier current) {
+
+        if (node instanceof LeafNode) {
+            final LeafNode<?> leaf = (LeafNode<?>) node;
+
+            if (referencedByCtx != null && referencedByCtx.isReferenced()) {
+                validateLeafRefTargetNodeData(leaf, referencedByCtx,
+                        modificationType);
+            }
+            if (referencingCtx != null && referencingCtx.isReferencing()) {
+                validateLeafRefNodeData(leaf, referencingCtx, modificationType,
+                        current);
+            }
+
+            return;
+        }
+
+        if (node instanceof LeafSetNode) {
+            final LeafSetNode<?> leafSet = (LeafSetNode<?>) node;
+
+            if (referencedByCtx == null && referencingCtx == null) {
+                return;
+            }
+
+            final Iterable<? extends NormalizedNode<?, ?>> leafSetEntries = leafSet
+                    .getValue();
+            for (final NormalizedNode<?, ?> leafSetEntry : leafSetEntries) {
+                if (referencedByCtx != null && referencedByCtx.isReferenced()) {
+                    validateLeafRefTargetNodeData(leafSetEntry,
+                            referencedByCtx, modificationType);
+                }
+                if (referencingCtx != null && referencingCtx.isReferencing()) {
+                    validateLeafRefNodeData(leafSetEntry, referencingCtx,
+                            modificationType, current);
+                }
+            }
+
+            return;
+        }
+
+        if (node instanceof ChoiceNode) {
+            final ChoiceNode choice = (ChoiceNode) node;
+            final Iterable<DataContainerChild<? extends PathArgument, ?>> childs = choice
+                    .getValue();
+            for (final DataContainerChild<? extends PathArgument, ?> dataContainerChild : childs) {
+                final QName qname = dataContainerChild.getNodeType();
+
+                LeafRefContext childReferencedByCtx = null;
+                LeafRefContext childReferencingCtx = null;
+                if (referencedByCtx != null) {
+                    childReferencedByCtx = findReferencedByCtxUnderChoice(
+                            referencedByCtx, qname);
+                }
+                if (referencingCtx != null) {
+                    childReferencingCtx = findReferencingCtxUnderChoice(
+                            referencingCtx, qname);
+                }
+                if (childReferencedByCtx != null || childReferencingCtx != null) {
+                    final YangInstanceIdentifier childYangInstanceIdentifier = current
+                            .node(dataContainerChild.getIdentifier());
+                    validateNodeData(dataContainerChild, childReferencedByCtx,
+                            childReferencingCtx, modificationType,
+                            childYangInstanceIdentifier);
+                }
+            }
+        } else if (node instanceof DataContainerNode) {
+            final DataContainerNode<?> dataContainerNode = (DataContainerNode<?>) node;
+            final Iterable<DataContainerChild<? extends PathArgument, ?>> dataContainerChilds = dataContainerNode
+                    .getValue();
+
+            for (final DataContainerChild<? extends PathArgument, ?> dataContainerChild : dataContainerChilds) {
+                final QName qname = dataContainerChild.getNodeType();
+
+                LeafRefContext childReferencedByCtx = null;
+                LeafRefContext childReferencingCtx = null;
+                if (referencedByCtx != null) {
+                    childReferencedByCtx = referencedByCtx
+                            .getReferencedChildByName(qname);
+                }
+                if (referencingCtx != null) {
+                    childReferencingCtx = referencingCtx
+                            .getReferencingChildByName(qname);
+                }
+                if (childReferencedByCtx != null || childReferencingCtx != null) {
+                    final YangInstanceIdentifier childYangInstanceIdentifier = current
+                            .node(dataContainerChild.getIdentifier());
+                    validateNodeData(dataContainerChild, childReferencedByCtx,
+                            childReferencingCtx, modificationType,
+                            childYangInstanceIdentifier);
+                }
+            }
+        } else if (node instanceof MapNode) {
+            final MapNode map = (MapNode) node;
+            final Iterable<MapEntryNode> mapEntries = map.getValue();
+            for (final MapEntryNode mapEntry : mapEntries) {
+                final Iterable<DataContainerChild<? extends PathArgument, ?>> mapEntryNodes = mapEntry
+                        .getValue();
+                final YangInstanceIdentifier mapEntryYangInstanceIdentifier = current
+                        .node(mapEntry.getIdentifier());
+                for (final DataContainerChild<? extends PathArgument, ?> mapEntryNode : mapEntryNodes) {
+                    final QName qname = mapEntryNode.getNodeType();
+
+                    LeafRefContext childReferencedByCtx = null;
+                    LeafRefContext childReferencingCtx = null;
+                    if (referencedByCtx != null) {
+                        childReferencedByCtx = referencedByCtx
+                                .getReferencedChildByName(qname);
+                    }
+                    if (referencingCtx != null) {
+                        childReferencingCtx = referencingCtx
+                                .getReferencingChildByName(qname);
+                    }
+                    if (childReferencedByCtx != null
+                            || childReferencingCtx != null) {
+                        final YangInstanceIdentifier mapEntryNodeYangInstanceIdentifier = mapEntryYangInstanceIdentifier
+                                .node(mapEntryNode.getIdentifier());
+                        validateNodeData(mapEntryNode, childReferencedByCtx,
+                                childReferencingCtx, modificationType,
+                                mapEntryNodeYangInstanceIdentifier);
+                    }
+                }
+            }
+
+        }
+        // FIXME if(node instance of UnkeyedListNode ...
+    }
+
+    private LeafRefContext findReferencingCtxUnderChoice(
+            final LeafRefContext referencingCtx, final QName qname) {
+
+        final Map<QName, LeafRefContext> referencingChilds = referencingCtx
+                .getReferencingChilds();
+        final Set<Entry<QName, LeafRefContext>> childs = referencingChilds.entrySet();
+        for (final Entry<QName, LeafRefContext> child : childs) {
+            final LeafRefContext referencingChildByName = child.getValue()
+                    .getReferencingChildByName(qname);
+            if (referencingChildByName != null) {
+                return referencingChildByName;
+            }
+        }
+
+        return null;
+    }
+
+    private LeafRefContext findReferencedByCtxUnderChoice(
+            final LeafRefContext referencedByCtx, final QName qname) {
+
+        final Map<QName, LeafRefContext> referencedByChilds = referencedByCtx
+                .getReferencedByChilds();
+        final Set<Entry<QName, LeafRefContext>> childs = referencedByChilds
+                .entrySet();
+        for (final Entry<QName, LeafRefContext> child : childs) {
+            final LeafRefContext referencedByChildByName = child.getValue()
+                    .getReferencedChildByName(qname);
+            if (referencedByChildByName != null) {
+                return referencedByChildByName;
+            }
+        }
+
+        return null;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private void validateLeafRefTargetNodeData(final NormalizedNode<?, ?> leaf,
+            final LeafRefContext referencedByCtx, final ModificationType modificationType) {
+
+        final StringBuilder header_log = new StringBuilder();
+        final StringBuilder log = new StringBuilder();
+        header_log.append("Operation [" + modificationType
+                + "] validate data of leafref TARGET node: name["
+                + referencedByCtx.getNodeName() + "] = value["
+                + leaf.getValue() + "]");
+
+        if (validatedLeafRefCtx.contains(referencedByCtx)) {
+            header_log.append(" -> SKIP: Already validated");
+            LOG.debug(header_log.toString());
+            return;
+        }
+
+        final Map<QName, LeafRefContext> allReferencedByLeafRefCtxs = referencedByCtx
+                .getAllReferencedByLeafRefCtxs();
+
+        final HashMap<LeafRefContext, HashSet> leafRefsValues = new HashMap<LeafRefContext, HashSet>();
+        final Collection<LeafRefContext> leafrefs = allReferencedByLeafRefCtxs
+                .values();
+        for (final LeafRefContext leafRefContext : leafrefs) {
+            if (leafRefContext.isReferencing()) {
+                final HashSet<Object> values = new HashSet<>();
+
+                final SchemaPath leafRefNodeSchemaPath = leafRefContext
+                        .getCurrentNodePath();
+                final LeafRefPath leafRefNodePath = LeafRefUtils
+                        .schemaPathToLeafRefPath(leafRefNodeSchemaPath,
+                                leafRefContext.getLeafRefContextModule());
+                final Iterable<QNameWithPredicate> pathFromRoot = leafRefNodePath
+                        .getPathFromRoot();
+                addValues(values, tree.getRootNode().getDataAfter(),
+                        pathFromRoot, null, QNameWithPredicate.ROOT);
+                leafRefsValues.put(leafRefContext, values);
+            }
+        }
+
+        final HashSet<Object> leafRefTargetNodeValues = new HashSet<>();
+        final SchemaPath nodeSchemaPath = referencedByCtx.getCurrentNodePath();
+        final LeafRefPath nodePath = LeafRefUtils.schemaPathToLeafRefPath(
+                nodeSchemaPath, referencedByCtx.getLeafRefContextModule());
+        addValues(leafRefTargetNodeValues, tree.getRootNode().getDataAfter(),
+                nodePath.getPathFromRoot(), null, QNameWithPredicate.ROOT);
+
+        boolean valid = true;
+        final Set<Entry<LeafRefContext, HashSet>> entrySet = leafRefsValues
+                .entrySet();
+        for (final Entry<LeafRefContext, HashSet> entry : entrySet) {
+            final LeafRefContext leafRefContext = entry.getKey();
+            final HashSet leafRefValuesSet = entry.getValue();
+            for (final Object leafRefsValue : leafRefValuesSet) {
+                if (!leafRefTargetNodeValues.contains(leafRefsValue)) {
+
+                    final StringBuilder sb = createInvalidTargetMessage(leaf,
+                            leafRefTargetNodeValues, leafRefContext,
+                            leafRefsValue);
+                    log.append(NEW_LINE);
+                    log.append(sb.toString());
+                    log.append(" -> FAILED");
+
+                    sb.append(NEW_LINE);
+                    errorsMessages.add(sb.toString());
+
+                    valid = false;
+                } else {
+                    log.append(NEW_LINE);
+                    log.append("Valid leafref value [");
+                    log.append(leafRefsValue);
+                    log.append("]");
+                    log.append(" -> OK");
+                }
+            }
+        }
+
+        header_log.append(valid ? " -> OK" : " -> FAILED");
+        LOG.debug(header_log.append(log.toString()).toString());
+
+        validatedLeafRefCtx.add(referencedByCtx);
+    }
+
+    private StringBuilder createInvalidTargetMessage(final NormalizedNode<?, ?> leaf,
+            final HashSet<?> leafRefTargetNodeValues, final LeafRefContext leafRefContext,
+            final Object leafRefsValue) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("Invalid leafref value [");
+        sb.append(leafRefsValue);
+        sb.append("]");
+        sb.append(" allowed values ");
+        sb.append(leafRefTargetNodeValues);
+        sb.append(" by validation of leafref TARGET node: ");
+        sb.append(leaf.getNodeType());
+        sb.append(" path of invalid LEAFREF node: ");
+        sb.append(leafRefContext.getCurrentNodePath());
+        sb.append(" leafRef target path: ");
+        sb.append(leafRefContext.getAbsoluteLeafRefTargetPath());
+        return sb;
+    }
+
+    private void validateLeafRefNodeData(final NormalizedNode<?, ?> leaf,
+            final LeafRefContext referencingCtx, final ModificationType modificationType,
+            final YangInstanceIdentifier current) {
+
+        final StringBuilder header_log = new StringBuilder();
+        final StringBuilder log = new StringBuilder();
+
+        header_log.append("Operation [" + modificationType
+                + "] validate data of LEAFREF node: name["
+                + referencingCtx.getNodeName() + "] = value["
+                + leaf.getValue() + "]");
+
+        final HashSet<Object> values = new HashSet<>();
+        final LeafRefPath targetPath = referencingCtx.getAbsoluteLeafRefTargetPath();
+        final Iterable<QNameWithPredicate> pathFromRoot = targetPath
+                .getPathFromRoot();
+
+        addValues(values, tree.getRootNode().getDataAfter(), pathFromRoot,
+                current, QNameWithPredicate.ROOT);
+
+        if (!values.contains(leaf.getValue())) {
+            final StringBuilder sb = createInvalidLeafRefMessage(leaf,
+                    referencingCtx, values);
+            errorsMessages.add(sb.toString());
+
+            header_log.append(" -> FAILED");
+            log.append(sb.toString());
+        } else {
+            header_log.append(" -> OK");
+        }
+
+        LOG.debug(header_log.toString());
+        if (!log.toString().equals(""))
+            LOG.debug(log.toString());
+    }
+
+    private StringBuilder createInvalidLeafRefMessage(
+            final NormalizedNode<?, ?> leaf, final LeafRefContext referencingCtx,
+            final Set<?> values) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("Invalid leafref value [");
+        sb.append(leaf.getValue());
+        sb.append("]");
+        sb.append(" allowed values ");
+        sb.append(values);
+        sb.append(" of LEAFREF node: ");
+        sb.append(leaf.getNodeType());
+        sb.append(" leafRef target path: ");
+        sb.append(referencingCtx.getAbsoluteLeafRefTargetPath());
+        sb.append(NEW_LINE);
+        return sb;
+    }
+
+    private void addValues(final Set<Object> values,
+            final Optional<? extends NormalizedNode<?, ?>> optDataNode,
+            final Iterable<QNameWithPredicate> path, final YangInstanceIdentifier current,
+            final QNameWithPredicate previousQName) {
+
+        if (!optDataNode.isPresent()) {
+            return;
+        }
+        final NormalizedNode<?, ?> node = optDataNode.get();
+
+        if (node instanceof LeafNode || node instanceof LeafSetEntryNode) {
+            values.add(node.getValue());
+            return;
+        } else if (node instanceof LeafSetNode<?>) {
+            final LeafSetNode<?> leafSetNode = (LeafSetNode<?>) node;
+            final Iterable<? extends NormalizedNode<?, ?>> entries = leafSetNode
+                    .getValue();
+            for (final NormalizedNode<?, ?> entry : entries) {
+                values.add(entry.getValue());
+            }
+            return;
+        }
+
+        final Iterator<QNameWithPredicate> iterator = path.iterator();
+        if (!iterator.hasNext()) {
+            return;
+        }
+        final QNameWithPredicate qnameWithPredicate = iterator.next();
+        final QName qName = qnameWithPredicate.getQName();
+        final PathArgument pathArgument = toPathArgument(qName);
+
+        if (node instanceof DataContainerNode) {
+            final DataContainerNode<?> dataContainerNode = (DataContainerNode<?>) node;
+            final Optional<DataContainerChild<? extends PathArgument, ?>> child = dataContainerNode
+                    .getChild(pathArgument);
+
+            if (child.isPresent()) {
+                addValues(values, child, nextLevel(path), current,
+                        qnameWithPredicate);
+            } else {
+                final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(dataContainerNode);
+                for (final ChoiceNode choiceNode : choiceNodes) {
+                    addValues(values, Optional.of(choiceNode), path, current,
+                            qnameWithPredicate);
+                }
+            }
+
+        } else if (node instanceof MapNode) {
+            final MapNode map = (MapNode) node;
+            final List<QNamePredicate> qNamePredicates = previousQName
+                    .getQNamePredicates();
+            if (qNamePredicates.isEmpty() || current == null) {
+                final Iterable<MapEntryNode> value = map.getValue();
+                for (final MapEntryNode mapEntryNode : value) {
+                    final Optional<DataContainerChild<? extends PathArgument, ?>> child = mapEntryNode
+                            .getChild(pathArgument);
+
+                    if (child.isPresent()) {
+                        addValues(values, child, nextLevel(path), current,
+                                qnameWithPredicate);
+                    } else {
+                        final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(mapEntryNode);
+                        for (final ChoiceNode choiceNode : choiceNodes) {
+                            addValues(values, Optional.of(choiceNode), path,
+                                    current, qnameWithPredicate);
+                        }
+                    }
+                }
+            } else {
+                final Map<QName, Set<?>> keyValues = new HashMap<QName, Set<?>>();
+
+                final Iterator<QNamePredicate> predicates = qNamePredicates
+                        .iterator();
+                while (predicates.hasNext()) {
+                    final QNamePredicate predicate = predicates.next();
+                    final QName identifier = predicate.getIdentifier();
+                    final LeafRefPath predicatePathKeyExpression = predicate
+                            .getPathKeyExpression();
+
+                    final Set<?> pathKeyExprValues = getPathKeyExpressionValues(
+                            predicatePathKeyExpression, current);
+
+                    keyValues.put(identifier, pathKeyExprValues);
+                }
+
+                final Iterable<MapEntryNode> mapEntryNodes = map.getValue();
+                for (final MapEntryNode mapEntryNode : mapEntryNodes) {
+                    if (isMatchingPredicate(mapEntryNode, keyValues)) {
+                        final Optional<DataContainerChild<? extends PathArgument, ?>> child = mapEntryNode
+                                .getChild(pathArgument);
+
+                        if (child.isPresent()) {
+                            addValues(values, child, nextLevel(path), current,
+                                    qnameWithPredicate);
+                        } else {
+                            final Iterable<ChoiceNode> choiceNodes = getChoiceNodes(mapEntryNode);
+                            for (final ChoiceNode choiceNode : choiceNodes) {
+                                addValues(values, Optional.of(choiceNode),
+                                        path, current, qnameWithPredicate);
+                            }
+                        }
+                    }
+                }
+
+            }
+        }
+    }
+
+    private Iterable<ChoiceNode> getChoiceNodes(
+            final DataContainerNode<?> dataContainerNode) {
+
+        final LinkedList<ChoiceNode> choiceNodes = new LinkedList<ChoiceNode>();
+
+        final Iterable<DataContainerChild<? extends PathArgument, ?>> childs = dataContainerNode
+                .getValue();
+        for (final DataContainerChild<? extends PathArgument, ?> child : childs) {
+            if (child instanceof ChoiceNode) {
+                choiceNodes.add((ChoiceNode) child);
+            }
+        }
+        return choiceNodes;
+    }
+
+    private boolean isMatchingPredicate(final MapEntryNode mapEntryNode,
+            final Map<QName, Set<?>> allowedKeyValues) {
+
+        final NodeIdentifierWithPredicates identifier = mapEntryNode.getIdentifier();
+        final Map<QName, Object> entryKeyValues = identifier.getKeyValues();
+
+        final Set<Entry<QName, Object>> entryKeyValueSet = entryKeyValues.entrySet();
+        for (final Entry<QName, Object> entryKeyValue : entryKeyValueSet) {
+            final QName key = entryKeyValue.getKey();
+            final Object value = entryKeyValue.getValue();
+
+            final Set<?> allowedValues = allowedKeyValues.get(key);
+            if (allowedValues != null && !allowedValues.contains(value)) {
+                return false;
+            }
+
+        }
+
+        return true;
+    }
+
+    private Set<?> getPathKeyExpressionValues(
+            final LeafRefPath predicatePathKeyExpression,
+            final YangInstanceIdentifier current) {
+
+        final Optional<NormalizedNode<?, ?>> parent = findParentNode(tree
+                .getRootNode().getDataAfter(), current);
+
+        final Iterable<QNameWithPredicate> predicatePathExpr = predicatePathKeyExpression
+                .getPathFromRoot();
+        final Iterable<QNameWithPredicate> predicatePath = nextLevel(predicatePathExpr);
+
+        final Set<Object> values = new HashSet<>();
+        if (parent != null) {
+            addValues(values, parent, predicatePath, null,
+                    QNameWithPredicate.ROOT);
+        }
+
+        return values;
+    }
+
+    private Optional<NormalizedNode<?, ?>> findParentNode(
+            final Optional<NormalizedNode<?, ?>> root, final YangInstanceIdentifier path) {
+        Optional<NormalizedNode<?, ?>> currentNode = root;
+        final Iterator<PathArgument> pathIterator = path.getPathArguments()
+                .iterator();
+        while (pathIterator.hasNext()) {
+            final PathArgument childPathArgument = pathIterator.next();
+            if (pathIterator.hasNext() && currentNode.isPresent()) {
+                currentNode = NormalizedNodes.getDirectChild(currentNode.get(),
+                        childPathArgument);
+            } else {
+                return currentNode;
+            }
+        }
+        return Optional.absent();
+    }
+
+    private Iterable<QNameWithPredicate> nextLevel(
+            final Iterable<QNameWithPredicate> path) {
+        return Iterables.skip(path, 1);
+    }
+
+    private PathArgument toPathArgument(final QName qName) {
+        return YangInstanceIdentifier.of(qName).getLastPathArgument();
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefYangSyntaxErrorException.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/LeafRefYangSyntaxErrorException.java
new file mode 100644 (file)
index 0000000..f1a4698
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Preconditions;
+
+public class LeafRefYangSyntaxErrorException extends Exception {
+    private static final long serialVersionUID = 1L;
+    private final String module;
+    private final int line;
+    private final int charPositionInLine;
+
+    public LeafRefYangSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+            final String message) {
+        this(module, line, charPositionInLine, message, null);
+    }
+
+    public LeafRefYangSyntaxErrorException(final String module, final int line, final int charPositionInLine,
+            final String message, final Throwable cause) {
+        super(Preconditions.checkNotNull(message), cause);
+        this.module = module;
+        this.line = line;
+        this.charPositionInLine = charPositionInLine;
+    }
+
+    public String getModule() {
+        return module;
+    }
+
+    public int getLine() {
+        return line;
+    }
+
+    public int getCharPositionInLine() {
+        return charPositionInLine;
+    }
+
+    public String getFormattedMessage() {
+        final StringBuilder sb = new StringBuilder(getMessage());
+        if (module != null) {
+            sb.append(" in module ");
+            sb.append(module);
+        }
+        if (line != 0) {
+            sb.append(" on line ");
+            sb.append(line);
+            if (charPositionInLine != 0) {
+                sb.append(" character ");
+                sb.append(charPositionInLine);
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        return this.getClass().getName() + ": " + getFormattedMessage();
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicate.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicate.java
new file mode 100644 (file)
index 0000000..e4f5de6
--- /dev/null
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+public interface QNamePredicate {
+
+    public QName getIdentifier();
+
+    public LeafRefPath getPathKeyExpression();
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateBuilder.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateBuilder.java
new file mode 100644 (file)
index 0000000..0cdb9dd
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import org.opendaylight.yangtools.yang.common.QName;
+
+class QNamePredicateBuilder {
+
+    private QName identifier;
+    private LeafRefPath pathKeyExpression;
+
+    public QNamePredicateBuilder() {
+    }
+
+    public QNamePredicateBuilder(final QName identifier, final LeafRefPath pathKeyExpression) {
+        this.identifier = identifier;
+        this.pathKeyExpression = pathKeyExpression;
+    }
+
+    public QName getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(final QName identifier) {
+        this.identifier = identifier;
+    }
+
+    public LeafRefPath getPathKeyExpression() {
+        return pathKeyExpression;
+    }
+
+    public void setPathKeyExpression(final LeafRefPath pathKeyExpression) {
+        this.pathKeyExpression = pathKeyExpression;
+    }
+
+    public QNamePredicate build() {
+        return new QNamePredicateImpl(identifier, pathKeyExpression);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+
+        sb.append(identifier);
+        sb.append("=current()");
+
+        final Iterable<QNameWithPredicate> pathFromRoot = pathKeyExpression
+                .getPathFromRoot();
+
+        for (final QNameWithPredicate qName : pathFromRoot) {
+            sb.append("/" + qName);
+        }
+
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateImpl.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNamePredicateImpl.java
new file mode 100644 (file)
index 0000000..6607475
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import com.google.common.base.Preconditions;
+import java.io.Serializable;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+class QNamePredicateImpl implements Immutable, Serializable,
+        QNamePredicate {
+
+    private static final long serialVersionUID = 1L;
+    private final QName identifier;
+    private final LeafRefPath pathKeyExpression;
+
+    public QNamePredicateImpl(final QName identifier, final LeafRefPath pathKeyExpression) {
+        this.identifier = Preconditions.checkNotNull(identifier, "QNamePredicate: identifier should not be null");
+        this.pathKeyExpression = Preconditions.checkNotNull(pathKeyExpression, "QNamePredicate: pathKeyExpression should not be null");
+    }
+
+    @Override
+    public QName getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public LeafRefPath getPathKeyExpression() {
+        return pathKeyExpression;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+
+        sb.append(identifier);
+        sb.append("=current()");
+
+        final Iterable<QNameWithPredicate> pathFromRoot = pathKeyExpression
+                .getPathFromRoot();
+
+        for (final QNameWithPredicate qName : pathFromRoot) {
+            sb.append("/" + qName);
+        }
+
+        sb.append("]");
+        return sb.toString();
+    }
+
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicate.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicate.java
new file mode 100644 (file)
index 0000000..c3adece
--- /dev/null
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+public interface QNameWithPredicate {
+
+    static final QNameWithPredicate UP_PARENT = new QNameWithPredicateBuilder(
+            null, "..").build();
+
+    static final QNameWithPredicate ROOT = new QNameWithPredicateBuilder(
+            null, "").build();
+
+    public List<QNamePredicate> getQNamePredicates();
+
+    public QNameModule getModuleQname();
+
+    public String getLocalName();
+
+    public QName getQName();
+
+}
\ No newline at end of file
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateBuilder.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateBuilder.java
new file mode 100644 (file)
index 0000000..daa8dbd
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.util.LinkedList;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+class QNameWithPredicateBuilder {
+
+    private LinkedList<QNamePredicate> qnamePredicates;
+    private QNameModule moduleQname;
+    private String localName;
+
+    public static QNameWithPredicateBuilder UP_PARENT_BUILDER = new QNameWithPredicateBuilder(
+            null, "..") {
+        @Override
+        public QNameWithPredicate build() {
+            return QNameWithPredicate.UP_PARENT;
+        }
+    };
+
+    public QNameWithPredicateBuilder(final QNameModule moduleQname, final String localName) {
+        this.moduleQname = moduleQname;
+        this.localName = localName;
+        this.qnamePredicates = new LinkedList<QNamePredicate>();
+    }
+
+    public QNameWithPredicate build() {
+        final QNameWithPredicateImpl qNameWithPredicateImpl = new QNameWithPredicateImpl(
+                moduleQname, localName, qnamePredicates);
+
+        this.qnamePredicates = new LinkedList<QNamePredicate>();
+
+        return qNameWithPredicateImpl;
+    }
+
+    public LinkedList<QNamePredicate> getQNamePredicates() {
+        return qnamePredicates;
+    }
+
+    public void addQNamePredicate(final QNamePredicate qnamePredicate) {
+        qnamePredicates.add(qnamePredicate);
+    }
+
+    public QNameModule getModuleQname() {
+        return moduleQname;
+    }
+
+    public void setModuleQname(final QNameModule moduleQname) {
+        this.moduleQname = moduleQname;
+    }
+
+    public String getLocalName() {
+        return localName;
+    }
+
+    public void setLocalName(final String localName) {
+        this.localName = localName;
+    }
+
+    // FIXME: check also predicates ...
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof QNameWithPredicateBuilder)) {
+            return false;
+        }
+        final QNameWithPredicateBuilder other = (QNameWithPredicateBuilder) obj;
+        if (localName == null) {
+            if (other.localName != null) {
+                return false;
+            }
+        } else if (!localName.equals(other.localName)) {
+            return false;
+        }
+        return moduleQname.equals(other.moduleQname);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+
+        if (moduleQname != null) {
+            sb.append("(" + moduleQname.getNamespace());
+            sb.append("?revision=" + moduleQname.getRevision());
+            sb.append(")");
+        }
+
+        sb.append(localName);
+
+        for (final QNamePredicate predicate : qnamePredicates) {
+            sb.append(predicate);
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateImpl.java b/yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/leafref/QNameWithPredicateImpl.java
new file mode 100644 (file)
index 0000000..1661d9b
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+final class QNameWithPredicateImpl implements Immutable, Serializable,
+        QNameWithPredicate {
+
+    private static final long serialVersionUID = 1L;
+
+    private final LinkedList<QNamePredicate> qnamePredicates;
+    private final QNameModule moduleQname;
+    private final String localName;
+
+    public QNameWithPredicateImpl(final QNameModule moduleQname, final String localName,
+            final LinkedList<QNamePredicate> qnamePredicates) {
+        this.moduleQname = moduleQname;
+        this.localName = localName;
+        this.qnamePredicates = qnamePredicates;
+    }
+
+    @Override
+    public LinkedList<QNamePredicate> getQNamePredicates() {
+        return qnamePredicates;
+    }
+
+    @Override
+    public QNameModule getModuleQname() {
+        return moduleQname;
+    }
+
+    @Override
+    public String getLocalName() {
+        return localName;
+    }
+
+    @Override
+    public QName getQName() {
+        return QName.create(moduleQname, localName);
+    }
+
+    // FIXME: check also predicates ...
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof QNameWithPredicateImpl)) {
+            return false;
+        }
+        final QNameWithPredicateImpl other = (QNameWithPredicateImpl) obj;
+        if (localName == null) {
+            if (other.localName != null) {
+                return false;
+            }
+        } else if (!localName.equals(other.localName)) {
+            return false;
+        }
+        return moduleQname.equals(other.moduleQname);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+
+        if (moduleQname != null) {
+            sb.append("(" + moduleQname.getNamespace());
+            sb.append("?revision=" + moduleQname.getRevision());
+            sb.append(")");
+        }
+
+        sb.append(localName);
+
+        for (final QNamePredicate predicate : qnamePredicates) {
+            sb.append(predicate);
+        }
+
+        return sb.toString();
+    }
+
+}
index b2b132d1369485d14f6585afdeaf7d2f1d46a96b..9b1ef2d2ef50148aacbf47488c95ae4f718fe0d0 100644 (file)
@@ -51,7 +51,7 @@ abstract class AbstractDataTreeTip implements DataTreeTip {
 
         final Optional<TreeNode> newRoot = m.getStrategy().apply(m.getRootModification(),
             Optional.<TreeNode>of(currentRoot), m.getVersion());
-        Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node");
+        Preconditions.checkState(newRoot.isPresent(), "Apply strategy failed to produce root node for modification %s", modification);
         return new InMemoryDataTreeCandidate(PUBLIC_ROOT_PATH, root, currentRoot, newRoot.get());
     }
 }
index ada5798e98dbdd255dee0d2e047079eb0324ea08..b771bccadf616380fe98279648c54161d9a93bcb 100644 (file)
@@ -173,7 +173,7 @@ abstract class SchemaAwareApplyOperation extends ModificationApplyOperation {
         }
     }
 
-    private void checkDeleteApplicable(final NodeModification modification, final Optional<TreeNode> current) {
+    private static void checkDeleteApplicable(final NodeModification modification, final Optional<TreeNode> current) {
         // Delete is always applicable, we do not expose it to subclasses
         if (current.isPresent()) {
             LOG.trace("Delete operation turned to no-op on missing node {}", modification);
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest.java
new file mode 100644 (file)
index 0000000..2c2d563
--- /dev/null
@@ -0,0 +1,810 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest {
+
+    private static SchemaContext context;
+    private static Module valModule;
+    private static QNameModule valModuleQname;
+    private static LeafRefContext rootLeafRefContext;
+    public static TipProducingDataTree inMemoryDataTree;
+
+    private static QName odl;
+    private static QName project;
+    private static QName name;
+    private static QName desc;
+    private static QName lead;
+    private static QName owner;
+    private static QName odlContributor;
+    private static QName contributor;
+    private static QName odlProjectName;
+    private static QName odlProjectDesc;
+    private static QName login;
+    private static QName contributorName;
+    private static QName l1;
+    private static QName l2;
+    private static QName con1;
+    private static QName ch1;
+    private static QName ch2;
+    private static QName leafrefInChoice;
+    private static QName listInChoice;
+
+    private static QName leafrefInChoiceToChoice;
+    private static QName con3;
+    private static QName list3InChoice;
+    private static QName l3;
+    private static QName choiceInCon3;
+
+    private static QName listInChoiceKey;
+    private static QName k;
+
+    private static QName leafrefLeafList;
+
+    private static final Logger LOG = LoggerFactory.getLogger("");
+    private static final String NEW_LINE = System.getProperty("line.separator");
+
+    static {
+        BasicConfigurator.configure();
+    }
+
+    @BeforeClass
+    public static void init() throws URISyntaxException, IOException,
+            YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+        initSchemaContext();
+
+        initLeafRefContext();
+
+        initQnames();
+
+        initDataTree();
+
+    }
+
+    private static void initSchemaContext() throws URISyntaxException,
+            IOException, YangSyntaxErrorException {
+        final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+                .getResource("/leafref-validation/leafref-validation.yang")
+                .toURI());
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        context = parser.parseFile(resourceFile, resourceDir);
+
+        final Set<Module> modules = context.getModules();
+        for (final Module module : modules) {
+            if (module.getName().equals("leafref-validation")) {
+                valModule = module;
+            }
+        }
+
+        valModuleQname = valModule.getQNameModule();
+    }
+
+    private static void initLeafRefContext() throws IOException,
+            LeafRefYangSyntaxErrorException {
+        rootLeafRefContext = LeafRefContext.create(context);
+    }
+
+    private static void initQnames() {
+        odl = QName.create(valModuleQname, "odl-project");
+        project = QName.create(valModuleQname, "project");
+        name = QName.create(valModuleQname, "name");
+        desc = QName.create(valModuleQname, "desc");
+        lead = QName.create(valModuleQname, "project-lead");
+        owner = QName.create(valModuleQname, "project-owner");
+
+        odlContributor = QName.create(valModuleQname, "odl-contributor");
+        contributor = QName.create(valModuleQname, "contributor");
+        odlProjectName = QName.create(valModuleQname, "odl-project-name");
+        login = QName.create(valModuleQname, "login");
+        contributorName = QName.create(valModuleQname, "contributor-name");
+
+        con1 = QName.create(valModuleQname, "con1");
+        l1 = QName.create(valModuleQname, "l1");
+        l2 = QName.create(valModuleQname, "l2");
+        odlProjectDesc = QName.create(valModuleQname, "odl-project-desc");
+
+        ch1 = QName.create(valModuleQname, "ch1");
+        ch2 = QName.create(valModuleQname, "ch2");
+        leafrefInChoice = QName.create(valModuleQname, "leafref-in-choice");
+        listInChoice = QName.create(valModuleQname, "list-in-choice");
+
+        leafrefInChoiceToChoice = QName.create(valModuleQname,
+                "leafref-in-choice-to-choice");
+        con3 = QName.create(valModuleQname, "con3");
+        list3InChoice = QName.create(valModuleQname, "list3-in-choice");
+        l3 = QName.create(valModuleQname, "l3");
+        choiceInCon3 = QName.create(valModuleQname, "choice-in-con3");
+
+        listInChoiceKey = QName.create(valModuleQname, "list-in-choice-key");
+        k = QName.create(valModuleQname, "k");
+
+        leafrefLeafList = QName.create(valModuleQname, "leafref-leaf-list");
+
+    }
+
+    private static void initDataTree() {
+        inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+        inMemoryDataTree.setSchemaContext(context);
+
+        final DataTreeModification initialDataTreeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+
+        final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+                .getDataChildByName(odl);
+
+        final ContainerNode odlProjectContainer = createOdlContainer(odlProjContSchemaNode);
+
+        final YangInstanceIdentifier path = YangInstanceIdentifier.of(odl);
+        initialDataTreeModification.write(path, odlProjectContainer);
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(initialDataTreeModification);
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+    }
+
+    @Test
+    public void dataTreeCanditateValidationTest() {
+        write();
+
+        write2();
+
+        delete();
+
+        writeContributors();
+
+        writeMapEntry();
+
+        writeIntoMapEntry();
+    }
+
+    private void writeContributors() {
+
+        final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+                .getDataChildByName(odlContributor);
+
+        final ContainerNode contributorContainer = createBasicContributorContainer(contributorContSchemaNode);
+
+        final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+                .of(odlContributor);
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(contributorPath, contributorContainer);
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before write of contributors: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(3, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After write of contributors: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        assertTrue(exception);
+
+    }
+
+    private void writeIntoMapEntry() {
+
+        final Map<QName, Object> keys = new HashMap<QName, Object>();
+        keys.put(name, "New Project");
+        final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+                project, keys);
+
+        final YangInstanceIdentifier leaderPath = YangInstanceIdentifier.of(odl)
+                .node(project).node(mapEntryPath).node(lead);
+
+        final LeafNode<String> leader = ImmutableNodes.leafNode(lead,
+                "Updated leader");
+
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(leaderPath, leader);
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before write into map entry (update of leader name): ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(1, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After write into map entry (update of leader name): ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        assertTrue(exception);
+
+    }
+
+    private void writeMapEntry() {
+
+        final Map<QName, Object> keys = new HashMap<QName, Object>();
+        keys.put(name, "New Project");
+        final NodeIdentifierWithPredicates mapEntryPath = new NodeIdentifierWithPredicates(
+                project, keys);
+
+        final YangInstanceIdentifier newOdlProjectMapEntryPath = YangInstanceIdentifier
+                .of(odl).node(project).node(mapEntryPath);
+
+        final ContainerSchemaNode odlProjContSchemaNode = (ContainerSchemaNode) valModule
+                .getDataChildByName(odl);
+        final ListSchemaNode projListSchemaNode = (ListSchemaNode) odlProjContSchemaNode
+                .getDataChildByName(project);
+        final MapEntryNode newProjectMapEntry = createProjectListEntry("New Project",
+                "New Project description ...", "Leader of New Project",
+                "Owner of New Project", projListSchemaNode);
+
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(newOdlProjectMapEntryPath, newProjectMapEntry);
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before map entry write: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(2, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After map entry write: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        assertTrue(exception);
+
+    }
+
+    private void write() {
+
+        final ContainerSchemaNode contributorContSchemaNode = (ContainerSchemaNode) valModule
+                .getDataChildByName(odlContributor);
+
+        final ContainerNode contributorContainer = createContributorContainer(contributorContSchemaNode);
+
+        final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+                .of(odlContributor);
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(contributorPath, contributorContainer);
+
+        writeModification.write(YangInstanceIdentifier.of(l1),
+                ImmutableNodes.leafNode(l1, "Leafref l1 under the root"));
+        writeModification
+                .write(YangInstanceIdentifier.of(l2), ImmutableNodes.leafNode(
+                        l2, "Leafref target l2 under the root"));
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before write: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(12, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After write: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        assertTrue(exception);
+    }
+
+    private void write2() {
+
+        final ContainerSchemaNode odlCon = (ContainerSchemaNode) valModule
+                .getDataChildByName(odl);
+        final ContainerSchemaNode con1Con = (ContainerSchemaNode) odlCon
+                .getDataChildByName(con1);
+        final LeafNode<String> l1Leaf = ImmutableNodes.leafNode(l1, "l1 value");
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+                .containerBuilder(con1Con);
+        containerBuilder.addChild(l1Leaf);
+        final ContainerNode con1Node = containerBuilder.build();
+
+        final YangInstanceIdentifier con1Path = YangInstanceIdentifier.of(odl).node(
+                con1);
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(con1Path, con1Node);
+
+        final ChoiceNode choiceNode = createChoiceNode();
+        final YangInstanceIdentifier choicePath = YangInstanceIdentifier.of(odl)
+                .node(ch1);
+        writeModification.write(choicePath, choiceNode);
+
+        final ContainerNode con3Node = createCon3Node();
+        final YangInstanceIdentifier con3Path = YangInstanceIdentifier.of(odl).node(
+                con3);
+        writeModification.write(con3Path, con3Node);
+
+        final LeafSetNode leafListNode = createLeafRefLeafListNode();
+        final YangInstanceIdentifier leafListPath = YangInstanceIdentifier.of(odl)
+                .node(leafrefLeafList);
+        writeModification.write(leafListPath, leafListNode);
+
+        final DataTreeCandidate writeContributorsCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before write2: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeContributorsCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(6, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        assertTrue(exception);
+
+        inMemoryDataTree.commit(writeContributorsCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After write2: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+    }
+
+    private LeafSetNode createLeafRefLeafListNode() {
+
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+                .leafSetBuilder();
+        leafSetBuilder.withNodeIdentifier(new NodeIdentifier(leafrefLeafList));
+
+        leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k1"));
+        leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k2"));
+        leafSetBuilder.addChild(createLeafSetEntry(leafrefLeafList, "k3"));
+
+        return leafSetBuilder.build();
+    }
+
+    private ContainerNode createCon3Node() {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder = Builders
+                .mapBuilder();
+        mapBuilder.withNodeIdentifier(new NodeIdentifier(list3InChoice));
+
+        mapBuilder.addChild(createList3Entry("k1", "val1", "valA", "valX"));
+        mapBuilder.addChild(createList3Entry("k2", "val2", "valB", "valY"));
+
+        final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+                .choiceBuilder();
+        choiceBuilder.withNodeIdentifier(new NodeIdentifier(choiceInCon3));
+
+        choiceBuilder.addChild(mapBuilder.build());
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
+                .containerBuilder();
+        containerBuilder.withNodeIdentifier(new NodeIdentifier(con3));
+
+        containerBuilder.addChild(choiceBuilder.build());
+
+        return containerBuilder.build();
+    }
+
+    private MapEntryNode createList3Entry(final String kVal, final String l3Val1,
+            final String l3Val2, final String l3Val3) {
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+                .mapEntryBuilder();
+        mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+                list3InChoice, k, kVal));
+
+        final ListNodeBuilder<Object, LeafSetEntryNode<Object>> leafSetBuilder = Builders
+                .leafSetBuilder();
+        leafSetBuilder.withNodeIdentifier(new NodeIdentifier(l3));
+
+        leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val1));
+        leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val2));
+        leafSetBuilder.addChild(createLeafSetEntry(l3, l3Val3));
+
+        mapEntryBuilder.addChild(ImmutableNodes.leafNode(k, kVal));
+        mapEntryBuilder.addChild(leafSetBuilder.build());
+
+        return mapEntryBuilder.build();
+    }
+
+    private LeafSetEntryNode<Object> createLeafSetEntry(final QName qname, final String val) {
+        final NormalizedNodeAttrBuilder<NodeWithValue, Object, LeafSetEntryNode<Object>> leafSetEntryBuilder = Builders
+                .leafSetEntryBuilder();
+        leafSetEntryBuilder.withNodeIdentifier(new NodeWithValue(qname, val));
+        leafSetEntryBuilder.withValue(val);
+        return leafSetEntryBuilder.build();
+    }
+
+    private ChoiceNode createChoiceNode() {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> listInChoiceBuilder = Builders
+                .mapBuilder();
+        listInChoiceBuilder
+                .withNodeIdentifier(new NodeIdentifier(listInChoice));
+
+        listInChoiceBuilder.addChild(createListInChoiceEntry("key1",
+                "leafref-in-choice value", "val1"));
+        listInChoiceBuilder.addChild(createListInChoiceEntry("key2",
+                "l1 value", "val2"));
+        listInChoiceBuilder.addChild(createListInChoiceEntry("key3",
+                "l1 value", "val3"));
+
+        final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choice2Builder = Builders
+                .choiceBuilder();
+        choice2Builder.withNodeIdentifier(new NodeIdentifier(ch2));
+
+        choice2Builder.addChild(listInChoiceBuilder.build());
+
+        final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> choiceBuilder = Builders
+                .choiceBuilder();
+        choiceBuilder.withNodeIdentifier(new NodeIdentifier(ch1));
+        choiceBuilder.addChild(choice2Builder.build());
+
+        return choiceBuilder.build();
+    }
+
+    private MapEntryNode createListInChoiceEntry(final String keyVal,
+            final String leafrefInChoiceVal, final String leafrefInChoiceToChoiceVal) {
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = Builders
+                .mapEntryBuilder();
+
+        mapEntryBuilder.withNodeIdentifier(new NodeIdentifierWithPredicates(
+                listInChoice, listInChoiceKey, keyVal));
+
+        mapEntryBuilder.addChild(ImmutableNodes.leafNode(listInChoiceKey,
+                keyVal));
+        mapEntryBuilder.addChild(ImmutableNodes.leafNode(leafrefInChoice,
+                leafrefInChoiceVal));
+        mapEntryBuilder.addChild(ImmutableNodes.leafNode(
+                leafrefInChoiceToChoice, leafrefInChoiceToChoiceVal));
+
+        return mapEntryBuilder.build();
+    }
+
+    private void delete() {
+
+        final YangInstanceIdentifier contributorPath = YangInstanceIdentifier
+                .of(odlContributor);
+        final DataTreeModification delete = inMemoryDataTree.takeSnapshot()
+                .newModification();
+        delete.delete(contributorPath);
+
+        final DataTreeCandidate deleteContributorsCanditate = inMemoryDataTree
+                .prepare(delete);
+
+        LOG.debug("*************************");
+        LOG.debug("Before delete: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(deleteContributorsCanditate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(6, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        assertTrue(exception);
+
+        inMemoryDataTree.commit(deleteContributorsCanditate);
+
+        LOG.debug("*************************");
+        LOG.debug("After delete: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+    }
+
+    private ContainerNode createContributorContainer(
+            final ContainerSchemaNode contributorContSchemaNode) {
+
+        final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+                .getDataChildByName(contributor);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+                .containerBuilder(contributorContSchemaNode);
+
+        final MapNode contributorMap = createContributorList(contributorListSchemaNode);
+        contributorContainerBldr.addChild(contributorMap);
+
+        final ContainerNode contributorContainer = contributorContainerBldr.build();
+
+        return contributorContainer;
+
+    }
+
+    private MapNode createContributorList(
+            final ListSchemaNode contributorListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+                .mapBuilder(contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+                "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+                "Yangtools description ...", contributorListSchemaNode);
+        final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+                "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+                "MD-SAL description ...", contributorListSchemaNode);
+        final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+                "Leader of Controller", "Controller Leader name", "Controller",
+                "Controller description ...", contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry4 = createContributorListEntry("jdoe",
+                "John Doe", "MD-SAL", "Yangtools description ...",
+                contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry5 = createContributorListEntry("foo",
+                "foo name", "Controller", "MD-SAL description ...",
+                contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry6 = createContributorListEntry("bar",
+                "bar name", "Yangtools", "Controller description ...",
+                contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry7 = createContributorListEntry("baz",
+                "baz name", "Unknown Project",
+                "Unknown Project description ...", contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry8 = createContributorListEntry("pk",
+                "pk name", "Unknown Project 2", "Controller description ...",
+                contributorListSchemaNode);
+
+        contributorMapBldr.addChild(contributorMapEntry1);
+        contributorMapBldr.addChild(contributorMapEntry2);
+        contributorMapBldr.addChild(contributorMapEntry3);
+        contributorMapBldr.addChild(contributorMapEntry4);
+        contributorMapBldr.addChild(contributorMapEntry5);
+        contributorMapBldr.addChild(contributorMapEntry6);
+        contributorMapBldr.addChild(contributorMapEntry7);
+        contributorMapBldr.addChild(contributorMapEntry8);
+
+        final MapNode contributorMap = contributorMapBldr.build();
+
+        return contributorMap;
+
+    }
+
+    private MapEntryNode createContributorListEntry(final String loginVal,
+            final String contributorNameVal, final String odlProjectNameVal,
+            final String odlProjectDescVal, final ListSchemaNode contributorListSchemaNode) {
+
+        final LeafNode<String> loginLeaf = ImmutableNodes.leafNode(login, loginVal);
+        final LeafNode<String> contributorNameLeaf = ImmutableNodes.leafNode(
+                contributorName, contributorNameVal);
+        final LeafNode<String> odlProjectNameLeafRef = ImmutableNodes.leafNode(
+                odlProjectName, odlProjectNameVal);
+        final LeafNode<String> odlProjectDescLeafRef = ImmutableNodes.leafNode(
+                odlProjectDesc, odlProjectDescVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> contributorMapEntryBldr = Builders
+                .mapEntryBuilder(contributorListSchemaNode);
+
+        contributorMapEntryBldr.addChild(loginLeaf);
+        contributorMapEntryBldr.addChild(contributorNameLeaf);
+        contributorMapEntryBldr.addChild(odlProjectNameLeafRef);
+        contributorMapEntryBldr.addChild(odlProjectDescLeafRef);
+
+        final MapEntryNode contributorMapEntry = contributorMapEntryBldr.build();
+
+        return contributorMapEntry;
+    }
+
+    private static ContainerNode createOdlContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode projListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(project);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> odlProjectContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode projectMap = createProjectList(projListSchemaNode);
+        odlProjectContainerBldr.addChild(projectMap);
+
+        final ContainerNode odlProjectContainer = odlProjectContainerBldr.build();
+
+        return odlProjectContainer;
+    }
+
+    private static MapNode createProjectList(final ListSchemaNode projListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> projectMapBldr = Builders
+                .mapBuilder(projListSchemaNode);
+
+        final MapEntryNode projMapEntry1 = createProjectListEntry("Yangtools",
+                "Yangtools description ...", "Leader of Yangtools",
+                "Owner of Yangtools", projListSchemaNode);
+        final MapEntryNode projMapEntry2 = createProjectListEntry("MD-SAL",
+                "MD-SAL description ...", "Leader of MD-SAL",
+                "Owner of MD-SAL", projListSchemaNode);
+        final MapEntryNode projMapEntry3 = createProjectListEntry("Controller",
+                "Controller description ...", "Leader of Controller",
+                "Owner of Controller", projListSchemaNode);
+
+        projectMapBldr.addChild(projMapEntry1);
+        projectMapBldr.addChild(projMapEntry2);
+        projectMapBldr.addChild(projMapEntry3);
+
+        final MapNode projectMap = projectMapBldr.build();
+
+        return projectMap;
+    }
+
+    private static MapEntryNode createProjectListEntry(final String nameVal,
+            final String descVal, final String leadVal, final String ownerVal,
+            final ListSchemaNode projListSchemaNode) {
+
+        final LeafNode<String> nameLeaf = ImmutableNodes.leafNode(name, nameVal);
+        final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+        final LeafNode<String> leadLeafRef = ImmutableNodes.leafNode(lead, leadVal);
+        final LeafNode<String> ownerLeafRef = ImmutableNodes
+                .leafNode(owner, ownerVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> projMapEntryBldr = Builders
+                .mapEntryBuilder(projListSchemaNode);
+
+        projMapEntryBldr.addChild(nameLeaf);
+        projMapEntryBldr.addChild(descLeaf);
+        projMapEntryBldr.addChild(leadLeafRef);
+        projMapEntryBldr.addChild(ownerLeafRef);
+        final MapEntryNode projMapEntry = projMapEntryBldr.build();
+
+        return projMapEntry;
+    }
+
+    private ContainerNode createBasicContributorContainer(
+            final ContainerSchemaNode contributorContSchemaNode) {
+
+        final ListSchemaNode contributorListSchemaNode = (ListSchemaNode) contributorContSchemaNode
+                .getDataChildByName(contributor);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contributorContainerBldr = Builders
+                .containerBuilder(contributorContSchemaNode);
+
+        final MapNode contributorMap = createBasicContributorList(contributorListSchemaNode);
+        contributorContainerBldr.addChild(contributorMap);
+
+        final ContainerNode contributorContainer = contributorContainerBldr.build();
+
+        return contributorContainer;
+
+    }
+
+    private MapNode createBasicContributorList(
+            final ListSchemaNode contributorListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> contributorMapBldr = Builders
+                .mapBuilder(contributorListSchemaNode);
+
+        final MapEntryNode contributorMapEntry1 = createContributorListEntry(
+                "Leader of Yangtools", "Yangtools Leader name", "Yangtools",
+                "Yangtools description ...", contributorListSchemaNode);
+        final MapEntryNode contributorMapEntry2 = createContributorListEntry(
+                "Leader of MD-SAL", "MD-SAL Leader name", "MD-SAL",
+                "MD-SAL description ...", contributorListSchemaNode);
+        final MapEntryNode contributorMapEntry3 = createContributorListEntry(
+                "Leader of Controller", "Controller Leader name", "Controller",
+                "Controller description ...", contributorListSchemaNode);
+
+        contributorMapBldr.addChild(contributorMapEntry1);
+        contributorMapBldr.addChild(contributorMapEntry2);
+        contributorMapBldr.addChild(contributorMapEntry3);
+
+        final MapNode contributorMap = contributorMapBldr.build();
+
+        return contributorMap;
+
+    }
+
+}
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest2.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest2.java
new file mode 100644 (file)
index 0000000..f73c1d2
--- /dev/null
@@ -0,0 +1,359 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest2 {
+
+    private static SchemaContext context;
+    private static Module mainModule;
+    private static QNameModule rootModuleQname;
+    private static LeafRefContext rootLeafRefContext;
+    public static TipProducingDataTree inMemoryDataTree;
+
+    private static QName chips;
+    private static QName chip;
+    private static QName devType;
+    private static QName chipDesc;
+
+    private static QName devices;
+    private static QName device;
+    private static QName typeChoice;
+    private static QName typeText;
+    private static QName devDesc;
+    private static QName sn;
+    private static QName defaultIp;
+
+    private static QName deviceTypeStr;
+    private static QName deviceType;
+    private static QName type;
+    private static QName desc;
+
+    private static final Logger LOG = LoggerFactory.getLogger("");
+    private static final String NEW_LINE = System.getProperty("line.separator");
+
+    static {
+        BasicConfigurator.configure();
+    }
+
+    @BeforeClass
+    public static void init() throws URISyntaxException, IOException,
+            YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+        initSchemaContext();
+        initLeafRefContext();
+        initQnames();
+        initDataTree();
+    }
+
+    @Test
+    public void dataTreeCanditateValidationTest2() {
+
+        writeDevices();
+    }
+
+    private static void writeDevices() {
+
+        final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(devices);
+
+        final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+        final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(devicesPath, devicesContainer);
+
+        final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before writeDevices: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+
+            assertEquals(4, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        assertTrue(exception);
+
+        inMemoryDataTree.commit(writeDevicesCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After write: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+    }
+
+    private static void initQnames() {
+
+        chips = QName.create(rootModuleQname, "chips");
+        chip = QName.create(rootModuleQname, "chip");
+        devType = QName.create(rootModuleQname, "dev_type");
+        chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+        devices = QName.create(rootModuleQname, "devices");
+        device = QName.create(rootModuleQname, "device");
+        typeText = QName.create(rootModuleQname, "type_text");
+        devDesc = QName.create(rootModuleQname, "dev_desc");
+        sn = QName.create(rootModuleQname, "sn");
+        defaultIp = QName.create(rootModuleQname, "default_ip");
+
+        deviceTypeStr = QName.create(rootModuleQname, "device_types");
+        deviceType = QName.create(rootModuleQname, "device_type");
+        type = QName.create(rootModuleQname, "type");
+        desc = QName.create(rootModuleQname, "desc");
+    }
+
+    private static void initSchemaContext() throws URISyntaxException,
+            IOException, YangSyntaxErrorException {
+
+        final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+                .getResource("/leafref-validation/leafref-validation2.yang")
+                .toURI());
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        context = parser.parseFile(resourceFile, resourceDir);
+
+        final Set<Module> modules = context.getModules();
+        for (final Module module : modules) {
+            if (module.getName().equals("leafref-validation2")) {
+                mainModule = module;
+            }
+        }
+
+        rootModuleQname = mainModule.getQNameModule();
+    }
+
+    private static void initDataTree() {
+
+        inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+        inMemoryDataTree.setSchemaContext(context);
+
+        final DataTreeModification initialDataTreeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+
+        final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(chips);
+        final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+        final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+        initialDataTreeModification.write(path1, chipsContainer);
+
+        final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(deviceTypeStr);
+        final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+        final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+        initialDataTreeModification.write(path2, deviceTypesContainer);
+
+        final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
+                .prepare(initialDataTreeModification);
+
+        inMemoryDataTree.commit(writeChipsCandidate);
+
+        System.out.println(inMemoryDataTree.toString());
+    }
+
+    private static void initLeafRefContext() throws IOException,
+            LeafRefYangSyntaxErrorException {
+        rootLeafRefContext = LeafRefContext.create(context);
+    }
+
+    private static ContainerNode createDevTypeStrContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(deviceType);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+        devTypeContainerBldr.addChild(devTypeMap);
+
+        return devTypeContainerBldr.build();
+    }
+
+    private static MapNode createDevTypeList(
+            final ListSchemaNode devTypeListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders
+                .mapBuilder(devTypeListSchemaNode);
+
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_1",
+                "typedesc1", devTypeListSchemaNode));
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_2",
+                "typedesc2", devTypeListSchemaNode));
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type_3",
+                "typedesc3", devTypeListSchemaNode));
+
+        return devTypeMapBldr.build();
+    }
+
+    private static MapEntryNode createDevTypeListEntry(final String typeVal,
+            final String descVal, final ListSchemaNode devTypeListSchemaNode) {
+
+        final LeafNode<String> typeLeaf = ImmutableNodes.leafNode(type, typeVal);
+        final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+                .mapEntryBuilder(devTypeListSchemaNode);
+
+        devTypeMapEntryBldr.addChild(typeLeaf);
+        devTypeMapEntryBldr.addChild(descLeaf);
+
+        return devTypeMapEntryBldr.build();
+    }
+
+    private static ContainerNode createChipsContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(chip);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+        chipsContainerBldr.addChild(chipsMap);
+
+        return chipsContainerBldr.build();
+    }
+
+    private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders
+                .mapBuilder(chipsListSchemaNode);
+
+        chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1",
+                chipsListSchemaNode));
+        chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2",
+                chipsListSchemaNode));
+
+        return chipsMapBldr.build();
+    }
+
+    private static MapEntryNode createChipsListEntry(final String devTypeVal,
+            final String chipDescVal, final ListSchemaNode chipsListSchemaNode) {
+
+        final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType,
+                devTypeVal);
+        final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc,
+                chipDescVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+                .mapEntryBuilder(chipsListSchemaNode);
+
+        chipsMapEntryBldr.addChild(devTypeLeaf);
+        chipsMapEntryBldr.addChild(chipDescLeaf);
+
+        return chipsMapEntryBldr.build();
+    }
+
+    private static ContainerNode createDevicesContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(device);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+        devicesContainerBldr.addChild(devicesMap);
+
+        return devicesContainerBldr.build();
+    }
+
+    private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+                .mapBuilder(deviceListSchemaNode);
+
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type_1",
+                "typedesc1", 123456, "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type_2",
+                "typedesc2", 123457, "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type_2",
+                "typedesc3", 123457, "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type_1",
+                "typedesc2", 123458, "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("unknown", "unknown",
+                123457, "192.168.0.1", deviceListSchemaNode));
+
+        return devicesMapBldr.build();
+    }
+
+    private static MapEntryNode createDeviceListEntry(final String typeTextVal,
+            final String descVal, final int snVal, final String defaultIpVal,
+            final ListSchemaNode devicesListSchemaNode) {
+
+        final LeafNode<String> typeTextLeaf = ImmutableNodes.leafNode(typeText,
+                typeTextVal);
+        final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+        final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+        final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp,
+                defaultIpVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+                .mapEntryBuilder(devicesListSchemaNode);
+
+        devicesMapEntryBldr.addChild(typeTextLeaf);
+        devicesMapEntryBldr.addChild(descLeaf);
+        devicesMapEntryBldr.addChild(snValLeaf);
+        devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+        return devicesMapEntryBldr.build();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest3.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/DataTreeCandidateValidatorTest3.java
new file mode 100644 (file)
index 0000000..e345354
--- /dev/null
@@ -0,0 +1,459 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Set;
+import org.apache.log4j.BasicConfigurator;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefDataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefValidatation;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DataTreeCandidateValidatorTest3 {
+
+    private static SchemaContext context;
+    private static Module mainModule;
+    private static QNameModule rootModuleQname;
+    private static LeafRefContext rootLeafRefContext;
+    public static TipProducingDataTree inMemoryDataTree;
+
+    private static QName chips;
+    private static QName chip;
+    private static QName devType;
+    private static QName chipDesc;
+
+    private static QName devices;
+    private static QName device;
+    private static QName typeText1;
+    private static QName typeText2;
+    private static QName typeText3;
+    private static QName devDesc;
+    private static QName sn;
+    private static QName defaultIp;
+
+    private static QName deviceTypeStr;
+    private static QName deviceType;
+    private static QName type1;
+    private static QName type2;
+    private static QName type3;
+    private static QName desc;
+
+    private static final Logger LOG = LoggerFactory.getLogger("");
+    private static final String NEW_LINE = System.getProperty("line.separator");
+
+    static {
+        BasicConfigurator.configure();
+    }
+
+    @BeforeClass
+    public static void init() throws URISyntaxException, IOException,
+            YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+        initSchemaContext();
+        initLeafRefContext();
+        initQnames();
+        initDataTree();
+    }
+
+    @Test
+    public void dataTreeCanditateValidationTest2() {
+
+        writeDevices();
+
+        mergeDevices();
+    }
+
+    private static void writeDevices() {
+
+        final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(devices);
+
+        final ContainerNode devicesContainer = createDevicesContainer(devicesContSchemaNode);
+
+        final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+        final DataTreeModification writeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        writeModification.write(devicesPath, devicesContainer);
+
+        final DataTreeCandidate writeDevicesCandidate = inMemoryDataTree
+                .prepare(writeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before writeDevices: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(writeDevicesCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            assertEquals(6, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        assertTrue(exception);
+
+        inMemoryDataTree.commit(writeDevicesCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After writeDevices: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+    }
+
+    private static void mergeDevices() {
+
+        final ContainerSchemaNode devicesContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(devices);
+
+        final ContainerNode devicesContainer = createDevices2Container(devicesContSchemaNode);
+
+        final YangInstanceIdentifier devicesPath = YangInstanceIdentifier.of(devices);
+        final DataTreeModification mergeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+        // mergeModification.write(devicesPath, devicesContainer);
+        mergeModification.merge(devicesPath, devicesContainer);
+
+        final DataTreeCandidate mergeDevicesCandidate = inMemoryDataTree
+                .prepare(mergeModification);
+
+        LOG.debug("*************************");
+        LOG.debug("Before mergeDevices: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        boolean exception = false;
+        try {
+            LeafRefValidatation.validate(mergeDevicesCandidate, rootLeafRefContext);
+        } catch (final LeafRefDataValidationFailedException e) {
+            LOG.debug("All validation errors:" + NEW_LINE + e.getMessage());
+            // :TODO verify errors count gz
+            assertEquals(6, e.getValidationsErrorsCount());
+            exception = true;
+        }
+
+        inMemoryDataTree.commit(mergeDevicesCandidate);
+
+        LOG.debug("*************************");
+        LOG.debug("After mergeDevices: ");
+        LOG.debug("*************************");
+        LOG.debug(inMemoryDataTree.toString());
+
+        assertTrue(exception);
+    }
+
+    private static void initQnames() {
+
+        chips = QName.create(rootModuleQname, "chips");
+        chip = QName.create(rootModuleQname, "chip");
+        devType = QName.create(rootModuleQname, "dev_type");
+        chipDesc = QName.create(rootModuleQname, "chip_desc");
+
+        devices = QName.create(rootModuleQname, "devices");
+        device = QName.create(rootModuleQname, "device");
+        typeText1 = QName.create(rootModuleQname, "type_text1");
+        typeText2 = QName.create(rootModuleQname, "type_text2");
+        typeText3 = QName.create(rootModuleQname, "type_text3");
+        devDesc = QName.create(rootModuleQname, "dev_desc");
+        sn = QName.create(rootModuleQname, "sn");
+        defaultIp = QName.create(rootModuleQname, "default_ip");
+
+        deviceTypeStr = QName.create(rootModuleQname, "device_types");
+        deviceType = QName.create(rootModuleQname, "device_type");
+        type1 = QName.create(rootModuleQname, "type1");
+        type2 = QName.create(rootModuleQname, "type2");
+        type3 = QName.create(rootModuleQname, "type3");
+        desc = QName.create(rootModuleQname, "desc");
+    }
+
+    private static void initSchemaContext() throws URISyntaxException,
+            IOException, YangSyntaxErrorException {
+
+        final File resourceFile = new File(DataTreeCandidateValidatorTest.class
+                .getResource("/leafref-validation/leafref-validation3.yang")
+                .toURI());
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        context = parser.parseFile(resourceFile, resourceDir);
+
+        final Set<Module> modules = context.getModules();
+        for (final Module module : modules) {
+            if (module.getName().equals("leafref-validation3")) {
+                mainModule = module;
+            }
+        }
+
+        rootModuleQname = mainModule.getQNameModule();
+    }
+
+    private static void initDataTree() {
+
+        inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create();
+        inMemoryDataTree.setSchemaContext(context);
+
+        final DataTreeModification initialDataTreeModification = inMemoryDataTree
+                .takeSnapshot().newModification();
+
+        final ContainerSchemaNode chipsListContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(chips);
+        final ContainerNode chipsContainer = createChipsContainer(chipsListContSchemaNode);
+        final YangInstanceIdentifier path1 = YangInstanceIdentifier.of(chips);
+        initialDataTreeModification.write(path1, chipsContainer);
+
+        final ContainerSchemaNode devTypesListContSchemaNode = (ContainerSchemaNode) mainModule
+                .getDataChildByName(deviceTypeStr);
+        final ContainerNode deviceTypesContainer = createDevTypeStrContainer(devTypesListContSchemaNode);
+        final YangInstanceIdentifier path2 = YangInstanceIdentifier.of(deviceTypeStr);
+        initialDataTreeModification.write(path2, deviceTypesContainer);
+
+        final DataTreeCandidate writeChipsCandidate = inMemoryDataTree
+                .prepare(initialDataTreeModification);
+
+        inMemoryDataTree.commit(writeChipsCandidate);
+
+        System.out.println(inMemoryDataTree.toString());
+    }
+
+    private static void initLeafRefContext() throws IOException,
+            LeafRefYangSyntaxErrorException {
+        rootLeafRefContext = LeafRefContext.create(context);
+    }
+
+    private static ContainerNode createDevTypeStrContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode devTypeListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(deviceType);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devTypeContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode devTypeMap = createDevTypeList(devTypeListSchemaNode);
+        devTypeContainerBldr.addChild(devTypeMap);
+
+        return devTypeContainerBldr.build();
+    }
+
+    private static MapNode createDevTypeList(
+            final ListSchemaNode devTypeListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> devTypeMapBldr = Builders
+                .mapBuilder(devTypeListSchemaNode);
+
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_1",
+                "dev_type2_1", "dev_type3_1", "typedesc1",
+                devTypeListSchemaNode));
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_2",
+                "dev_type2_2", "dev_type3_2", "typedesc2",
+                devTypeListSchemaNode));
+        devTypeMapBldr.addChild(createDevTypeListEntry("dev_type1_3",
+                "dev_type2_3", "dev_type3_3", "typedesc3",
+                devTypeListSchemaNode));
+
+        return devTypeMapBldr.build();
+    }
+
+    private static MapEntryNode createDevTypeListEntry(final String type1Val,
+            final String type2Val, final String type3Val, final String descVal,
+            final ListSchemaNode devTypeListSchemaNode) {
+
+        final LeafNode<String> type1Leaf = ImmutableNodes.leafNode(type1, type1Val);
+        final LeafNode<String> type2Leaf = ImmutableNodes.leafNode(type2, type2Val);
+        final LeafNode<String> type3Leaf = ImmutableNodes.leafNode(type3, type3Val);
+        final LeafNode<String> descLeaf = ImmutableNodes.leafNode(desc, descVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devTypeMapEntryBldr = Builders
+                .mapEntryBuilder(devTypeListSchemaNode);
+
+        devTypeMapEntryBldr.addChild(type1Leaf);
+        devTypeMapEntryBldr.addChild(type2Leaf);
+        devTypeMapEntryBldr.addChild(type3Leaf);
+        devTypeMapEntryBldr.addChild(descLeaf);
+
+        return devTypeMapEntryBldr.build();
+    }
+
+    private static ContainerNode createChipsContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode chipsListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(chip);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> chipsContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode chipsMap = createChipsList(chipsListSchemaNode);
+        chipsContainerBldr.addChild(chipsMap);
+
+        return chipsContainerBldr.build();
+    }
+
+    private static MapNode createChipsList(final ListSchemaNode chipsListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> chipsMapBldr = Builders
+                .mapBuilder(chipsListSchemaNode);
+
+        chipsMapBldr.addChild(createChipsListEntry("dev_type_1", "desc1",
+                chipsListSchemaNode));
+        chipsMapBldr.addChild(createChipsListEntry("dev_type_2", "desc2",
+                chipsListSchemaNode));
+
+        return chipsMapBldr.build();
+    }
+
+    private static MapEntryNode createChipsListEntry(final String devTypeVal,
+            final String chipDescVal, final ListSchemaNode chipsListSchemaNode) {
+
+        final LeafNode<String> devTypeLeaf = ImmutableNodes.leafNode(devType,
+                devTypeVal);
+        final LeafNode<String> chipDescLeaf = ImmutableNodes.leafNode(chipDesc,
+                chipDescVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> chipsMapEntryBldr = Builders
+                .mapEntryBuilder(chipsListSchemaNode);
+
+        chipsMapEntryBldr.addChild(devTypeLeaf);
+        chipsMapEntryBldr.addChild(chipDescLeaf);
+
+        return chipsMapEntryBldr.build();
+    }
+
+    private static ContainerNode createDevicesContainer(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(device);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode devicesMap = createDeviceList(devicesListSchemaNode);
+        devicesContainerBldr.addChild(devicesMap);
+
+        return devicesContainerBldr.build();
+    }
+
+    private static MapNode createDeviceList(final ListSchemaNode deviceListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+                .mapBuilder(deviceListSchemaNode);
+
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1",
+                "dev_type2_1", "dev_type3_1", "typedesc1", 123456,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_2",
+                "dev_type2_2", "dev_type3_2", "typedesc1", 123457,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_1",
+                "dev_type2_2", "dev_type3_3", "typedesc2", 123458,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("unk11", "unk22",
+                "unk33", "unk_desc2", 123457, "192.168.0.1",
+                deviceListSchemaNode));
+
+        return devicesMapBldr.build();
+    }
+
+    private static ContainerNode createDevices2Container(
+            final ContainerSchemaNode container) {
+
+        final ListSchemaNode devicesListSchemaNode = (ListSchemaNode) container
+                .getDataChildByName(device);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> devicesContainerBldr = Builders
+                .containerBuilder(container);
+
+        final MapNode devicesMap = createDevice2List(devicesListSchemaNode);
+        devicesContainerBldr.addChild(devicesMap);
+
+        return devicesContainerBldr.build();
+    }
+
+    private static MapNode createDevice2List(final ListSchemaNode deviceListSchemaNode) {
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> devicesMapBldr = Builders
+                .mapBuilder(deviceListSchemaNode);
+
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+                "dev_type2_3", "dev_type3_3", "typedesc3", 123459,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+                "dev_type2_3", "dev_type3_3", "typedesc2", 123460,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("dev_type1_3",
+                "dev_type2_2", "dev_type3_1", "typedesc1", 123461,
+                "192.168.0.1", deviceListSchemaNode));
+        devicesMapBldr.addChild(createDeviceListEntry("unk1", "unk2", "unk3",
+                "unk_desc", 123462, "192.168.0.1", deviceListSchemaNode));
+
+        return devicesMapBldr.build();
+    }
+
+    private static MapEntryNode createDeviceListEntry(final String type1TextVal,
+            final String type2TextVal, final String type3TextVal, final String descVal,
+            final int snVal, final String defaultIpVal, final ListSchemaNode devicesListSchemaNode) {
+
+        final LeafNode<String> typeText1Leaf = ImmutableNodes.leafNode(typeText1,
+                type1TextVal);
+        final LeafNode<String> typeText2Leaf = ImmutableNodes.leafNode(typeText2,
+                type2TextVal);
+        final LeafNode<String> typeText3Leaf = ImmutableNodes.leafNode(typeText3,
+                type3TextVal);
+        final LeafNode<String> descLeaf = ImmutableNodes.leafNode(devDesc, descVal);
+        final LeafNode<Integer> snValLeaf = ImmutableNodes.leafNode(sn, snVal);
+        final LeafNode<String> defaultIpLeaf = ImmutableNodes.leafNode(defaultIp,
+                defaultIpVal);
+
+        final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> devicesMapEntryBldr = Builders
+                .mapEntryBuilder(devicesListSchemaNode);
+
+        devicesMapEntryBldr.addChild(typeText1Leaf);
+        devicesMapEntryBldr.addChild(typeText2Leaf);
+        devicesMapEntryBldr.addChild(typeText3Leaf);
+        devicesMapEntryBldr.addChild(descLeaf);
+        devicesMapEntryBldr.addChild(snValLeaf);
+        devicesMapEntryBldr.addChild(defaultIpLeaf);
+
+        return devicesMapEntryBldr.build();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTest.java
new file mode 100644 (file)
index 0000000..eb3143d
--- /dev/null
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class LeafRefContextTest {
+
+    private static SchemaContext context;
+    private static Module rootMod;
+    private static QNameModule root;
+    private static LeafRefContext rootLeafRefContext;
+
+    @BeforeClass
+    public static void init() throws URISyntaxException, IOException,
+            YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+
+        final File resourceFile = new File(
+                LeafRefContextTreeBuilderTest.class
+                        .getResource(
+                                "/leafref-context-test/correct-modules/leafref-test2.yang")
+                        .toURI());
+
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        context = parser.parseFile(resourceFile, resourceDir);
+
+        final Set<Module> modules = context.getModules();
+        for (final Module module : modules) {
+            if (module.getName().equals("leafref-test2")) {
+                rootMod = module;
+            }
+        }
+
+        root = rootMod.getQNameModule();
+        rootLeafRefContext = LeafRefContext.create(context);
+    }
+
+    @Test
+    public void test() {
+
+        final QName q1 = QName.create(root, "ref1");
+        final QName q2 = QName.create(root, "leaf1");
+        final QName q3 = QName.create(root, "cont1");
+        final QName q4 = QName.create(root, "cont2");
+        final QName q5 = QName.create(root, "list1");
+        final QName q6 = QName.create(root, "name");
+
+        final DataSchemaNode leafRefNode = rootMod.getDataChildByName(q1);
+        final DataSchemaNode targetNode = rootMod.getDataChildByName(q2);
+        final DataSchemaNode cont1Node = rootMod.getDataChildByName(q3);
+        final DataSchemaNode cont2Node = rootMod.getDataChildByName(q4);
+        final DataSchemaNode name1Node = ((DataNodeContainer) ((DataNodeContainer) rootMod
+                .getDataChildByName(q3)).getDataChildByName(q5))
+                .getDataChildByName(q6);
+
+        assertTrue(LeafRefContextUtils.isLeafRef(leafRefNode,
+                rootLeafRefContext));
+        assertFalse(LeafRefContextUtils.isLeafRef(targetNode,
+                rootLeafRefContext));
+
+        assertTrue(LeafRefContextUtils.hasLeafRefChild(cont1Node,
+                rootLeafRefContext));
+        assertFalse(LeafRefContextUtils.hasLeafRefChild(leafRefNode,
+                rootLeafRefContext));
+
+        assertTrue(LeafRefContextUtils.isReferencedByLeafRef(targetNode,
+                rootLeafRefContext));
+        assertFalse(LeafRefContextUtils.isReferencedByLeafRef(leafRefNode,
+                rootLeafRefContext));
+
+        assertTrue(LeafRefContextUtils.hasChildReferencedByLeafRef(cont2Node,
+                rootLeafRefContext));
+        assertFalse(LeafRefContextUtils.hasChildReferencedByLeafRef(
+                leafRefNode, rootLeafRefContext));
+
+        Map<QName, LeafRefContext> leafRefs = LeafRefContextUtils
+                .getAllLeafRefsReferencingThisNode(name1Node,
+                        rootLeafRefContext);
+        assertEquals(4, leafRefs.size());
+        leafRefs = LeafRefContextUtils.getAllLeafRefsReferencingThisNode(
+                leafRefNode, rootLeafRefContext);
+        assertTrue(leafRefs.isEmpty());
+    }
+}
diff --git a/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTreeBuilderTest.java b/yang/yang-data-impl/src/test/java/org/opendaylight/yangtools/yang/data/impl/leafref/context/test/LeafRefContextTreeBuilderTest.java
new file mode 100644 (file)
index 0000000..110f246
--- /dev/null
@@ -0,0 +1,281 @@
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.data.impl.leafref.context.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContext;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefContextUtils;
+import org.opendaylight.yangtools.yang.data.impl.leafref.LeafRefYangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public class LeafRefContextTreeBuilderTest {
+
+    private static SchemaContext context;
+    private static Module impMod;
+    private static Module tstMod;
+    private static QNameModule imp;
+    private static QNameModule tst;
+    private static LeafRefContext rootLeafRefContext;
+
+    @BeforeClass
+    public static void init() throws URISyntaxException, IOException,
+            YangSyntaxErrorException, LeafRefYangSyntaxErrorException {
+        final File resourceFile = new File(
+                LeafRefContextTreeBuilderTest.class
+                        .getResource(
+                                "/leafref-context-test/correct-modules/leafref-test.yang")
+                        .toURI());
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        context = parser.parseFile(resourceFile, resourceDir);
+
+        final Set<Module> modules = context.getModules();
+        for (final Module module : modules) {
+            if (module.getName().equals("import-mod")) {
+                impMod = module;
+            }
+            if (module.getName().equals("leafref-test")) {
+                tstMod = module;
+            }
+        }
+
+        imp = impMod.getQNameModule();
+        tst = tstMod.getQNameModule();
+
+        rootLeafRefContext = LeafRefContext.create(context);
+    }
+
+    @Test
+    public void buildLeafRefContextTreeTest1() {
+
+        final QName q1 = QName.create(tst, "odl-project");
+        final QName q2 = QName.create(tst, "project");
+        final QName q3 = QName.create(tst, "project-lead");
+
+        final LeafRefContext leafRefCtx = rootLeafRefContext
+                .getReferencingChildByName(q1).getReferencingChildByName(q2)
+                .getReferencingChildByName(q3);
+
+        assertTrue(leafRefCtx.isReferencing());
+        assertNotNull(leafRefCtx.getLeafRefTargetPath());
+        assertFalse(leafRefCtx.getLeafRefTargetPath().isAbsolute());
+        assertNotNull(leafRefCtx.getAbsoluteLeafRefTargetPath());
+        assertTrue(leafRefCtx.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+        System.out.println();
+        System.out.println("******* Test 1 ************");
+        System.out.println("Original definition string:");
+        System.out.println(leafRefCtx.getLeafRefTargetPathString());
+        System.out.println("Parsed leafref path:");
+        System.out.println(leafRefCtx.getLeafRefTargetPath().toString());
+        System.out.println("Absolute leafref path:");
+        System.out
+                .println(leafRefCtx.getAbsoluteLeafRefTargetPath().toString());
+    }
+
+    @Test
+    public void buildLeafRefContextTreeTest2() {
+
+        final QName q1 = QName.create(tst, "odl-project");
+        final QName q2 = QName.create(tst, "project");
+        final QName q4 = QName.create(tst, "project-lead2");
+
+        final LeafRefContext leafRefCtx2 = rootLeafRefContext
+                .getReferencingChildByName(q1).getReferencingChildByName(q2)
+                .getReferencingChildByName(q4);
+
+        assertTrue(leafRefCtx2.isReferencing());
+        assertNotNull(leafRefCtx2.getLeafRefTargetPath());
+        assertTrue(leafRefCtx2.getLeafRefTargetPath().isAbsolute());
+        assertNotNull(leafRefCtx2.getAbsoluteLeafRefTargetPath());
+        assertTrue(leafRefCtx2.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+        System.out.println();
+        System.out.println("******* Test 2 ************");
+        System.out.println("Original definition string2:");
+        System.out.println(leafRefCtx2.getLeafRefTargetPathString());
+        System.out.println("Parsed leafref path2:");
+        System.out.println(leafRefCtx2.getLeafRefTargetPath().toString());
+        System.out.println("Absolute leafref path2:");
+        System.out.println(leafRefCtx2.getAbsoluteLeafRefTargetPath()
+                .toString());
+        System.out.println();
+
+    }
+
+    @Test
+    public void buildLeafRefContextTreeXPathTest() {
+        final QName q1 = QName.create(tst, "odl-project");
+        final QName q2 = QName.create(tst, "project");
+        final QName q5 = QName.create(tst, "ch1");
+        final QName q6 = QName.create(tst, "c1");
+        final QName q7 = QName.create(tst, "ch2");
+        final QName q8 = QName.create(tst, "l1");
+        final LeafRefContext leafRefCtx3 = rootLeafRefContext
+                .getReferencingChildByName(q1).getReferencingChildByName(q2)
+                .getReferencingChildByName(q5).getReferencingChildByName(q6)
+                .getReferencingChildByName(q7).getReferencingChildByName(q6)
+                .getReferencingChildByName(q8);
+
+        assertTrue(leafRefCtx3.isReferencing());
+        assertNotNull(leafRefCtx3.getLeafRefTargetPath());
+        assertFalse(leafRefCtx3.getLeafRefTargetPath().isAbsolute());
+        assertNotNull(leafRefCtx3.getAbsoluteLeafRefTargetPath());
+        assertTrue(leafRefCtx3.getAbsoluteLeafRefTargetPath().isAbsolute());
+
+        System.out.println();
+        System.out.println("******* Test 3 ************");
+        System.out.println("Original definition string2:");
+        System.out.println(leafRefCtx3.getLeafRefTargetPathString());
+        System.out.println("Parsed leafref path2:");
+        System.out.println(leafRefCtx3.getLeafRefTargetPath().toString());
+        System.out.println("Absolute leafref path2:");
+        System.out.println(leafRefCtx3.getAbsoluteLeafRefTargetPath()
+                .toString());
+        System.out.println();
+    }
+
+    @Test
+    public void buildLeafRefContextTreeTest4() {
+        final QName q9 = QName.create(tst, "odl-project");
+        final QName q10 = QName.create(tst, "project");
+        final QName q11 = QName.create(tst, "name");
+
+        final LeafRefContext leafRefCtx4 = rootLeafRefContext
+                .getReferencedChildByName(q9).getReferencedChildByName(q10)
+                .getReferencedChildByName(q11);
+
+        assertNotNull(leafRefCtx4);
+        assertTrue(leafRefCtx4.isReferenced());
+        assertEquals(6, leafRefCtx4.getAllReferencedByLeafRefCtxs().size());
+
+    }
+
+    @Test
+    public void leafRefContextUtilsTest() {
+        final QName q1 = QName.create(tst, "odl-contributor");
+        final QName q2 = QName.create(tst, "contributor");
+        final QName q3 = QName.create(tst, "odl-project-name");
+
+        final LeafRefContext odlContrProjNameCtx = rootLeafRefContext
+                .getReferencingChildByName(q1).getReferencingChildByName(q2)
+                .getReferencingChildByName(q3);
+
+        final DataSchemaNode odlContrProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod
+                .getDataChildByName(q1)).getDataChildByName(q2))
+                .getDataChildByName(q3);
+
+        final LeafRefContext foundOdlContrProjNameCtx = LeafRefContextUtils
+                .getLeafRefReferencingContext(odlContrProjNameNode,
+                        rootLeafRefContext);
+
+        assertNotNull(foundOdlContrProjNameCtx);
+        assertTrue(foundOdlContrProjNameCtx.isReferencing());
+        assertNotNull(foundOdlContrProjNameCtx.getLeafRefTargetPath());
+        assertEquals(odlContrProjNameCtx, foundOdlContrProjNameCtx);
+    }
+
+    @Test
+    public void leafRefContextUtilsTest2() {
+        final QName q1 = QName.create(tst, "odl-project");
+        final QName q2 = QName.create(tst, "project");
+        final QName q3 = QName.create(tst, "name");
+
+        final LeafRefContext leafRefCtx = rootLeafRefContext
+                .getReferencedChildByName(q1).getReferencedChildByName(q2)
+                .getReferencedChildByName(q3);
+
+        final DataSchemaNode odlProjNameNode = ((DataNodeContainer) ((DataNodeContainer) tstMod
+                .getDataChildByName(q1)).getDataChildByName(q2))
+                .getDataChildByName(q3);
+
+        LeafRefContext foundOdlProjNameCtx = LeafRefContextUtils
+                .getLeafRefReferencingContext(odlProjNameNode,
+                        rootLeafRefContext);
+
+        assertNull(foundOdlProjNameCtx);
+
+        foundOdlProjNameCtx = LeafRefContextUtils
+                .getLeafRefReferencedByContext(odlProjNameNode,
+                        rootLeafRefContext);
+
+        assertNotNull(foundOdlProjNameCtx);
+        assertTrue(foundOdlProjNameCtx.isReferenced());
+        assertFalse(foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs()
+                .isEmpty());
+        assertEquals(6, foundOdlProjNameCtx.getAllReferencedByLeafRefCtxs()
+                .size());
+        assertEquals(leafRefCtx, foundOdlProjNameCtx);
+    }
+
+    @Test
+    public void leafRefContextUtilsTest3() {
+        final QName q16 = QName.create(tst, "con1");
+        final DataSchemaNode con1 = tstMod.getDataChildByName(q16);
+        final List<LeafRefContext> allLeafRefChilds = LeafRefContextUtils
+                .findAllLeafRefChilds(con1, rootLeafRefContext);
+
+        assertNotNull(allLeafRefChilds);
+        assertFalse(allLeafRefChilds.isEmpty());
+        assertEquals(4, allLeafRefChilds.size());
+
+        final QName q17 = QName.create(tst, "odl-contributor");
+        final DataSchemaNode odlContributorNode = tstMod.getDataChildByName(q17);
+        List<LeafRefContext> allChildsReferencedByLeafRef = LeafRefContextUtils
+                .findAllChildsReferencedByLeafRef(odlContributorNode,
+                        rootLeafRefContext);
+
+        assertNotNull(allChildsReferencedByLeafRef);
+        assertFalse(allChildsReferencedByLeafRef.isEmpty());
+        assertEquals(1, allChildsReferencedByLeafRef.size());
+
+        allChildsReferencedByLeafRef = LeafRefContextUtils
+                .findAllChildsReferencedByLeafRef(con1, rootLeafRefContext);
+
+        assertNotNull(allChildsReferencedByLeafRef);
+        assertTrue(allChildsReferencedByLeafRef.isEmpty());
+
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void incorrectLeafRefPathTest() throws URISyntaxException,
+            IOException, YangSyntaxErrorException,
+            LeafRefYangSyntaxErrorException {
+        final File resourceFile = new File(getClass().getResource(
+                "/leafref-context-test/incorrect-modules/leafref-test.yang")
+                .toURI());
+        final File resourceDir = resourceFile.getParentFile();
+
+        final YangParserImpl parser = YangParserImpl.getInstance();
+        final SchemaContext context = parser.parseFile(resourceFile, resourceDir);
+
+        LeafRefContext.create(context);
+
+    }
+
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/import-mod.yang b/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/import-mod.yang
new file mode 100644 (file)
index 0000000..826a339
--- /dev/null
@@ -0,0 +1,10 @@
+module import-mod {
+    namespace "pk.import";
+    prefix imp;
+
+    revision 2014-10-07 {
+        description
+                "Yang initial revision";
+    }
+
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test.yang b/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test.yang
new file mode 100644 (file)
index 0000000..1bf8f42
--- /dev/null
@@ -0,0 +1,152 @@
+module leafref-test {
+    namespace "pk.test";
+    prefix tst;
+
+    import import-mod { prefix imp; revision-date 2014-10-07; }
+
+    revision 1999-09-09 {
+        description
+                "Yang initial revision";
+    }
+
+    container odl-contributor {
+        list contributor {
+            key "login";
+            leaf login {
+                type string;
+            }
+            leaf contributor-name {
+                type string;
+            }
+            leaf odl-project-name {
+                type leafref {
+                    path "/odl-project/project/name";
+                }
+            }
+        }
+        list noleafref-contributor {
+            leaf foo {
+                type string;
+            }
+        }
+    }
+
+    container odl-project {
+        list project {
+            key "name";
+            leaf name {
+                type string;
+            }
+            leaf project-lead {
+                type leafref {
+                    path "../../../tst:odl-contributor[imp:foo=current()/bar]/contributor[tst:odl-project-name
+                                        = current()/../imp:name][odl-project-name2 = current()/../../imp:name/tst:name2][imp:odl-project-name3
+                                        = current()/../../imp:name/imp:name2]/tst:login";
+                }
+            }
+            leaf project-lead2 {
+                type leafref {
+                    path "/odl-contributor[foo=current()/bar]/contributor[odl-project-name
+                                        = current()/../name][odl-project-name2 = current()/../../name/name2][odl-project-name3
+                                        = current()/../../name/name2]/login";
+                }
+            }
+
+            choice ch1 {
+                case c1 {
+                    choice ch2 {
+                        case c1 {
+                            leaf l1 {
+                                type leafref {
+                                    path "../../con1/l1";
+                                }
+                            }
+                        }
+                        case c2 {
+                        }
+                    }
+                }
+                case c2 {
+                }
+            }
+        }
+        list noleafref-project {
+            leaf foo {
+                type string;
+            }
+        }
+        container con1 {
+            leaf l1 {
+                type empty;
+            }
+        }
+    }
+
+    container con1 {
+        container con2 {
+            container con3 {
+                leaf l1 {
+                    type leafref {
+                        path "/odl-project/project/name";
+                    }
+                }
+                leaf l2 {
+                    type leafref {
+                        path "/odl-project/project/name";
+                    }
+                }
+                leaf l3-noleafref {
+                    type int16;
+                }
+            }
+            leaf l4 {
+                type leafref {
+                    path "/odl-project/project/name";
+                }
+            }
+            leaf l5-noleafref {
+                type int16;
+            }
+        }
+        leaf l6 {
+            type leafref {
+                path "/odl-project/project/name";
+            }
+        }
+        leaf l7-noleafref {
+            type int16;
+        }
+    }
+
+    leaf l8 {
+        type leafref {
+            path "/odl-project/project/name";
+        }
+    }
+
+    container no-leafrefcontainer {
+        list no-leafreflist {
+            leaf bar {
+                type string;
+            }
+        }
+        container no-leafrefcontainer2 {
+            leaf baz {
+                type string;
+            }
+        }
+    }
+
+    container no-leafrefcontainer2 {
+        list no-leafreflist {
+            leaf bar {
+                type string;
+            }
+        }
+        container no-leafrefcontainer2 {
+            leaf baz {
+                type string;
+            }
+        }
+    }
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test2.yang b/yang/yang-data-impl/src/test/resources/leafref-context-test/correct-modules/leafref-test2.yang
new file mode 100644 (file)
index 0000000..b707a70
--- /dev/null
@@ -0,0 +1,83 @@
+module leafref-test2 {
+    namespace "gz.test";
+    prefix "main";
+
+    revision 2015-02-13 {
+        description "Initial revision";
+    }
+
+    leaf leaf1 {
+        type int16;
+    }
+
+    leaf ref1 {
+        type leafref {
+            path "../leaf1";
+        }
+    }
+
+    typedef low_int {
+        type int8 {
+            range 1..100;
+        }
+    }
+
+    container cont1 {
+
+        list list1 {
+            leaf name {
+                type string;
+            }
+            leaf id {
+                type int32;
+            }
+            leaf value {
+                type low_int;
+            }
+            leaf external {
+                type leafref {
+                    path "../../../cont2/value";
+                }
+            }
+        }
+    }
+
+    container cont2 {
+        leaf value {
+            type decimal64 {
+                fraction-digits 4;
+            }
+        }
+    }
+
+    container cont3 {
+        container cont4 {
+            leaf l1 {
+                type leafref {
+                    path "/cont1/list1/name";
+                }
+            }
+            leaf l2 {
+                type leafref {
+                    path "../../../cont1/list1/name";
+                }
+            }
+        }
+        leaf l3 {
+            type leafref {
+                path "/cont1/list1/name";
+            }
+        }
+        leaf l4 {
+            type int32;
+        }
+    }
+
+    container cont5 {
+        leaf l5 {
+            type leafref {
+                path "/cont1/list1/name";
+            }
+        }
+    }
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-context-test/incorrect-modules/leafref-test.yang b/yang/yang-data-impl/src/test/resources/leafref-context-test/incorrect-modules/leafref-test.yang
new file mode 100644 (file)
index 0000000..ae33ffb
--- /dev/null
@@ -0,0 +1,114 @@
+module leafref-test {
+    namespace "test";
+    prefix test;
+
+    container odl-contributor {
+        list contributor {
+            key "login";
+            leaf login {
+                type string;
+            }
+            leaf contributor-name {
+                type string;
+            }
+            leaf odl-project-name {
+                type leafref {
+                    path ".../odl-project/project/name";
+                }
+            }
+        }
+        list noleafref-contributor {
+            leaf foo {
+                type string;
+            }
+        }
+    }
+
+    container odl-project {
+        list project {
+            key "name";
+            leaf name {
+                type string;
+            }
+            leaf project-lead {
+                type leafref {
+                    path "/odl-contributor/contributor/login";
+                }
+            }
+        }
+        list noleafref-project {
+            leaf foo {
+                type string;
+            }
+        }
+    }
+
+    container con1 {
+        container con2 {
+            container con3 {
+                leaf l1 {
+                    type leafref {
+                        path "/odl-project/project/name";
+                    }
+                }
+                leaf l2 {
+                    type leafref {
+                        path "/odl-project/project/name";
+                    }
+                }
+                leaf l3-noleafref {
+                    type int16;
+                }
+            }
+            leaf l4 {
+                type leafref {
+                    path "/odl-project/project/name";
+                }
+            }
+            leaf l5-noleafref {
+                type int16;
+            }
+        }
+        leaf l6 {
+            type leafref {
+                path "/odl-project/project/name";
+            }
+        }
+        leaf l7-noleafref {
+            type int16;
+        }
+    }
+
+    leaf l8 {
+        type leafref {
+            path "/odl-project/project/name";
+        }
+    }
+
+    container no-leafrefcontainer {
+        list no-leafreflist {
+            leaf bar {
+                type string;
+            }
+        }
+        container no-leafrefcontainer2 {
+            leaf baz {
+                type string;
+            }
+        }
+    }
+
+    container no-leafrefcontainer2 {
+        list no-leafreflist {
+            leaf bar {
+                type string;
+            }
+        }
+        container no-leafrefcontainer2 {
+            leaf baz {
+                type string;
+            }
+        }
+    }
+
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation.yang b/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation.yang
new file mode 100644 (file)
index 0000000..60e2df8
--- /dev/null
@@ -0,0 +1,150 @@
+module leafref-validation {
+    namespace "leafref.validation";
+    prefix val;
+
+    leaf l1 {
+        type leafref {
+            path "../l2";
+        }
+    }
+
+    leaf l2 {
+        type string;
+    }
+
+    container odl-contributor {
+        list contributor {
+            key "login";
+            leaf login {
+                type string;
+            }
+            leaf contributor-name {
+                type string;
+            }
+            leaf odl-group-id {
+                type string;
+            }
+            leaf odl-project-name {
+                type leafref {
+                    path "../../../odl-project/project/name";
+                }
+            }
+            leaf odl-project-desc {
+                type leafref {
+                    path "/odl-project/project[name = current()/../odl-project-name]/desc";
+                }
+                // type string;                                    
+            }
+        }
+        list noleafref-contributor {
+            leaf foo {
+                type string;
+            }
+        }
+    }
+
+    container odl-project {
+        list project {
+            key "name";
+            leaf name {
+                type string;
+            }
+            leaf desc {
+                type string;
+            }
+            leaf project-lead {
+                type leafref {
+                    path "../../../odl-contributor/contributor/login";
+                }
+            }
+            leaf project-owner {
+                type leafref {
+                    path "/odl-contributor/contributor/login";
+                }
+            }
+        }
+
+        choice ch1 {
+            case c1 {
+                choice ch2 {
+                    case c1 {
+                        list list-in-choice {
+                            key "list-in-choice-key";
+                            leaf list-in-choice-key {
+                                type string;
+                            }
+                            leaf leafref-in-choice {
+                                type leafref {
+                                    path "../../con1/l1";
+                                }
+                            }
+                            leaf leafref-in-choice-to-choice {
+                                type leafref {
+                                    path "../../con3/list3-in-choice/l3";
+                                }
+                            }
+                        }
+                    }
+                    case c2 {
+                    }
+                }
+            }
+            case c2 {
+            }
+        }
+
+        list noleafref-project {
+            leaf foo {
+                type string;
+            }
+        }
+        container con1 {
+            leaf l1 {
+                type string;
+            }
+        }
+
+        container con3 {
+            choice choice-in-con3 {
+                case one {
+                    list list3-in-choice {
+                        key "k";
+                        leaf k {
+                            type string;
+                        }
+                        leaf-list l3 {
+                            type string;
+                        }
+                    }
+                }
+                case two {
+                    list list3-in-choice-2 {
+                        key "l3-2";
+                        leaf l3-2 {
+                            type string;
+                        }
+                    }
+                }
+            }
+        }
+
+        leaf-list leafref-leaf-list {
+            type leafref {
+                path "../con3/list3-in-choice/k";
+            }
+        }
+    }
+
+    container no-leafrefcontainer {
+        list no-leafreflist {
+            leaf bar {
+                type string;
+            }
+        }
+        container no-leafrefcontainer2 {
+            leaf baz {
+                type string;
+            }
+        }
+    }
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation2.yang b/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation2.yang
new file mode 100644 (file)
index 0000000..0a103e3
--- /dev/null
@@ -0,0 +1,52 @@
+module leafref-validation2 {
+    namespace "leafref.validation2";
+    prefix val2;
+
+    container device_types {
+        list device_type {
+            key "type";
+            leaf type {
+                type string;
+            }
+            leaf desc {
+                type string;
+            }
+        }
+    }
+
+    container devices {
+        list device {
+            key "type_text sn";
+            leaf type_text {
+                type leafref {
+                    path "/device_types/device_type/type";
+                }
+            }
+            leaf dev_desc {
+                type leafref {
+                    path "/device_types/device_type[type = current()/../type_text]/desc";
+                }
+            }
+            leaf sn {
+                type int32;
+            }
+            leaf default_ip {
+                type string;
+            }
+        }
+    }
+
+    container chips {
+        list chip {
+            key "dev_type";
+            leaf dev_type {
+                type leafref {
+                    path "/devices/device/type_text";
+                }
+            }
+            leaf chip_desc {
+                type string;
+            }
+        }
+    }
+}
diff --git a/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation3.yang b/yang/yang-data-impl/src/test/resources/leafref-validation/leafref-validation3.yang
new file mode 100644 (file)
index 0000000..6823e10
--- /dev/null
@@ -0,0 +1,70 @@
+module leafref-validation3 {
+    namespace "leafref.validation3";
+    prefix val3;
+
+    container device_types {
+        list device_type {
+            key "type1 type2 type3";
+            leaf type1 {
+                type string;
+            }
+            leaf type2 {
+                type string;
+            }
+            leaf type3 {
+                type string;
+            }
+            leaf desc {
+                type string;
+            }
+        }
+    }
+
+    container devices {
+        list device {
+            key "type_text1 sn";
+            unique "sn";
+            leaf type_text1 {
+                type leafref {
+                    path "/device_types/device_type/type1";
+                }
+            }
+            leaf type_text2 {
+                type leafref {
+                    path "/device_types/device_type/type2";
+                }
+            }
+            leaf type_text3 {
+                type leafref {
+                    path "/device_types/device_type/type3";
+                }
+            }
+            leaf dev_desc {
+                type leafref {
+                    path "/device_types/device_type[type1 = current()/../type_text1][type2
+                                        = current()/../type_text2][type3 = current()/../type_text3]/desc";
+                }
+            }
+            leaf sn {
+                type int32;
+            }
+            leaf default_ip {
+                type string;
+            }
+        }
+    }
+
+    container chips {
+        list chip {
+            key "dev_type";
+            leaf dev_type {
+                type leafref {
+                    path "/devices/device/type_text";
+                }
+            }
+            leaf chip_desc {
+                type string;
+            }
+        }
+    }
+}
index dec5406e42c133f1a19af14fc386e67a5ab2abaa..a11ebf851083d2007f77f37110e16260f49017cd 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 85d904a2698534df081c0e47ec91e626edb5d78a..fc0d94592c266beb3ee15f89ed9f0081be8a74af 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 29048f106d844ff46212fc71bad37b1e9e2dbb5c..c3e8eea65abb7492d277d96fead54b5dcf6f159e 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 3c88fe63fc49a502ff1e75ae114b4e658293027f..6cbbd6051b8d61f25b28020e82ae70671220acd0 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index ab9085398894e628fd1c76d2062229c8c9c7d163..35b6f770d8967f1560239a9b26487bc08d655d23 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 10361ba20ccb79768a550382f7e058819dcd576f..ca4d5540dde7d2e7c2f25a2dc3f8270ca3ded124 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 31f82961be842eefee343fc264153854b0db4223..81699215b7bade14eaf610123f5a1feaa005c310 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 50e2a926fd477971698d26091e4f5fb93046b68a..64284634adbc14c128d9bdbafd11c80cb4655fe0 100644 (file)
@@ -13,7 +13,7 @@
     <parent>
         <groupId>org.opendaylight.odlparent</groupId>
         <artifactId>bundle-parent</artifactId>
-        <version>1.5.0-SNAPSHOT</version>
+        <version>1.6.0-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <groupId>org.opendaylight.yangtools</groupId>
     <artifactId>yang-model-parent</artifactId>
     <packaging>pom</packaging>
-    <version>0.7.0-SNAPSHOT</version>
+    <version>0.8.0-SNAPSHOT</version>
 
     <properties>
-        <yangtools.version>0.7.0-SNAPSHOT</yangtools.version>
+        <yangtools.version>0.8.0-SNAPSHOT</yangtools.version>
     </properties>
 
     <dependencyManagement>
index f484e09d3a54d878eebbef8a4a74c4dff36d26ce..06c1b73089a3253792f4c75c76e910da515766be 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index ee32cd90d54d5d17887485c376a8c4f2e0f1f830..448ef2f664cf9b1f4bcf0660587c3fc23f4c7990 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 6115c83b578108ce4dc9e219c481516708a140bc..5cb407ed8da222d82d70eaaae65436e082aae5c0 100644 (file)
@@ -12,7 +12,7 @@
     <parent>
         <groupId>org.opendaylight.yangtools</groupId>
         <artifactId>yangtools-parent</artifactId>
-        <version>0.7.0-SNAPSHOT</version>
+        <version>0.8.0-SNAPSHOT</version>
         <relativePath>/../../common/parent/pom.xml</relativePath>
     </parent>
 
index 0aac6edbf575eae74cd831bb2025f5594a35582b..b5b3cf02915647a449fb6b25d3086f9fcb7ed44b 100644 (file)
@@ -24,6 +24,9 @@ import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReferenc
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
 
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
 public class YangStatementParserListenerImpl extends YangStatementParserBaseListener {
 
     private StatementWriter writer;
@@ -57,7 +60,7 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList
                 try {
                     QName identifier = new QName(YangConstants.RFC6020_YIN_NAMESPACE,
                             ((YangStatementParser.KeywordContext) child).children.get(0).getText());
-                    if (stmtDef != null && stmtDef.get(identifier) != null && toBeSkipped.isEmpty()) {
+                    if (stmtDef != null && Utils.isValidStatementDefinition(prefixes, stmtDef, identifier) && toBeSkipped.isEmpty()) {
                         writer.startStatement(identifier, ref);
                     } else {
                         action = false;
@@ -90,7 +93,7 @@ public class YangStatementParserListenerImpl extends YangStatementParserBaseList
                 try {
                     String statementName = ((YangStatementParser.KeywordContext) child).children.get(0).getText();
                     QName identifier = new QName(YangConstants.RFC6020_YIN_NAMESPACE, statementName);
-                    if (stmtDef != null && stmtDef.get(identifier) != null && toBeSkipped.isEmpty()) {
+                    if (stmtDef != null && Utils.isValidStatementDefinition(prefixes, stmtDef, identifier) && toBeSkipped.isEmpty()) {
                         writer.endStatement(ref);
                     }
 
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/PrefixToModuleMap.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/PrefixToModuleMap.java
new file mode 100644 (file)
index 0000000..e01e5ae
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.spi.source;
+
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+import javax.annotation.Nullable;
+import java.util.HashMap;
+import java.util.Map;
+
+public class PrefixToModuleMap implements PrefixToModule {
+
+    private Map<String, QNameModule> prefixToModuleMap = new HashMap<>();
+
+    public void put(String prefix, QNameModule qNameModule) {
+        prefixToModuleMap.put(prefix, qNameModule);
+    }
+
+    @Nullable
+    @Override
+    public QNameModule get(String prefix) {
+        return prefixToModuleMap.get(prefix);
+    }
+
+    @Nullable
+    @Override
+    public QNameModule getByNamespace(String namespace) {
+        return null;
+    }
+}
index f0767c7f3acd151f88258a2c153b147958c310b4..091360e04c6debc8e3f9807dd7ad3d4e05c137ef 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.yangtools.yang.parser.spi.source;
 
 import org.opendaylight.yangtools.yang.common.QName;
@@ -8,15 +15,16 @@ import javax.annotation.Nullable;
 import java.util.HashMap;
 import java.util.Map;
 
-public class QNameToStatementDefinitionMap implements QNameToStatementDefinition{
+public class QNameToStatementDefinitionMap implements QNameToStatementDefinition {
 
     private Map<QName, StatementDefinition> qNameToStmtDefMap = new HashMap<>();
 
-    public void put(QName qName, StatementDefinition stDef ) {
+    public void put(QName qName, StatementDefinition stDef) {
         qNameToStmtDefMap.put(qName, stDef);
     }
 
-    @Nullable @Override
+    @Nullable
+    @Override
     public StatementDefinition get(@Nonnull QName identifier) {
         return qNameToStmtDefMap.get(identifier);
     }
index d6ddc551c228760036f7d965113169993ce672f6..847f8e988e43040f221fbcd064af34cefd225d37 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangConstants;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 
 import com.google.common.base.Preconditions;
@@ -23,6 +25,8 @@ import org.opendaylight.yangtools.concepts.Mutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ImportedNamespaceContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
@@ -32,12 +36,15 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Namesp
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModuleMap;
 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinitionMap;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextBuilder;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
 
 public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable {
 
@@ -57,6 +64,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
     private ModelProcessingPhase inProgressPhase;
     private ModelProcessingPhase finishedPhase;
     private QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap();
+    private PrefixToModuleMap prefixToModuleMap = new PrefixToModuleMap();
 
 
     SourceSpecificContext(BuildGlobalContext currentContext,StatementStreamSource source) {
@@ -70,7 +78,15 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
 
     ContextBuilder<?, ?, ?> createDeclaredChild(StatementContextBase<?, ?, ?> current, QName name, StatementSourceReference ref) {
         StatementDefinitionContext<?,?,?> def = getDefinition(name);
-        Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.",name);
+
+        //extensions
+        if (def == null) {
+            if (Utils.isValidStatementDefinition(prefixToModuleMap, qNameToStmtDefMap, name)) {
+                def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition(qNameToStmtDefMap.get(Utils.trimPrefix(name))));
+            }
+        }
+
+        Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.", name);
         if(current == null) {
             return createDeclaredRoot(def,ref);
         }
@@ -216,13 +232,13 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
 
     void loadStatements() throws SourceException {
         switch (inProgressPhase) {
-        case SOURCE_LINKAGE:
+            case SOURCE_LINKAGE:
             source.writeLinkage(new StatementContextWriter(this, inProgressPhase),stmtDef());
             break;
-        case STATEMENT_DEFINITION:
+            case STATEMENT_DEFINITION:
             source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
             break;
-        case FULL_DECLARATION:
+            case FULL_DECLARATION:
             source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
             break;
         default:
@@ -231,16 +247,30 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
     }
 
     private PrefixToModule prefixes() {
-        // TODO Auto-generated method stub
-        return null;
+        Map<String, QNameModule> prefixes = (Map<String, QNameModule>) currentContext.getAllFromNamespace(PrefixToModule.class);
+        for (Map.Entry<String, QNameModule> prefix : prefixes.entrySet()) {
+            prefixToModuleMap.put(prefix.getKey(), prefix.getValue());
+        }
+        return prefixToModuleMap;
     }
 
     private QNameToStatementDefinition stmtDef() {
+        //regular YANG statements added
         ImmutableMap<QName, StatementSupport<?, ?, ?>> definitions = currentContext.getSupportsForPhase(
                 inProgressPhase).getDefinitions();
         for (Map.Entry<QName, StatementSupport<?,?,?>> entry : definitions.entrySet()) {
             qNameToStmtDefMap.put(entry.getKey(), entry.getValue());
         }
+
+        //extensions added
+        if (inProgressPhase.equals(ModelProcessingPhase.FULL_DECLARATION)) {
+            Map<QName, SubstatementContext<?, ?, ?>> extensions = (Map<QName, SubstatementContext<?, ?, ?>>) currentContext.getAllFromNamespace(ExtensionNamespace.class);
+            if (extensions != null) {
+                for (Map.Entry<QName, SubstatementContext<?, ?, ?>> extension : extensions.entrySet()) {
+                    qNameToStmtDefMap.put(new QName(YangConstants.RFC6020_YIN_NAMESPACE, extension.getKey().getLocalName()), (StatementDefinition) extension.getValue().definition().getFactory());
+                }
+            }
+        }
         return qNameToStmtDefMap;
     }
 }
index 2e9c54ffdd57abdf1be777a57ddc3719311f86c4..e3ff0d39fb7a3092fc9b6e062ac8c95252eb904c 100644 (file)
@@ -8,18 +8,20 @@
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ExtensionEffectiveStatementImpl;
-
-import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentStatement;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.ArgumentStatement;
 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
+import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 public class ExtensionStatementImpl extends AbstractDeclaredStatement<QName> implements ExtensionStatement {
 
@@ -35,7 +37,7 @@ public class ExtensionStatementImpl extends AbstractDeclaredStatement<QName> imp
 
         @Override
         public QName parseArgumentValue(StmtContext<?,?,?> ctx, String value) {
-            return Utils.qNameFromArgument(ctx,value);
+            return Utils.qNameFromArgument(ctx, value);
         }
 
         @Override
@@ -48,6 +50,10 @@ public class ExtensionStatementImpl extends AbstractDeclaredStatement<QName> imp
            return new ExtensionEffectiveStatementImpl(ctx);
         }
 
+        @Override
+        public void onStatementDefinitionDeclared(final StmtContext.Mutable<QName, ExtensionStatement, EffectiveStatement<QName, ExtensionStatement>> stmt) throws InferenceException, SourceException {
+            stmt.addContext(ExtensionNamespace.class, stmt.getStatementArgument(), stmt);
+        }
     }
 
     @Override
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UnknownStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UnknownStatementImpl.java
new file mode 100644 (file)
index 0000000..1dbb030
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
+
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.UnknownStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+import javax.annotation.Nullable;
+
+public class UnknownStatementImpl extends AbstractDeclaredStatement<String> implements UnknownStatement<String> {
+
+    protected UnknownStatementImpl(StmtContext<String, ?, ?> context) {
+        super(context);
+    }
+
+    public static class Definition extends AbstractStatementSupport<String, UnknownStatement<String>, EffectiveStatement<String, UnknownStatement<String>>> {
+
+
+        public Definition(StatementDefinition publicDefinition) {
+            super(publicDefinition);
+        }
+
+        @Override
+        public String parseArgumentValue(StmtContext<?, ?, ?> ctx, String value) throws SourceException {
+            return value;
+        }
+
+        @Override
+        public UnknownStatement createDeclared(StmtContext<String, UnknownStatement<String>, ?> ctx) {
+            return new UnknownStatementImpl(ctx);
+        }
+
+        @Override
+        public EffectiveStatement<String, UnknownStatement<String>> createEffective(StmtContext<String, UnknownStatement<String>, EffectiveStatement<String, UnknownStatement<String>>> ctx) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Nullable
+    @Override
+    public String getArgument() {
+        return rawArgument();
+    }
+}
index 99ca6c126c5243d4303cb9fc60cb4f11d45f8624..3a62cfaab6272d4f826f35c20797cc36ba465a46 100644 (file)
@@ -17,12 +17,14 @@ import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-
 import javax.annotation.Nullable;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
-
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.antlr.v4.runtime.tree.TerminalNode;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -45,11 +47,6 @@ import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
 
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 public final class Utils {
 
     private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
index 34fc0fccfd95ad8cd8a679dd3c21ac935280f717..87bfe2b3f4f9bb5cbf5cd261cebcfcb7876057db 100644 (file)
@@ -11,6 +11,7 @@ import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour
 import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.sourceLocal;
 import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.treeScoped;
 
+import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
 
 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
@@ -26,6 +27,7 @@ import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
 
 public final class YangInferencePipeline {
@@ -56,17 +58,15 @@ public final class YangInferencePipeline {
             .addSupport(sourceLocal(IncludedModuleContext.class))
             .addSupport(sourceLocal(ImpPrefixToModuleIdentifier.class))
             .addSupport(sourceLocal(BelongsToPrefixToModuleName.class))
-            //.addSupport(global(ImpPrefixToModuleIdentifier.class))
-                    .build();
+            .addSupport(sourceLocal(QNameToStatementDefinition.class))
+            .build();
 
     private static final StatementSupportBundle STMT_DEF_BUNDLE = StatementSupportBundle.
             derivedFrom(LINKAGE_BUNDLE)
             .addSupport(new YinElementStatementImpl.Definition())
             .addSupport(new ArgumentStatementImpl.Definition())
             .addSupport(new ExtensionStatementImpl.Definition())
-            //TODO: implement extension support in SourceSpecificContext
-            // in order to prepare statements for full declaration phase,
-            // when those ones are read.
+            .addSupport(global(ExtensionNamespace.class))
             .build();
 
     private static final StatementSupportBundle FULL_DECL_BUNDLE = StatementSupportBundle.
index 210a837f81576413d58fc05b9bdd7ff3b3762f6c..2b6c97f8a8c8ed8b40e36ea40b9f464a3c201b30 100644 (file)
@@ -1,3 +1,10 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
 import org.antlr.v4.runtime.ANTLRInputStream;
index ee2b10a22209a22dceb8b1a0c103d359a2d8274e..3ffc50c2398d64205c059e86e3f5369d6ce54543 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -19,45 +19,27 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceIm
 import static org.junit.Assert.assertNotNull;
 
 public class YangFileStmtTest {
-        private static final YangStatementSourceImpl YANGFILE = new YangStatementSourceImpl("/semantic-statement-parser/test.yang");
-        private static final YangStatementSourceImpl IMPORTEDYANGFILE = new YangStatementSourceImpl("/semantic-statement-parser/importedtest.yang");
-        private static final YangStatementSourceImpl SIMPLENODES = new YangStatementSourceImpl("/semantic-statement-parser/simple-nodes-semantic.yang");
-        private static final YangStatementSourceImpl FOO = new YangStatementSourceImpl("/semantic-statement-parser/foo.yang");
-        private static final YangStatementSourceImpl FILE1 = new YangStatementSourceImpl("/model/bar.yang");
-        private static final YangStatementSourceImpl FILE2 = new YangStatementSourceImpl("/model/baz.yang");
-        private static final YangStatementSourceImpl FILE3 = new YangStatementSourceImpl("/model/foo.yang");
-        private static final YangStatementSourceImpl FILE4 = new YangStatementSourceImpl("/model/subfoo.yang");
-        private static final YangStatementSourceImpl EXTFILE = new YangStatementSourceImpl("/semantic-statement-parser/ext-typedef.yang");
-        private static final YangStatementSourceImpl EXTUSE = new YangStatementSourceImpl("/semantic-statement-parser/ext-use.yang");
+    //basic statements to parse and write
+    private static final YangStatementSourceImpl YANGFILE = new YangStatementSourceImpl("/semantic-statement-parser/test.yang");
+    private static final YangStatementSourceImpl IMPORTEDYANGFILE = new YangStatementSourceImpl("/semantic-statement-parser/importedtest.yang");
+    private static final YangStatementSourceImpl SIMPLENODES = new YangStatementSourceImpl("/semantic-statement-parser/simple-nodes-semantic.yang");
+    private static final YangStatementSourceImpl FOOBAR = new YangStatementSourceImpl("/semantic-statement-parser/foobar.yang");
+    //extension statement to parse and write
+    private static final YangStatementSourceImpl EXTFILE = new YangStatementSourceImpl("/semantic-statement-parser/ext-typedef.yang");
+    private static final YangStatementSourceImpl EXTUSE = new YangStatementSourceImpl("/semantic-statement-parser/ext-use.yang");
 
-        @Test
-        public void readAndParseYangFileTest1() throws SourceException, ReactorException {
-                CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-                addSources(reactor, YANGFILE, SIMPLENODES, IMPORTEDYANGFILE, FOO);
-                EffectiveModelContext result = reactor.build();
-                assertNotNull(result);
-        }
-
-        // TODO uncomment when Augment in Uses implemented
-//        @Test
-//        public void readAndParseYangFileTest2() throws SourceException, ReactorException {
-//                CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-//                addSources(reactor, FILE1, FILE2, FILE3, FILE4);
-//                EffectiveModelContext result = reactor.build();
-//                assertNotNull(result);
-//        }
-
-        @Test
-        public void readAndParseYangFileTest3() throws SourceException, ReactorException {
-                CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-                addSources(reactor, EXTFILE, EXTUSE);
-                EffectiveModelContext result = reactor.build();
-                assertNotNull(result);
-        }
+    @Test
+    public void readAndParseYangFileTest() throws SourceException, ReactorException {
+        CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor, YANGFILE, SIMPLENODES, IMPORTEDYANGFILE, FOOBAR);
+        addSources(reactor, EXTFILE, EXTUSE);
+        EffectiveModelContext result = reactor.build();
+        assertNotNull(result);
+    }
 
-        private void addSources(CrossSourceStatementReactor.BuildAction reactor, StatementStreamSource... sources) {
-                for (StatementStreamSource source : sources) {
-                        reactor.addSource(source);
-                }
+    private void addSources(CrossSourceStatementReactor.BuildAction reactor, StatementStreamSource... sources) {
+        for (StatementStreamSource source : sources) {
+            reactor.addSource(source);
         }
+    }
 }
\ No newline at end of file
similarity index 87%
rename from yang/yang-parser-impl/src/test/resources/semantic-statement-parser/foo.yang
rename to yang/yang-parser-impl/src/test/resources/semantic-statement-parser/foobar.yang
index 6854e33aac2adcda9e0ab2ca7f20be39d242db6d..6870055629f5c491d390d786c8a7de0b0bcf19d2 100644 (file)
@@ -1,7 +1,7 @@
-module foo {
+module foobar {
     yang-version 1;
-    namespace "urn:opendaylight.foo";
-    prefix "foo";
+    namespace "urn:opendaylight.foobar";
+    prefix "foobar";
 
     revision "2015-07-08" {
     }
index dcc8578ad3838b3b2bd336f0fdbd9308456bd2d5..247aceb56512987dff3cf111b2d31e4a6a1510c0 100644 (file)
@@ -29,7 +29,7 @@ module simple-nodes {
 
 
     anyxml data {
-        config false;
+         config false;
          description "anyxml desc";
          if-feature has-name;
          mandatory true;