Merge "BUG-2352: Remove commons-io from features"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 23 Mar 2015 10:08:25 +0000 (10:08 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 23 Mar 2015 10:08:26 +0000 (10:08 +0000)
55 files changed:
.gitignore
README.md [new file with mode: 0644]
docs/src/main/asciidoc/contributor/introduction.adoc [new file with mode: 0644]
docs/src/main/asciidoc/developer/introduction.adoc [new file with mode: 0644]
pom.xml
yang-validation-tool/pom.xml [new file with mode: 0644]
yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Main.java [new file with mode: 0644]
yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Params.java [new file with mode: 0644]
yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/ParamsUtil.java [new file with mode: 0644]
yang/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifierTest.java [moved from yang/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/test/InstanceIdentifierTest.java with 77% similarity]
yang/yang-data-api/src/main/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifier.java
yang/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifierTest.java [moved from yang/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifierTest.java with 83% similarity]
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/CompositeNodeDataWithSchema.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/ImmutableMapEntryNodeBuilder.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/builder/impl/valid/DataValidationException.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/NormalizedNodeContainerModificationStrategy.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/SchemaAwareApplyOperation.java
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/schema/tree/UnkeyedListModificationStrategy.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ExtensionNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/FeatureNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/GroupingNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/IdentityNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ModuleNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/NamespaceToModule.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SchemaNodeIdentifierNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubmoduleNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/TypeNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CrossSourceStatementReactor.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/EffectiveModelContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/RootStatementContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementIdentifier.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SubstatementContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AbstractRootStatement.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ContainerStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportedModuleContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementSupport.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/NamespaceStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/PrefixStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UsesStatementImpl.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/util/YangModelDependencyInfoTest.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/ImportResolutionTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/TestStatementSource.java [new file with mode: 0644]

index ca58b83dc4217945e770f33f8f0de62cc014cb83..1900c9af87502f01cd02094cc5dceb21b10b5d98 100644 (file)
@@ -15,3 +15,4 @@ bin
 xtend-gen
 target
 .DS_Store
+META-INF
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..81ffe78
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+# YANG Tools
+
+YANG Tools is to develop necessary tooling and libraries to provide Java runtime
+and support for [YANG modeling language][RFC6020], data structures modeled by YANG and their
+serialization and deserialization as defined in IETF drafts and standards.
+
+## Current Features
+
+* parsing of [YANG sources][RFC6020] and semantic inference of relationship across YANG models as defined in [RFC6020]
+* representation of YANG-modeled data in Java
+  * **DOM-like APIs** - DOM-like tree model, which uses conceptual meta-model
+  * **Java Bindings** - Concrete data model generated from YANG models
+* serialization / deserialization of YANG-modeled data driven by YANG models
+  * XML - as defined in [RFC6020]
+  * JSON - as defined in [draft-lhotka-netmod-yang-json-01]
+* Integration of YANG model parsing into Maven build lifecycle and
+  support for third-party generators processing  YANG models.
+
+
+[RFC6020]:https://tools.ietf.org/html/rfc6020
+[draft-lhotka-netmod-yang-json-01]:https://tools.ietf.org/html/draft-lhotka-netmod-yang-json-01
diff --git a/docs/src/main/asciidoc/contributor/introduction.adoc b/docs/src/main/asciidoc/contributor/introduction.adoc
new file mode 100644 (file)
index 0000000..6378e84
--- /dev/null
@@ -0,0 +1,13 @@
+= Contributor Guide
+
+== Architecture
+
+== Design
+
+=== Design considerations
+
+=== Design decisions
+
+== Common concepts
+
+== Recomendations
diff --git a/docs/src/main/asciidoc/developer/introduction.adoc b/docs/src/main/asciidoc/developer/introduction.adoc
new file mode 100644 (file)
index 0000000..8c0c0b0
--- /dev/null
@@ -0,0 +1,35 @@
+= Developer Guide
+
+== Overview
+
+=== Architecture
+
+=== Concepts
+
+=== Components
+
+==== YANG Model API
+
+==== YANG Parser
+
+==== YANG Data API
+
+==== YANG Data Codecs
+
+==== YANG Maven Plugin
+
+== How to / Tutorials
+
+=== Working with YANG Model
+
+=== Working with YANG Data
+
+=== Serialization / deserialization of YANG Data
+
+=== Introducing schema source repositories
+
+=== Writing YANG driven generators
+
+=== Introducing specific extension support for YANG parser
+
+=== Diagnostics
diff --git a/pom.xml b/pom.xml
index faa849b89020ac81451ed49dbcd478d922030906..e64f5c3bfe9bf6c56bfbea7efc8f9b2105c8011c 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
         <module>restconf</module>
         <module>websocket</module>
         <module>yang</module>
+        <module>yang-validation-tool</module>
       <!-- module>third-party</module -->
     </modules>
 
diff --git a/yang-validation-tool/pom.xml b/yang-validation-tool/pom.xml
new file mode 100644 (file)
index 0000000..8dbaa1d
--- /dev/null
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yangtools-aggregator</artifactId>
+        <version>0.7.0-SNAPSHOT</version>
+    </parent>
+    <artifactId>yang-validation-tool</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.sourceforge.argparse4j</groupId>
+            <artifactId>argparse4j</artifactId>
+            <version>0.4.3</version>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-yang-types-20130715</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.yangtools.model</groupId>
+            <artifactId>ietf-inet-types</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <configuration></configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <!-- TODO investigate why jar fails without this
+                                filter -->
+                            <filters>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/*.SF</exclude>
+                                        <exclude>META-INF/*.DSA</exclude>
+                                        <exclude>META-INF/*.RSA</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <transformers>
+                                <transformer
+                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+                                    <mainClass>org.opendaylight.yangtools.yang.validation.tool.Main</mainClass>
+                                </transformer>
+                            </transformers>
+                            <shadedArtifactAttached>true</shadedArtifactAttached>
+                            <shadedClassifierName>executable</shadedClassifierName>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Main.java b/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Main.java
new file mode 100644 (file)
index 0000000..b1c94b0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.validation.tool;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+public final class Main {
+    private Main() {
+
+    }
+
+    public static void main(final String[] args) throws URISyntaxException {
+        final Params params = ParamsUtil.parseArgs(args, Params.getParser());
+        final YangParserImpl yangParser = new YangParserImpl();
+
+        if (params.isValid()) {
+            final File[] yangModels = params.getYangSourceDir().listFiles();
+
+            try {
+                yangParser.parseFiles(Arrays.asList(yangModels));
+            } catch (Exception e) {
+
+            }
+        }
+    }
+}
diff --git a/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Params.java b/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/Params.java
new file mode 100644 (file)
index 0000000..6cd01cd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.validation.tool;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.annotation.Arg;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+
+final class Params {
+
+    @Arg(dest = "yang-source-dir")
+    private File yangSourceDir;
+
+    static ArgumentParser getParser() throws URISyntaxException {
+        final ArgumentParser parser = ArgumentParsers.newArgumentParser("jar_file_name");
+        parser.description("Validation Tool for Yang Models")
+            .formatUsage();
+
+        parser.addArgumentGroup("Required arguments")
+            .addArgument("--yang-source-dir")
+            .type(File.class)
+            .required(true)
+            .help("directory containing yang models which will be parsed")
+            .dest("yang-source-dir")
+            .metavar("");
+
+        return parser;
+    }
+
+    public boolean isValid() {
+        if (yangSourceDir == null) {
+            return false;
+        }
+        if (!yangSourceDir.exists()) {
+            System.err.println("Yang source directory has to exist");
+            return false;
+        }
+        if (!yangSourceDir.canRead()) {
+            System.err.println("Yang source directory has to be readable");
+            return false;
+        }
+        if (yangSourceDir.list().length == 0) {
+            System.err.printf("Yang source directory '%s' does't contain any model%n", yangSourceDir.getPath());
+            return false;
+        }
+
+        return true;
+    }
+
+    public File getYangSourceDir() {
+        return yangSourceDir;
+    }
+}
diff --git a/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/ParamsUtil.java b/yang-validation-tool/src/main/java/org/opendaylight/yangtools/yang/validation/tool/ParamsUtil.java
new file mode 100644 (file)
index 0000000..bfdfc3c
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.validation.tool;
+
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+
+final class ParamsUtil {
+    private ParamsUtil() {
+
+    }
+
+    public static Params parseArgs(final String[] args, final ArgumentParser parser) {
+        final Params params = new Params();
+        try {
+            parser.parseArgs(args, params);
+            return params;
+        } catch (final ArgumentParserException e) {
+            parser.handleError(e);
+        }
+        System.exit(1);
+        return null;
+    }
+}
similarity index 77%
rename from yang/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/test/InstanceIdentifierTest.java
rename to yang/yang-binding/src/test/java/org/opendaylight/yangtools/yang/binding/InstanceIdentifierTest.java
index 34e3911516cdb5ea35494ab5dfbd9ad304019f85..97ee4feded7c19fd129672f89de43c02e74c89f7 100644 (file)
@@ -5,14 +5,15 @@
  * 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.binding.test;
+package org.opendaylight.yangtools.yang.binding;
 
 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 org.junit.Test;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.test.mock.FooChild;
 import org.opendaylight.yangtools.yang.binding.test.mock.InstantiatedFoo;
@@ -69,6 +70,9 @@ public class InstanceIdentifierTest {
 
         assertFalse(nodeOne.contains(nodes));
         assertTrue(nodes.contains(nodeOne));
+
+        assertTrue(nodes.containsWildcarded(nodeOne));
+        assertFalse(nodeOne.containsWildcarded(nodes));
     }
 
     @Test
@@ -111,9 +115,33 @@ public class InstanceIdentifierTest {
 
     }
 
-
     void childOfTest() {
         InstanceIdentifier.builder(Nodes.class).child(InstantiatedFoo.class).child(FooChild.class);
     }
 
+    @Test
+    public void basicTests() {
+        InstanceIdentifier<DataObject> instanceIdentifier1 = InstanceIdentifier.create(DataObject.class);
+        InstanceIdentifier<DataObject> instanceIdentifier2 = InstanceIdentifier.create(DataObject.class);
+        Object object = new Object();
+
+        assertTrue(instanceIdentifier1.equals(instanceIdentifier1));
+        assertFalse(instanceIdentifier1.equals(null));
+        assertFalse(instanceIdentifier1.equals(object));
+        assertTrue(instanceIdentifier1.equals(instanceIdentifier2));
+
+        assertNotNull(instanceIdentifier1.hashCode());
+
+        assertNotNull(instanceIdentifier1.toString());
+    }
+
+    @Test
+    public void firstIdentifierOfTest() {
+        InstanceIdentifier<Node> instanceIdentifier = InstanceIdentifier.builder(Nodes.class).child(Node.class,new NodeKey(10)).build();
+
+        InstanceIdentifier<Nodes> nodesIdentifier = instanceIdentifier.firstIdentifierOf(Nodes.class);
+        assertNotNull(nodesIdentifier);
+        InstanceIdentifier<DataObject> dataObjectIdentifier = instanceIdentifier.firstIdentifierOf(DataObject.class);
+        assertNull(dataObjectIdentifier);
+    }
 }
index 00a041499062635a56ca2d6640f89a76c4df1ec1..62c876b530495e8cdf151e4585f45a7216a4a577 100644 (file)
@@ -16,6 +16,7 @@ import com.google.common.collect.Lists;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
@@ -463,6 +464,7 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
          *
          * @return {@link YangInstanceIdentifier}
          */
+        @Override
         YangInstanceIdentifier build();
 
         /*
@@ -736,6 +738,7 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
             return this;
         }
 
+        @Override
         @Deprecated
         public YangInstanceIdentifier toInstance() {
             return build();
@@ -806,6 +809,10 @@ public final class YangInstanceIdentifier implements Path<YangInstanceIdentifier
         }
     }
 
+    private Object readResolve() throws ObjectStreamException {
+        return legacyPath.isEmpty() ? EMPTY : this;
+    }
+
     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
         /*
          * This may look strange, but what we are doing here is side-stepping the fact
similarity index 83%
rename from yang/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/InstanceIdentifierTest.java
rename to yang/yang-data-api/src/test/java/org/opendaylight/yangtools/yang/data/api/YangInstanceIdentifierTest.java
index cc34224da23a7cf8b6e40856e37c89c6651dd0c9..95363b0ce9dba58b4de246cb550119947c91fae7 100644 (file)
@@ -9,7 +9,9 @@
 package org.opendaylight.yangtools.yang.data.api;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
@@ -36,7 +38,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgum
  *
  * @author Thomas Pantelis
  */
-public class InstanceIdentifierTest {
+public class YangInstanceIdentifierTest {
 
     static QName nodeName1 = QName.create("test", "2014-5-28", "node1");
     static QName nodeName2 = QName.create("test", "2014-5-28", "node2");
@@ -46,22 +48,47 @@ public class InstanceIdentifierTest {
     static QName key2 = QName.create("test", "2014-5-28", "key2");
     static QName key3 = QName.create("test", "2014-5-28", "key3");
 
+    @Test
+    public void testGetLastPathArgument() {
+       YangInstanceIdentifier id1 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
+       assertEquals( "getLastPathArgument", new NodeIdentifier(nodeName2), id1.getLastPathArgument());
+       YangInstanceIdentifier id2 = YangInstanceIdentifier.create();
+       assertNull( id2.getLastPathArgument() );
+    }
+
     @Test
     public void testHashCodeEquals() {
 
+        YangInstanceIdentifier id1 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
+        YangInstanceIdentifier id2 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
+
+        assertEquals( "hashCode", id1.hashCode(), id2.hashCode() );
+    }
+
+    @Test
+    public void testEquals() {
+
         YangInstanceIdentifier id1 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
         YangInstanceIdentifier id2 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
         YangInstanceIdentifier id3 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName2), new NodeIdentifier(nodeName1));
         YangInstanceIdentifier id4 = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1));
 
-        assertEquals( "hashCode", id1.hashCode(), id2.hashCode() );
+        assertEquals( "equals", false, id1.equals( null ) );
+        assertEquals( "equals", true, id1.equals( id1 ) );
         assertEquals( "equals", true, id1.equals( id2 ) );
-
         assertEquals( "equals", false, id1.equals( id3 ) );
         assertEquals( "equals", false, id1.equals( id4 ) );
         assertEquals( "equals", false, id1.equals( new Object() ) );
     }
 
+    @Test
+    public void testToString() {
+       YangInstanceIdentifier id = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2));
+
+       assertNotNull( id.toString() );
+
+    }
+
     @Test
     public void testNode() {
 
@@ -98,7 +125,6 @@ public class InstanceIdentifierTest {
                 Lists.newArrayList(new NodeIdentifier(nodeName1), new NodeIdentifier(nodeName2)));
 
         Optional<YangInstanceIdentifier> relative = id1.relativeTo( id2 );
-
         assertEquals( "isPresent", true, relative.isPresent() );
 
         Iterable<PathArgument> p = relative.get().getPathArguments();
@@ -114,6 +140,13 @@ public class InstanceIdentifierTest {
         assertEquals( "isPresent", false, relative.isPresent() );
     }
 
+    @Test(expected=IllegalArgumentException.class)
+    public void testContainsNull() {
+        final YangInstanceIdentifier id = YangInstanceIdentifier.create(new NodeIdentifier(nodeName1));
+
+        id.contains( null );
+    }
+
     @Test
     public void testContains() {
 
@@ -208,6 +241,7 @@ public class InstanceIdentifierTest {
         assertEquals( "equals", false, node1.equals( new Object() ) );
 
         assertNotNull( node1.toString() ); // for code coverage
+        assertNotNull( node1.toRelativeString(node2) );
 
         NodeIdentifierWithPredicates node3 = new NodeIdentifierWithPredicates( nodeName1,
                 ImmutableMap.<QName, Object>builder().put( key1, 10 ).put( key2, 20 ).build() );
@@ -254,6 +288,7 @@ public class InstanceIdentifierTest {
         assertEquals( "equals", false, node1.equals( new Object() ) );
 
         assertNotNull( node1.toString() ); // for code coverage
+        assertNotNull( node1.toRelativeString(node2) );
 
         NodeWithValue node3 = new NodeWithValue( nodeName1, new byte[]{1,2} );
         NodeWithValue node4 = new NodeWithValue( nodeName1, new byte[]{1,2} );
@@ -270,38 +305,55 @@ public class InstanceIdentifierTest {
 
         NodeIdentifier node1 = new NodeIdentifier( nodeName1 );
         assertEquals( "getNodeType", nodeName1, node1.getNodeType() );
-
         NodeIdentifier node2 = new NodeIdentifier( nodeName1 );
+        AugmentationIdentifier node3 = new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName2 ) );
 
         assertEquals( "hashCode", node1.hashCode(), node2.hashCode() );
-        assertEquals( "equals", true, node1.equals( node2 ) );
         assertEquals( "compareTo", 0, node1.compareTo( node2 ) );
+        assertEquals( "compareTo", true, node1.compareTo( new NodeIdentifier( nodeName3 ) ) != 0 );
 
+        assertEquals( "equals", false, node1.equals( null ) );
+        assertEquals( "equals", false, node1.equals( node3 ) );
+        assertEquals( "equals", true, node1.equals( node1 ) );
+        assertEquals( "equals", true, node1.equals( node2 ) );
         assertEquals( "equals", false, node1.equals( new NodeIdentifier( nodeName3 ) ) );
-        assertEquals( "compareTo", true, node1.compareTo( new NodeIdentifier( nodeName3 ) ) != 0 );
         assertEquals( "equals", false, node1.equals( new Object() ) );
 
         assertNotNull( node1.toString() ); // for code coverage
     }
 
+    @Test(expected=UnsupportedOperationException.class)
+    public void testAugmentationIdentifierNodeType() {
+        AugmentationIdentifier node1 = new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName2 ) );
+        node1.getNodeType();
+    }
+
     @Test
     public void testAugmentationIdentifier() {
 
         AugmentationIdentifier node1 = new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName2 ) );
         assertEquals( "getPossibleChildNames", Sets.newHashSet( nodeName1, nodeName2 ), node1.getPossibleChildNames() );
-
         AugmentationIdentifier node2 = new AugmentationIdentifier( Sets.newHashSet( nodeName2, nodeName1 ) );
+        AugmentationIdentifier node3 = new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName3 ) );
+        AugmentationIdentifier node4 = new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName2, nodeName3 ) );
+        NodeIdentifier node5 = new NodeIdentifier( nodeName3 );
 
         assertEquals( "hashCode", node1.hashCode(), node2.hashCode() );
-        assertEquals( "equals", true, node1.equals( node2 ) );
 
-        assertEquals( "equals", false,
-                node1.equals( new AugmentationIdentifier( Sets.newHashSet( nodeName1, nodeName3 ) ) ) );
-        assertEquals( "equals", false,
-                node1.equals( new AugmentationIdentifier( Sets.newHashSet( nodeName1 ) ) ) );
+        assertEquals( "equals", true, node1.equals( node1 ) );
+        assertEquals( "equals", true, node1.equals( node2 ) );
+        assertEquals( "equals", false, node1.equals( node3 ) );
+        assertEquals( "equals", false, node1.equals( new AugmentationIdentifier( Sets.newHashSet( nodeName1 ) ) ) );
         assertEquals( "equals", false, node1.equals( new Object() ) );
 
+        assertEquals( "compareTo", -1, node1.compareTo( node5 ) );
+        assertNotEquals( "compareTo", -1, node1.compareTo( node2 ) );
+        assertEquals( "compareTo", 0, node1.compareTo( node2 ) );
+        assertEquals( "compareTo", 1, node1.compareTo( node4 ) );
+        assertEquals( "compareTo", -1, node4.compareTo( node1 ) );
+
         assertNotNull( node1.toString() ); // for code coverage
+        assertNotNull( node1.toRelativeString(node5));
     }
 
     @Test
index 70612910d65ae098371ba9635c1004546a410be2..d34712e4f12909e8dbecdebd87cdc76989d9ac73 100644 (file)
@@ -96,7 +96,7 @@ class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
         CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
         if (caseNodeDataWithSchema == null) {
             ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
-            addChild(choiceNodeDataWithSchema);
+            childNodes.add(choiceNodeDataWithSchema);
             caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
         }
 
index 12f26a39bed8237aa6d6b133232073b7dea26992..445cf5519199ac0b896b1b8a80d5b7553928b481 100644 (file)
@@ -10,17 +10,22 @@ package org.opendaylight.yangtools.yang.data.impl.schema.builder.impl;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
 import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ImmutableMapEntryNodeBuilder extends AbstractImmutableDataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> {
-
+    private static final Logger LOG = LoggerFactory.getLogger(ImmutableMapEntryNodeBuilder.class);
     protected final Map<QName, YangInstanceIdentifier.PathArgument> childrenQNamesToPaths;
 
     protected ImmutableMapEntryNodeBuilder() {
@@ -91,15 +96,20 @@ public class ImmutableMapEntryNodeBuilder extends AbstractImmutableDataContainer
 
     @Override
     public MapEntryNode build() {
-        checkKeys();
-        return new ImmutableMapEntryNode(getNodeIdentifier(), buildValue(), getAttributes());
-    }
-
-    private void checkKeys() {
-        for (final QName keyQName : getNodeIdentifier().getKeyValues().keySet()) {
-            DataContainerChild<?, ?> childNode = getChild(childrenQNamesToPaths.get(keyQName));
-            DataValidationException.checkListKey(childNode, getNodeIdentifier().getKeyValues(), keyQName, getNodeIdentifier());
+        for (final Entry<QName, Object> key : getNodeIdentifier().getKeyValues().entrySet()) {
+            final DataContainerChild<?, ?> childNode = getChild(childrenQNamesToPaths.get(key.getValue()));
+
+            // We have enough information to fill-in missing leaf nodes, so let's do that
+            if (childNode == null) {
+                LeafNode<Object> leaf = ImmutableNodes.leafNode(key.getKey(), key.getValue());
+                LOG.debug("Adding leaf {} implied by key {}", leaf, key);
+                withChild(leaf);
+            } else {
+                DataValidationException.checkListKey(getNodeIdentifier(), key.getKey(), key.getValue(), childNode.getValue());
+            }
         }
+
+        return new ImmutableMapEntryNode(getNodeIdentifier(), buildValue(), getAttributes());
     }
 
     private static final class ImmutableMapEntryNode extends AbstractImmutableDataContainerAttrNode<YangInstanceIdentifier.NodeIdentifierWithPredicates> implements MapEntryNode {
index e370c131d73f1f87683f311263c65496b28c29ec..a37d6c34e2fd1653f1c24f8ae838f344f5a74082 100644 (file)
@@ -51,17 +51,21 @@ public class DataValidationException extends RuntimeException {
         }
     }
 
+    public static void checkListKey(final NodeIdentifierWithPredicates nodeId, final QName keyQName, final Object expected, final Object actual) {
+        // Objects.equals() does not deal with arrays, but is faster
+        if (!Objects.equals(expected, actual) && !Objects.deepEquals(expected, actual)) {
+            throw new IllegalListKeyException(keyQName, nodeId, actual, expected);
+        }
+    }
+
     public static void checkListKey(final DataContainerChild<?, ?> childNode, final Map<QName, Object> keyValues, final QName keyQName,
             final NodeIdentifierWithPredicates nodeId) {
         checkListKey(childNode, keyQName, nodeId);
 
-        final Object expected = nodeId.getKeyValues().get(keyQName);
+        final Object expected = keyValues.get(keyQName);
         final Object actual = childNode.getValue();
 
-        // Objects.equals() does not deal with arrays, but is faster
-        if (!Objects.equals(expected, actual) && !Objects.deepEquals(expected, actual)) {
-            throw new IllegalListKeyException(keyQName, nodeId, actual, expected);
-        }
+        checkListKey(nodeId, keyQName, expected, actual);
     }
 
     public static void checkListKey(final DataContainerChild<?, ?> childNode, final QName keyQName, final NodeIdentifierWithPredicates nodeId) {
index 5b924d78d5075d6a38013846ee078067ec8f4c8f..053d0b02274b5108e7820cfe70c9562e353485e7 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 import static com.google.common.base.Preconditions.checkArgument;
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
+import java.util.Collection;
 import java.util.Map;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
@@ -79,7 +79,7 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
         final NormalizedNode<?, ?> newValue = modification.getWrittenValue();
         final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, version);
 
-        if (Iterables.isEmpty(modification.getChildren())) {
+        if (modification.getChildren().isEmpty()) {
             return newValueMeta;
         }
 
@@ -158,8 +158,8 @@ abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareAp
          * The user has issued an empty merge operation. In this case we do not perform
          * a data tree mutation, do not pass GO, and do not collect useless garbage.
          */
-        final Iterable<ModifiedNode> children = modification.getChildren();
-        if (Iterables.isEmpty(children)) {
+        final Collection<ModifiedNode> children = modification.getChildren();
+        if (children.isEmpty()) {
             newMeta.setData(currentMeta.getData());
             return newMeta.seal();
         }
index aaee9c30d8fb96c27c9ca216d87a09da2861fe16..f024a9d830f677c048e610e32e233b8c121cdc15 100644 (file)
@@ -52,21 +52,14 @@ abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
 
     public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
             final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
-        AugmentationSchema augSchema = null;
-
-        allAugments:
-            for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
-                for (DataSchemaNode child : potential.getChildNodes()) {
-                    if (identifier.getPossibleChildNames().contains(child.getQName())) {
-                        augSchema = potential;
-                        break allAugments;
-                    }
+        for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
+            for (DataSchemaNode child : potential.getChildNodes()) {
+                if (identifier.getPossibleChildNames().contains(child.getQName())) {
+                    return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(potential, resolvedTree);
                 }
             }
-
-        if (augSchema != null) {
-            return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(augSchema, resolvedTree);
         }
+
         return null;
     }
 
index ace568fd21924a3fc16d3f604d5dbc8d4f9373be..23140b86a68cb86b597dabf44ce985fdb78b2e58 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.yang.data.impl.schema.tree;
 
 import com.google.common.base.Optional;
-import com.google.common.collect.Iterables;
 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.PathArgument;
@@ -54,7 +53,7 @@ final class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
         final NormalizedNode<?, ?> newValue = modification.getWrittenValue();
         final TreeNode newValueMeta = TreeNodeFactory.createTreeNode(newValue, version);
 
-        if (Iterables.isEmpty(modification.getChildren())) {
+        if (modification.getChildren().isEmpty()) {
             return newValueMeta;
         }
 
@@ -130,4 +129,4 @@ final class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
             final Optional<TreeNode> current) throws IncorrectDataStructureException {
         throw new IncorrectDataStructureException(path, "Subtree modification is not allowed.");
     }
-}
\ No newline at end of file
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ExtensionNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ExtensionNamespace.java
new file mode 100644 (file)
index 0000000..c7c8bb2
--- /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.parser.spi;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+/**
+ * Extension namespace
+ *
+ * All extension names defined in a module and its submodules share
+ * the same extension identifier namespace.
+ *
+ */
+public interface ExtensionNamespace extends StatementNamespace<QName, ExtensionStatement, EffectiveStatement<QName, ExtensionStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/FeatureNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/FeatureNamespace.java
new file mode 100644 (file)
index 0000000..781c62f
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.FeatureStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+/**
+ *
+ * Feature namespace
+ *
+ * All feature names defined in a module and its submodules share the
+ * same feature identifier namespace.
+ *
+ */
+public interface FeatureNamespace extends StatementNamespace<QName, FeatureStatement, EffectiveStatement<QName,FeatureStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/GroupingNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/GroupingNamespace.java
new file mode 100644 (file)
index 0000000..ade35f1
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+/**
+ * Grouping namespace
+ *
+ * All grouping names defined within a parent node or at the top level of the
+ * module or its submodules share the same grouping identifier namespace. This
+ * namespace is scoped to all descendant nodes of the parent node or module.
+ * This means that any descendant node may use that grouping, and it MUST NOT
+ * define a grouping with the same name.
+ */
+public interface GroupingNamespace extends StatementNamespace.TreeScoped<QName, GroupingStatement,EffectiveStatement<QName,GroupingStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/IdentityNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/IdentityNamespace.java
new file mode 100644 (file)
index 0000000..fc0e378
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
+
+/**
+ *
+ * Identity namespace
+ *
+ * All identity names defined in a module and its submodules share the same
+ * identity identifier namespace.
+ *
+ */
+public interface IdentityNamespace extends IdentifierNamespace<QName, IdentityStatement> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ModuleNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/ModuleNamespace.java
new file mode 100644 (file)
index 0000000..16add17
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+public interface ModuleNamespace extends StatementNamespace<ModuleIdentifier, ModuleStatement, EffectiveStatement<String, ModuleStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/NamespaceToModule.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/NamespaceToModule.java
new file mode 100644 (file)
index 0000000..f5b00f7
--- /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.parser.spi;
+
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
+
+public interface NamespaceToModule extends StatementNamespace<QNameModule, ModuleStatement, EffectiveStatement<String, ModuleStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SchemaNodeIdentifierNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SchemaNodeIdentifierNamespace.java
new file mode 100644 (file)
index 0000000..6b482dd
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+/**
+ * Schema node identifier namespace
+ *
+ * All leafs, leaf-lists, lists, containers, choices, rpcs, notifications, and
+ * anyxmls defined (directly or through a uses statement) within a parent node
+ * or at the top level of the module or its submodules share the same identifier
+ * namespace. This namespace is scoped to the parent node or module, unless the
+ * parent node is a case node. In that case, the namespace is scoped to the
+ * closest ancestor node that is not a case or choice node.
+ */
+public interface SchemaNodeIdentifierNamespace extends StatementNamespace.TreeBased<SchemaNodeIdentifier, DeclaredStatement<?>,EffectiveStatement<?,DeclaredStatement<?>>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubmoduleNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/SubmoduleNamespace.java
new file mode 100644 (file)
index 0000000..24584a1
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+public interface SubmoduleNamespace extends StatementNamespace<ModuleIdentifier, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/TypeNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/TypeNamespace.java
new file mode 100644 (file)
index 0000000..4e061d6
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+
+/**
+ * Derived types namespace
+ *
+ * All derived type names defined within a parent node or at the top level of
+ * the module or its submodules share the same type identifier namespace. This
+ * namespace is scoped to all descendant nodes of the parent node or module.
+ * This means that any descendant node may use that typedef, and it MUST NOT
+ * define a typedef with the same name.
+ *
+ */
+public interface TypeNamespace extends StatementNamespace.TreeScoped<QName, TypedefStatement, EffectiveStatement<QName,TypedefStatement>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java
new file mode 100644 (file)
index 0000000..b538022
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import javax.annotation.Nonnull;
+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.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.SourceSpecificContext.PhaseCompletionProgress;
+
+class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBehaviour.Registry {
+
+    private static final List<ModelProcessingPhase> PHASE_EXECUTION_ORDER = ImmutableList.<ModelProcessingPhase>builder()
+            .add(ModelProcessingPhase.SourceLinkage)
+            .add(ModelProcessingPhase.StatementDefinition)
+            .add(ModelProcessingPhase.FullDeclaration)
+            .add(ModelProcessingPhase.EffectiveModel)
+            .build();
+
+    private final Map<QName,StatementDefinitionContext<?,?,?>> definitions = new HashMap<>();
+    private final Map<Class<?>,NamespaceBehaviourWithListeners<?, ?, ?>> namespaces = new HashMap<>();
+
+
+    private final Map<ModelProcessingPhase,StatementSupportBundle> supports;
+    private final Set<SourceSpecificContext> sources = new HashSet<>();
+
+    private ModelProcessingPhase currentPhase;
+    private ModelProcessingPhase finishedPhase;
+
+    public BuildGlobalContext(Map<ModelProcessingPhase, StatementSupportBundle> supports) {
+        super();
+        this.supports = supports;
+    }
+
+    public void addSource(@Nonnull StatementStreamSource source) {
+        sources.add(new SourceSpecificContext(this,source));
+    }
+
+    @Override
+    public StorageNodeType getStorageNodeType() {
+        return StorageNodeType.Global;
+    }
+
+    @Override
+    public NamespaceStorageNode getParentNamespaceStorage() {
+        return null;
+    }
+
+    @Override
+    public NamespaceBehaviour.Registry getBehaviourRegistry() {
+        return this;
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getNamespaceBehaviour(Class<N> type) {
+        NamespaceBehaviourWithListeners<?, ?, ?> potential = namespaces.get(type);
+        if (potential == null) {
+            NamespaceBehaviour<K, V, N> potentialRaw = supports.get(currentPhase).getNamespaceBehaviour(type);
+            if(potentialRaw != null) {
+                potential = new NamespaceBehaviourWithListeners<>(potentialRaw);
+                namespaces.put(type, potential);
+            }
+        }
+        if (potential != null) {
+            Preconditions.checkState(type.equals(potential.getIdentifier()));
+
+            /*
+             * Safe cast, previous checkState checks equivalence of key from
+             * which type argument are derived
+             */
+            @SuppressWarnings("unchecked")
+            NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K, V, N>) potential;
+            return casted;
+        }
+        throw new NamespaceNotAvailableException("Namespace " + type + "is not available in phase " + currentPhase);
+    }
+
+    public StatementDefinitionContext<?, ?, ?> getStatementDefinition(QName name) {
+        StatementDefinitionContext<?, ?, ?> potential = definitions.get(name);
+        if(potential == null) {
+            StatementSupport<?, ?, ?> potentialRaw = supports.get(currentPhase).getStatementDefinition(name);
+            if(potentialRaw != null) {
+                potential = new StatementDefinitionContext<>(potentialRaw);
+                definitions.put(name, potential);
+            }
+        }
+        return potential;
+    }
+
+    public EffectiveModelContext build() throws SourceException, ReactorException {
+        for(ModelProcessingPhase phase : PHASE_EXECUTION_ORDER) {
+            startPhase(phase);
+            loadPhaseStatements();
+            completePhaseActions();
+            endPhase(phase);
+        }
+        return transform();
+    }
+
+    private EffectiveModelContext transform() {
+        Preconditions.checkState(finishedPhase == ModelProcessingPhase.EffectiveModel);
+        List<DeclaredStatement<?>> rootStatements = new ArrayList<>();
+        for(SourceSpecificContext source : sources) {
+            DeclaredStatement<?> root = source.getRoot().buildDeclared();
+            rootStatements.add(root);
+        }
+        return new EffectiveModelContext(rootStatements);
+    }
+
+    private void startPhase(ModelProcessingPhase phase) {
+        Preconditions.checkState(Objects.equals(finishedPhase, phase.getPreviousPhase()));
+        for(SourceSpecificContext source : sources) {
+            source.startPhase(phase);
+        }
+        currentPhase = phase;
+    }
+
+    private  void loadPhaseStatements() throws SourceException {
+        Preconditions.checkState(currentPhase != null);
+        for(SourceSpecificContext source : sources) {
+            source.loadStatements();
+        }
+    }
+
+    private  void completePhaseActions() throws ReactorException {
+        Preconditions.checkState(currentPhase != null);
+        ArrayList<SourceSpecificContext> sourcesToProgress = Lists.newArrayList(sources);
+        try {
+            boolean progressing = true;
+            while(progressing) {
+                // We reset progressing to false.
+                progressing = false;
+                Iterator<SourceSpecificContext> currentSource = sourcesToProgress.iterator();
+                while(currentSource.hasNext()) {
+                    PhaseCompletionProgress sourceProgress = currentSource.next().tryToCompletePhase(currentPhase);
+                    switch (sourceProgress) {
+                        case FINISHED:
+                            currentSource.remove();
+                        case PROGRESS:
+                            progressing = true;
+                        case NO_PROGRESS:
+                            // Noop;
+                    }
+                }
+            }
+        } catch (SourceException e) {
+            throw Throwables.propagate(e);
+        }
+        if(!sourcesToProgress.isEmpty()) {
+            SomeModifiersUnresolvedException buildFailure = new SomeModifiersUnresolvedException(currentPhase);
+                for(SourceSpecificContext failedSource : sourcesToProgress) {
+                    SourceException sourceEx = failedSource.failModifiers(currentPhase);
+                    buildFailure.addSuppressed(sourceEx);
+                }
+                throw buildFailure;
+        }
+    }
+
+    private  void endPhase(ModelProcessingPhase phase) {
+        Preconditions.checkState(currentPhase == phase);
+        finishedPhase = currentPhase;
+    }
+
+    public Set<SourceSpecificContext> getSources() {
+        return sources;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CrossSourceStatementReactor.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CrossSourceStatementReactor.java
new file mode 100644 (file)
index 0000000..819dfff
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.reactor;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.EnumMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+
+public class CrossSourceStatementReactor {
+
+    private final Map<ModelProcessingPhase,StatementSupportBundle> supportedTerminology;
+
+    CrossSourceStatementReactor(Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology) {
+        this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
+    }
+
+    public static final Builder builder() {
+        return new Builder();
+    }
+
+    public final BuildAction newBuild() {
+        return new BuildAction();
+    }
+
+    public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor>{
+
+        final Map<ModelProcessingPhase,StatementSupportBundle> bundles = new EnumMap<>(ModelProcessingPhase.class);
+
+        public Builder setBundle(ModelProcessingPhase phase,StatementSupportBundle bundle) {
+            bundles.put(phase, bundle);
+            return this;
+        }
+
+        @Override
+        public CrossSourceStatementReactor build() {
+            return new CrossSourceStatementReactor(bundles);
+        }
+
+    }
+
+    public class BuildAction {
+
+        private final BuildGlobalContext context;
+
+        public BuildAction() {
+            this.context = new BuildGlobalContext(supportedTerminology);
+        }
+
+        public void addSource(StatementStreamSource source) {
+            context.addSource(source);
+        }
+
+        public EffectiveModelContext build() throws SourceException, ReactorException {
+            return context.build();
+        }
+
+
+
+    }
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/EffectiveModelContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/EffectiveModelContext.java
new file mode 100644 (file)
index 0000000..0b1e823
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.reactor;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+
+public class EffectiveModelContext implements Immutable {
+
+    private final ImmutableList<DeclaredStatement<?>> rootStatements;
+
+    public EffectiveModelContext(List<DeclaredStatement<?>> rootStatements) {
+        this.rootStatements = ImmutableList.copyOf(rootStatements);
+    }
+
+    public ImmutableList<DeclaredStatement<?>> getRootStatements() {
+        return rootStatements;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java
new file mode 100644 (file)
index 0000000..fba7bb9
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * 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.reactor;
+
+import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.EffectiveModel;
+import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.FullDeclaration;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextMutation;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnNamespaceItemAdded;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnPhaseFinished;
+
+class ModifierImpl implements ModelActionBuilder {
+
+    private final ModelProcessingPhase phase;
+    private final Set<AbstractPrerequisite<?>> unsatisfied = new HashSet<>();
+    private final Set<AbstractPrerequisite<?>> mutations = new HashSet<>();
+
+    private InferenceAction action;
+    private boolean actionApplied = false;
+
+    ModifierImpl(ModelProcessingPhase phase) {
+        this.phase = Preconditions.checkNotNull(phase);
+    }
+
+    private <D> AbstractPrerequisite<D> addReq(AbstractPrerequisite<D> prereq) {
+        unsatisfied.add(prereq);
+        return prereq;
+    }
+
+    private <T> AbstractPrerequisite<T> addMutation(AbstractPrerequisite<T> mutation) {
+        mutations.add(mutation);
+        return mutation;
+    }
+
+
+
+    private void checkNotRegistered() {
+        Preconditions.checkState(action == null, "Action was already registered.");
+    }
+
+    private IllegalStateException shouldNotHappenProbablyBug(SourceException e) {
+        return new IllegalStateException("Source exception during registering prerequisite. This is probably bug.",e);
+    }
+
+    private void tryToResolve() throws InferenceException {
+        if(action == null) {
+            return; // Action was not yet defined
+        }
+        if(removeSatisfied()) {
+            applyAction();
+        }
+    }
+
+    private boolean removeSatisfied() {
+        Iterator<AbstractPrerequisite<?>> prereq = unsatisfied.iterator();
+        boolean allSatisfied = true;
+        while(prereq.hasNext()) {
+            if(prereq.next().isDone()) {
+                prereq.remove(); // We are removing current prerequisite from list.
+            } else {
+                allSatisfied  = false;
+            }
+        }
+        return allSatisfied;
+    }
+
+    ModelProcessingPhase getPhase() {
+        return phase;
+    }
+
+    boolean isApplied() {
+
+        return actionApplied;
+    }
+
+    void failModifier() throws InferenceException {
+        removeSatisfied();
+        action.prerequisiteFailed(unsatisfied);
+        action = null;
+    }
+
+    private void applyAction() throws InferenceException {
+
+        action.apply();
+        // Mark all mutations as performed, so context node could move to next.
+        actionApplied = true;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private <K, C extends StmtContext<?,?,?>, N extends StatementNamespace<K, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(StmtContext<?, ?, ?> context, Class<N> namespace, K key,ModelProcessingPhase phase)  {
+        checkNotRegistered();
+        try {
+            AddedToNamespace<C> addedToNs = new AddedToNamespace<C>(phase);
+            addReq(addedToNs);
+            contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,addedToNs);
+            return addedToNs;
+        } catch (SourceException e) {
+            throw shouldNotHappenProbablyBug(e);
+        }
+    }
+
+    private <C extends StmtContext<?, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(C context, ModelProcessingPhase phase) {
+        Preconditions.checkState(action == null, "Action was already registered.");
+        try {
+            PhaseFinished<C> phaseFin = new PhaseFinished<C>();
+            addReq(phaseFin);
+            contextImpl(context).addPhaseCompletedListener(FullDeclaration,phaseFin);
+            return phaseFin;
+        } catch (SourceException e) {
+            throw shouldNotHappenProbablyBug(e);
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private <K, C extends StmtContext.Mutable<?, ?, ?> , N extends StatementNamespace<K, ?, ? >> AbstractPrerequisite<C> mutatesCtxImpl(
+                StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
+            try {
+                PhaseModificationInNamespace<C> mod = new PhaseModificationInNamespace<C>(phase);
+                addMutation(mod);
+                contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,mod);
+                return mod;
+            } catch (SourceException e) {
+                throw shouldNotHappenProbablyBug(e);
+            }
+        }
+
+    private static StatementContextBase<?,?,?> contextImpl(StmtContext<?,?,?> context) {
+        Preconditions.checkArgument(context instanceof StatementContextBase,"Supplied context was not provided by this reactor.");
+        return StatementContextBase.class.cast(context);
+    }
+
+    @Override
+    public <C extends Mutable<?, ?, ?>, CT extends C> Prerequisite<C> mutatesCtx(CT context, ModelProcessingPhase phase) {
+        try {
+            return addMutation(new PhaseMutation<C>(contextImpl(context),phase));
+        } catch (InferenceException e) {
+            throw shouldNotHappenProbablyBug(e);
+        }
+    }
+
+    @Override
+    public  <A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> AbstractPrerequisite<StmtContext<A, D, E>> requiresCtx(StmtContext<A, D, E> context, ModelProcessingPhase phase) {
+        return requiresCtxImpl(context, phase);
+    }
+
+
+    @Override
+    public <K, N extends StatementNamespace<K, ?, ? >> Prerequisite<StmtContext<?,?,?>> requiresCtx(StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
+        return requiresCtxImpl(context, namespace, key, phase);
+    }
+
+    @Override
+    public <D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(StmtContext<?, ? extends D, ?> context) {
+        return requiresCtxImpl(context,FullDeclaration).transform(StmtContextUtils.<D>buildDeclared());
+    }
+
+    @Override
+    public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> AbstractPrerequisite<StmtContext<?, D, ?>> requiresDeclaredCtx(
+            StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+        return requiresCtxImpl(context, namespace, key,FullDeclaration);
+    }
+
+    @Override
+    public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<D> requiresDeclared(
+            StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+        final AbstractPrerequisite<StmtContext<?,D,?>> rawContext = requiresCtxImpl(context, namespace, key,FullDeclaration);
+        return rawContext.transform(StmtContextUtils.<D>buildDeclared());
+    }
+
+    @Override
+    public <E extends EffectiveStatement<?, ?>> Prerequisite<E> requiresEffective(StmtContext<?, ?, ? extends E> stmt) {
+        return requiresCtxImpl(stmt,EffectiveModel).transform(StmtContextUtils.<E>buildEffective());
+    }
+
+    @Override
+    public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<StmtContext<?, ?, E>> requiresEffectiveCtx(
+            StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+        return requiresCtxImpl(contextImpl(context),namespace,key,EffectiveModel);
+    }
+
+    @Override
+    public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<E> requiresEffective(
+            StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+        final AbstractPrerequisite<StmtContext<?,?,E>> rawContext = requiresCtxImpl(context, namespace, key,EffectiveModel);
+        return rawContext.transform(StmtContextUtils.<E>buildEffective());
+    }
+
+
+    @Override
+    public <N extends IdentifierNamespace<?, ?>> Prerequisite<Mutable<?, ?, ?>> mutatesNs(Mutable<?, ?, ?> context,
+            Class<N> namespace) {
+        try {
+            return addMutation(new NamespaceMutation<N>(contextImpl(context),namespace));
+        } catch (SourceException e) {
+            throw shouldNotHappenProbablyBug(e);
+        }
+    }
+
+    @Override
+    public <T extends Mutable<?, ?, ?>> Prerequisite<T> mutatesEffectiveCtx(T stmt) {
+        return mutatesCtx(stmt, EffectiveModel);
+    }
+
+
+   @Override
+    public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtx(
+            StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
+        return mutatesCtxImpl(context, namespace, key, EffectiveModel);
+    }
+
+
+
+    @Override
+    public void apply(InferenceAction action) throws InferenceException {
+        this.action = Preconditions.checkNotNull(action);
+        tryToResolve();
+    }
+
+    private abstract class AbstractPrerequisite<T> implements Prerequisite<T> {
+
+        private T value;
+        private boolean done = false;
+
+        @Override
+        public T get() {
+            Preconditions.checkState(isDone());
+            return value;
+        }
+
+        @Override
+        public boolean isDone() {
+            return done;
+        }
+
+        protected void resolvePrereq(T value) throws InferenceException {
+            Preconditions.checkState(!isDone());
+            this.value = value;
+            this.done = true;
+            tryToResolve();
+        }
+
+        protected <O> Prerequisite<O> transform(final Function<? super T,O> transformation) {
+
+            return new Prerequisite<O>() {
+
+                @Override
+                public O get() {
+                    return transformation.apply(AbstractPrerequisite.this.get());
+                }
+
+                @Override
+                public boolean isDone() {
+                    return AbstractPrerequisite.this.isDone();
+                }
+
+            };
+        }
+
+    }
+
+    private class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
+
+        @SuppressWarnings("unchecked")
+        public PhaseMutation(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws InferenceException {
+            context.addMutation(phase, this);
+            resolvePrereq((C) context);
+        }
+
+        @Override
+        public boolean isFinished() {
+            return isApplied();
+        }
+
+
+    }
+    private class PhaseFinished<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C> implements OnPhaseFinished {
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
+            resolvePrereq((C) (context));
+        }
+    }
+
+    private class NamespaceMutation<N extends IdentifierNamespace<?,?>> extends  AbstractPrerequisite<StmtContext.Mutable<?, ?, ?>>  {
+
+        public NamespaceMutation(StatementContextBase<?, ?, ?> ctx, Class<N> namespace) throws InferenceException {
+            resolvePrereq(ctx);
+        }
+
+    }
+
+    private class AddedToNamespace<C extends StmtContext<?,?,?>> extends  AbstractPrerequisite<C> implements OnNamespaceItemAdded,OnPhaseFinished {
+
+        private final ModelProcessingPhase phase;
+
+        public <K, N extends StatementNamespace<K, ?, ?>> AddedToNamespace(ModelProcessingPhase phase) {
+            this.phase = phase;
+        }
+
+        @Override
+        public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
+                Object value) throws SourceException {
+            StatementContextBase<?, ?, ?> targetContext = (StatementContextBase<?, ?, ?>) value;
+            targetContext.addPhaseCompletedListener(phase, this);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
+            resolvePrereq((C) context);
+        }
+
+    }
+
+    private class PhaseModificationInNamespace<C extends Mutable<?,?,?>> extends AbstractPrerequisite<C> implements OnNamespaceItemAdded, ContextMutation {
+
+        private final ModelProcessingPhase modPhase;
+
+        public <K, N extends StatementNamespace<K, ?, ?>> PhaseModificationInNamespace(ModelProcessingPhase phase) throws SourceException {
+            Preconditions.checkArgument(phase != null, "Model processing phase must not be null");
+            this.modPhase = phase;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
+                Object value) throws SourceException {
+            context.addMutation(modPhase,this);
+            resolvePrereq((C) context);
+        }
+
+        @Override
+        public boolean isFinished() {
+            return isApplied();
+        }
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java
new file mode 100644 (file)
index 0000000..2a99e6e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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.reactor;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Iterator;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+
+final class NamespaceBehaviourWithListeners<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+
+    static abstract class ValueAddedListener {
+
+        private org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode ctxNode;
+
+        public ValueAddedListener(NamespaceStorageNode contextNode) {
+            this.ctxNode = contextNode;
+        }
+
+        abstract void onValueAdded(Object key, Object value);
+
+    }
+
+    private final NamespaceBehaviour<K, V, N> delegate;
+    private final Multimap<K, ValueAddedListener> listeners = HashMultimap.create();
+
+    protected NamespaceBehaviourWithListeners(NamespaceBehaviour<K, V, N> delegate) {
+        super(delegate.getIdentifier());
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void addTo(NamespaceBehaviour.NamespaceStorageNode storage,
+            K key, V value) {
+        delegate.addTo(storage, key, value);
+
+        Iterator<ValueAddedListener> keyListeners = listeners.get(key).iterator();
+        while(keyListeners.hasNext()) {
+            ValueAddedListener listener = keyListeners.next();
+            if(listener.ctxNode == storage || hasIdentiticalValue(listener.ctxNode,key,value)) {
+                keyListeners.remove();
+                listener.onValueAdded(key, value);
+            }
+        }
+    }
+
+    private boolean hasIdentiticalValue(NamespaceBehaviour.NamespaceStorageNode ctxNode, K key, V value) {
+        return getFrom(ctxNode, key) == value;
+    }
+
+    void addValueListener(K key, ValueAddedListener listener) {
+        listeners.put(key, listener);
+    }
+
+    @Override
+    public V getFrom(NamespaceBehaviour.NamespaceStorageNode storage,
+            K key) {
+        return delegate.getFrom(storage, key);
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java
new file mode 100644 (file)
index 0000000..f79a062
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.reactor;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+abstract class NamespaceStorageSupport implements NamespaceStorageNode {
+
+    private final Map<Class<?>,Map<?,?>> namespaces = new HashMap<>();
+
+
+    @Override
+    public abstract NamespaceStorageNode getParentNamespaceStorage();
+
+    public abstract NamespaceBehaviour.Registry getBehaviourRegistry();
+
+    protected void checkLocalNamespaceAllowed(Class<? extends IdentifierNamespace<?, ?>> type) {
+        // NOOP
+    }
+
+    protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(Class<N> type, K key, V value) {
+        // NOOP
+    }
+
+    public final <K, VT, V extends VT ,N extends IdentifierNamespace<K, V>> VT getFromNamespace(Class<N> type, K key)
+            throws NamespaceNotAvailableException {
+        return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this,key);
+    }
+
+    public final <K,V,VT extends V,N extends IdentifierNamespace<K, V>> void addToNs(Class<N> type, K key, VT value)
+            throws NamespaceNotAvailableException {
+        getBehaviourRegistry().getNamespaceBehaviour(type).addTo(this,key,value);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public final <K, N extends StatementNamespace<K, ?,?>> void addContextToNamespace(Class<N> type, K key, StmtContext<?, ?, ?> value)
+            throws NamespaceNotAvailableException {
+        getBehaviourRegistry().getNamespaceBehaviour((Class)type).addTo(this, key, value);
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key) {
+        @SuppressWarnings("unchecked")
+        Map<K, V> localNamespace = (Map<K,V>) namespaces.get(type);
+        if(localNamespace != null) {
+            return localNamespace.get(key);
+        }
+        return null;
+    }
+
+
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value) {
+        @SuppressWarnings("unchecked")
+        Map<K, V> localNamespace = (Map<K,V>) namespaces.get(type);
+        if(localNamespace == null) {
+            checkLocalNamespaceAllowed(type);
+            localNamespace = new HashMap<>();
+            namespaces.put(type, localNamespace);
+        }
+        localNamespace.put(key,value);
+        onNamespaceElementAdded(type,key,value);
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/RootStatementContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/RootStatementContext.java
new file mode 100644 (file)
index 0000000..295d2cc
--- /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.reactor;
+
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+
+class RootStatementContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+    extends StatementContextBase<A, D,E> {
+
+
+    private final SourceSpecificContext sourceContext;
+
+    RootStatementContext(ContextBuilder<A, D,E> builder, SourceSpecificContext sourceContext) throws SourceException {
+        super(builder);
+        this.sourceContext = sourceContext;
+    }
+
+    @Override
+    public StatementContextBase<?,?, ?> getParentContext() {
+        return null;
+    }
+
+    @Override
+    public NamespaceStorageNode getParentNamespaceStorage() {
+        return sourceContext;
+    }
+
+    @Override
+    public Registry getBehaviourRegistry() {
+        return sourceContext;
+    }
+
+    @Override
+    public RootStatementContext<?,?,?> getRoot() {
+        return this;
+    }
+
+    SourceSpecificContext getSourceContext() {
+        return sourceContext;
+    }
+
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java
new file mode 100644 (file)
index 0000000..7cdcfb0
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import javax.annotation.Nullable;
+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.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+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;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
+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;
+
+public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable {
+
+    public enum PhaseCompletionProgress {
+        NO_PROGRESS,
+        PROGRESS,
+        FINISHED
+    }
+
+    private final StatementStreamSource source;
+    private final BuildGlobalContext currentContext;
+    private final Collection<NamespaceStorageNode> importedNamespaces = new ArrayList<>();
+    private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
+
+    private RootStatementContext<?,?, ?> root;
+
+    private ModelProcessingPhase inProgressPhase;
+    private ModelProcessingPhase finishedPhase;
+
+
+    SourceSpecificContext(BuildGlobalContext currentContext,StatementStreamSource source) {
+        this.source = source;
+        this.currentContext = currentContext;
+    }
+
+    StatementDefinitionContext<?,?,?> getDefinition(QName name) {
+        return currentContext.getStatementDefinition(name);
+    }
+
+    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);
+        if(current == null) {
+            return createDeclaredRoot(def,ref);
+        }
+        return current.substatementBuilder(def,ref);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private ContextBuilder<?,?, ?> createDeclaredRoot(StatementDefinitionContext<?,?,?> def, StatementSourceReference ref) {
+        return new ContextBuilder(def,ref) {
+
+            @Override
+            public StatementContextBase build() throws SourceException {
+                if(root == null) {
+                    root = new RootStatementContext(this, SourceSpecificContext.this);
+                } else {
+                    Preconditions.checkState(root.getIdentifier().equals(getIdentifier()), "Root statement was already defined.");
+                }
+                root.resetLists();
+                return root;
+            }
+
+        };
+    }
+
+    RootStatementContext<?,?,?> getRoot() {
+        return root;
+    }
+
+    DeclaredStatement<?> buildDeclared() {
+        return root.buildDeclared();
+    }
+
+    EffectiveStatement<?,?> build() {
+        return root.buildEffective();
+    }
+
+    void startPhase(ModelProcessingPhase phase) {
+        @Nullable ModelProcessingPhase previousPhase = phase.getPreviousPhase();
+        Preconditions.checkState(Objects.equals(previousPhase, finishedPhase));
+        Preconditions.checkState(modifiers.get(previousPhase).isEmpty());
+        inProgressPhase = phase;
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value) {
+        if(ImportedNamespaceContext.class.isAssignableFrom(type)) {
+            importedNamespaces.add((NamespaceStorageNode) value);
+        }
+        getRoot().addToLocalStorage(type, key, value);
+    }
+
+    @Override
+    public StorageNodeType getStorageNodeType() {
+        return StorageNodeType.SourceLocalSpecial;
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key) {
+        final V potentialLocal = getRoot().getFromLocalStorage(type, key);
+        if(potentialLocal != null) {
+            return potentialLocal;
+        }
+        for(NamespaceStorageNode importedSource : importedNamespaces) {
+            V potential = importedSource.getFromLocalStorage(type, key);
+            if(potential != null) {
+                return potential;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type) {
+        return currentContext.getNamespaceBehaviour(type);
+    }
+
+    @Override
+    public NamespaceStorageNode getParentNamespaceStorage() {
+        return currentContext;
+    }
+
+    PhaseCompletionProgress tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
+        Collection<ModifierImpl> currentPhaseModifiers = modifiers.get(phase);
+        Iterator<ModifierImpl> modifier = currentPhaseModifiers.iterator();
+        boolean hasProgressed = false;
+        while(modifier.hasNext()) {
+            if(modifier.next().isApplied()) {
+                modifier.remove();
+                hasProgressed = true;
+            }
+        }
+        if(root.tryToCompletePhase(phase) && currentPhaseModifiers.isEmpty()) {
+            finishedPhase = phase;
+            return PhaseCompletionProgress.FINISHED;
+
+        }
+        if(hasProgressed) {
+            return PhaseCompletionProgress.PROGRESS;
+        }
+        return PhaseCompletionProgress.NO_PROGRESS;
+    }
+
+    ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
+        ModifierImpl action = new ModifierImpl(phase);
+        modifiers.put(phase, action);
+        return action;
+    }
+
+    @Override
+    public String toString() {
+        return "SourceSpecificContext [source=" + source + ", current=" + inProgressPhase + ", finished="
+                + finishedPhase + "]";
+    }
+
+    SourceException failModifiers(ModelProcessingPhase identifier) {
+        InferenceException sourceEx = new InferenceException("Fail to infer source relationships", root.getStatementSourceReference());
+
+
+        for(ModifierImpl mod : modifiers.get(identifier)) {
+            try {
+                mod.failModifier();
+            } catch (SourceException e) {
+                sourceEx.addSuppressed(e);
+            }
+        }
+        return sourceEx;
+    }
+
+    void loadStatements() throws SourceException {
+        switch (inProgressPhase) {
+        case SourceLinkage:
+            source.writeLinkage(new StatementContextWriter(this, inProgressPhase),stmtDef());
+            break;
+        case StatementDefinition:
+            source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
+        case FullDeclaration:
+            source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
+
+        default:
+            break;
+        }
+    }
+
+    private PrefixToModule prefixes() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    private QNameToStatementDefinition stmtDef() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java
new file mode 100644 (file)
index 0000000..035e192
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.ValueAddedListener;
+
+abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends
+        NamespaceStorageSupport implements StmtContext.Mutable<A, D, E>, Identifiable<StatementIdentifier> {
+
+    interface OnNamespaceItemAdded extends EventListener{
+
+        void namespaceItemAdded(StatementContextBase<?,?,?> context, Class<?> namespace, Object key, Object value) throws SourceException;
+
+    }
+
+    interface OnPhaseFinished extends EventListener{
+
+        void phaseFinished(StatementContextBase<?,?,?> context, ModelProcessingPhase phase) throws SourceException;
+
+    }
+
+    interface ContextMutation {
+
+        boolean isFinished();
+
+    }
+
+    abstract static class ContextBuilder<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
+
+        private final StatementDefinitionContext<A, D, E> definition;
+        private final StatementSourceReference stmtRef;
+        private String rawArg;
+        private StatementSourceReference argRef;
+
+        public ContextBuilder(StatementDefinitionContext<A, D, E> def, StatementSourceReference sourceRef) {
+            this.definition = def;
+            this.stmtRef = sourceRef;
+        }
+
+        public void setArgument(@Nonnull String argument, @Nonnull StatementSourceReference argumentSource) {
+            Preconditions.checkArgument(definition.hasArgument(), "Statement does not take argument.");
+            this.rawArg = Preconditions.checkNotNull(argument);
+            this.argRef = Preconditions.checkNotNull(argumentSource);
+        }
+
+        public String getRawArgument() {
+            return rawArg;
+        }
+
+        public StatementSourceReference getStamementSource() {
+            return stmtRef;
+        }
+
+        public StatementSourceReference getArgumentSource() {
+            return argRef;
+        }
+
+        public StatementDefinitionContext<A, D, E> getDefinition() {
+            return definition;
+        }
+
+        public StatementIdentifier getIdentifier() {
+            return new StatementIdentifier(definition.getStatementName(), rawArg);
+        }
+
+        public abstract StatementContextBase<A, D, E> build() throws SourceException;
+
+    }
+
+    private final StatementDefinitionContext<A, D, E> definition;
+    private final StatementIdentifier identifier;
+    private final StatementSourceReference statementDeclSource;
+    private final A argument;
+
+    private LinkedHashMap<StatementIdentifier, StatementContextBase<?, ?, ?> > substatements = new LinkedHashMap<>();
+
+    private Collection<StatementContextBase<?, ?, ?>> declared = new ArrayList<>();
+    private Collection<StatementContextBase<?, ?, ?>> effective = new ArrayList<>();
+
+    private ModelProcessingPhase completedPhase;
+
+    private Multimap<ModelProcessingPhase,OnPhaseFinished> phaseListeners = HashMultimap.create();
+    private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = HashMultimap.create();
+
+    private D declaredInstance;
+    private E effectiveInstance;
+
+
+    StatementContextBase(@Nonnull ContextBuilder<A, D, E> builder) throws SourceException {
+        this.definition = builder.getDefinition();
+        this.identifier = builder.getIdentifier();
+        this.statementDeclSource = builder.getStamementSource();
+        this.argument = definition.parseArgumentValue(this, this.rawStatementArgument());
+        this.completedPhase = null;
+    }
+
+    @Override
+    public abstract StatementContextBase<?, ?, ?> getParentContext();
+
+    @Override
+    public abstract RootStatementContext<?, ?, ?> getRoot();
+
+
+    @Override
+    public StatementIdentifier getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public StatementSource getStatementSource() {
+        return statementDeclSource.getStatementSource();
+    }
+
+    @Override
+    public StatementSourceReference getStatementSourceReference() {
+        return statementDeclSource;
+    }
+
+    @Override
+    public String rawStatementArgument() {
+        return identifier.getArgument();
+    }
+
+    @Override
+    public A getStatementArgument() {
+        return argument;
+    }
+
+    @Override
+    public Collection<? extends StmtContext<?, ?, ?>> declaredSubstatements() {
+        return Collections.unmodifiableCollection(declared);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public ContextBuilder<?, ?, ?> substatementBuilder(StatementDefinitionContext<?, ?, ?> def,
+            StatementSourceReference ref) {
+        return new ContextBuilder(def, ref) {
+
+            @Override
+            public StatementContextBase build() throws SourceException {
+                StatementContextBase<?, ?, ?> potential = substatements.get(getIdentifier());
+                if(potential == null) {
+                    potential = new SubstatementContext(StatementContextBase.this, this);
+                    substatements.put(getIdentifier(), potential);
+                }
+                potential.resetLists();
+                switch (this.getStamementSource().getStatementSource()) {
+                    case DECLARATION:
+                        declared.add(potential);
+                        break;
+                    case CONTEXT:
+                        effective.add(potential);
+                        break;
+                }
+                return potential;
+            }
+        };
+    }
+
+    @Override
+    public StorageNodeType getStorageNodeType() {
+        return StorageNodeType.StatementLocal;
+    }
+
+    @Override
+    public D buildDeclared() {
+        Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FullDeclaration || completedPhase == ModelProcessingPhase.EffectiveModel);
+        if (declaredInstance == null) {
+            declaredInstance = definition().getFactory().createDeclared(this);
+        }
+        return declaredInstance;
+    }
+
+    @Override
+    public E buildEffective() {
+        Preconditions.checkArgument(completedPhase == ModelProcessingPhase.EffectiveModel);
+        if (effectiveInstance == null) {
+            effectiveInstance = definition().getFactory().createEffective(this);
+        }
+        return effectiveInstance;
+    }
+
+
+    void resetLists() {
+        declared.clear();
+    }
+
+    boolean tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
+        if(phase.equals(completedPhase)) {
+            return true;
+        }
+        Iterator<ContextMutation> openMutations = phaseMutation.get(phase).iterator();
+        boolean finished = true;
+        while(openMutations.hasNext()) {
+            ContextMutation current = openMutations.next();
+            if(current.isFinished()) {
+                openMutations.remove();
+            } else {
+                finished = false;
+            }
+        }
+        for(StatementContextBase<?, ?, ?> child: declared) {
+            finished &= child.tryToCompletePhase(phase);
+        }
+        if(finished) {
+            onPhaseCompleted(phase);
+            return true;
+        }
+        return false;
+    }
+
+
+    private void onPhaseCompleted(ModelProcessingPhase phase) throws SourceException {
+        completedPhase = phase;
+        Iterator<OnPhaseFinished> listener = phaseListeners.get(completedPhase).iterator();
+        while(listener.hasNext()) {
+            listener.next().phaseFinished(this, phase);
+            listener.remove();
+        }
+    }
+
+    /**
+     *
+     * Ends declared section of current node.
+     *
+     * @param ref
+     * @throws SourceException
+     *
+     */
+    void endDeclared(StatementSourceReference ref,ModelProcessingPhase phase) throws SourceException {
+        definition().onDeclarationFinished(this,phase);
+    }
+
+    protected final StatementDefinitionContext<A, D, E> definition() {
+        return definition;
+    }
+
+    @Override
+    protected void checkLocalNamespaceAllowed(Class<? extends IdentifierNamespace<?, ?>> type) {
+        definition().checkNamespaceAllowed(type);
+    }
+
+    @Override
+    protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(Class<N> type, K key, V value) {
+        //definition().onNamespaceElementAdded(this, type, key, value);
+    }
+
+    <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, K key, final OnNamespaceItemAdded listener) throws SourceException {
+        Object potential = getFromNamespace(type, key);
+        if(potential != null) {
+            listener.namespaceItemAdded(this, type, key, potential);
+            return;
+        }
+        NamespaceBehaviour<K,V,N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
+        if(behaviour instanceof NamespaceBehaviourWithListeners) {
+            NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K,V,N>) behaviour;
+            casted.addValueListener(key, new ValueAddedListener(this) {
+                @Override
+                void onValueAdded(Object key, Object value) {
+                    try {
+                        listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
+                    } catch (SourceException e) {
+                        throw Throwables.propagate(e);
+                    }
+                }
+            });
+        }
+    }
+
+    @Override
+    public StatementDefinition getPublicDefinition() {
+        return definition().getPublicView();
+    }
+
+    @Override
+    public ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
+        return getRoot().getSourceContext().newInferenceAction(phase);
+    }
+
+    void addPhaseCompletedListener(ModelProcessingPhase phase, OnPhaseFinished listener) throws SourceException {
+        ModelProcessingPhase finishedPhase = completedPhase;
+        while (finishedPhase != null) {
+            if(phase.equals(finishedPhase)) {
+                listener.phaseFinished(this, finishedPhase);
+                return;
+            }
+            finishedPhase = finishedPhase.getPreviousPhase();
+        }
+        phaseListeners.put(phase, listener);
+    }
+
+    void addMutation(ModelProcessingPhase phase, ContextMutation mutation) {
+        ModelProcessingPhase finishedPhase = completedPhase;
+        while (finishedPhase != null) {
+            if(phase.equals(finishedPhase)) {
+                throw new IllegalStateException("Mutation registered after phase was completed.");
+            }
+            finishedPhase = finishedPhase.getPreviousPhase();
+        }
+        phaseMutation.put(phase, mutation);
+    }
+
+    @Override
+    public <K,KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(
+            Class<N> namepsace, KT key, StmtContext<?, ?, ?> stmt) {
+        addContextToNamespace(namepsace,(K) key, stmt);
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextWriter.java
new file mode 100644 (file)
index 0000000..3a1a8b7
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+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.StatementWriter;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextBuilder;
+
+class StatementContextWriter implements StatementWriter {
+
+    private final SourceSpecificContext ctx;
+    private StatementContextBase<?, ?, ?> parent;
+    private ContextBuilder<?, ?, ?> current;
+    private ModelProcessingPhase phase;
+
+    public StatementContextWriter(SourceSpecificContext ctx, ModelProcessingPhase phase) {
+        this.ctx = Preconditions.checkNotNull(ctx);
+        this.phase = Preconditions.checkNotNull(phase);
+    }
+
+    @Override
+    public void startStatement(QName name, StatementSourceReference ref) throws SourceException {
+        defferedCreate();
+        current = ctx.createDeclaredChild(parent, name, ref);
+
+    }
+
+    @Override
+    public void argumentValue(String value, StatementSourceReference ref) {
+        Preconditions.checkState(current != null, "Could not two arguments for one statement.");
+        current.setArgument(value, ref);
+    }
+
+    void defferedCreate() throws SourceException {
+        if(current != null) {
+            parent = current.build();
+            current = null;
+        }
+    }
+
+    @Override
+    public void endStatement(StatementSourceReference ref) throws SourceException {
+        defferedCreate();
+        Preconditions.checkState(parent != null);
+        parent.endDeclared(ref,phase);
+        parent = parent.getParentContext();
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementDefinitionContext.java
new file mode 100644 (file)
index 0000000..bf99398
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.reactor;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+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.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+class StatementDefinitionContext<A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A,D>> {
+    private final StatementSupport<A,D,E> support;
+    public StatementDefinitionContext(StatementSupport<A,D,E> support) {
+        this.support= support;
+    }
+
+
+    public StatementFactory<A,D,E> getFactory() {
+        return support;
+    }
+
+    public A parseArgumentValue(StmtContext<A,D,E> context, String value) throws SourceException {
+        return support.parseArgumentValue(context,value);
+    }
+
+
+    public void checkNamespaceAllowed(Class<? extends IdentifierNamespace<?,?>> namespace) throws NamespaceNotAvailableException {
+        // Noop
+    }
+
+    public StatementDefinition getPublicView() {
+        return support.getPublicView();
+    }
+
+    public boolean onStatementAdded(Mutable<A,D,E> stmt) {
+        return false;
+    }
+
+
+    public void onDeclarationFinished(Mutable<A,D,E> statement, ModelProcessingPhase phase) throws SourceException {
+        switch (phase) {
+        case SourceLinkage:
+            support.onLinkageDeclared(statement);
+            break;
+        case StatementDefinition:
+            support.onStatementDefinitionDeclared(statement);
+        case FullDeclaration:
+            support.onFullDefinitionDeclared(statement);
+        default:
+            break;
+        }
+    }
+
+
+
+    public Class<?> getRepresentingClass() {
+        return support.getDeclaredRepresentationClass();
+    }
+
+
+    public boolean hasArgument() {
+        return support.getArgumentName() != null;
+    }
+
+
+    public QName getStatementName() {
+        return support.getStatementName();
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementIdentifier.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementIdentifier.java
new file mode 100644 (file)
index 0000000..4ebc2c2
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+
+class StatementIdentifier {
+
+    private final @Nonnull QName name;
+    private final @Nullable String argument;
+
+    StatementIdentifier(QName name, String argument) {
+        this.name = Preconditions.checkNotNull(name);
+        this.argument = argument;
+    }
+
+    QName getName() {
+        return name;
+    }
+
+    String getArgument() {
+        return argument;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result +  name.hashCode();
+        result = prime * result + ((argument == null) ? 0 : argument.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        StatementIdentifier other = (StatementIdentifier) obj;
+        if (!name.equals(other.name)) {
+            return false;
+        }
+        if (!Objects.equal(argument, other.argument)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "StatementIdentifier [name=" + name + ", argument=" + argument + "]";
+    }
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SubstatementContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SubstatementContext.java
new file mode 100644 (file)
index 0000000..aafdfca
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.reactor;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
+import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+class SubstatementContext<A,D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+    extends StatementContextBase<A,D,E> {
+
+    private final StatementContextBase<?,?,?> parent;
+
+    SubstatementContext(StatementContextBase<?,?,?> parent,ContextBuilder<A,D,E> builder) throws SourceException {
+        super(builder);
+        this.parent = Preconditions.checkNotNull(parent, "Parent must not be null");
+    }
+
+    @Override
+    public StatementContextBase<?,?,?> getParentContext() {
+        return parent;
+    }
+
+    @Override
+    public NamespaceStorageNode getParentNamespaceStorage() {
+        return parent;
+    }
+
+    @Override
+    public Registry getBehaviourRegistry() {
+        return parent.getBehaviourRegistry();
+    }
+
+    @Override
+    public RootStatementContext<?, ?, ?> getRoot() {
+        return parent.getRoot();
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AbstractRootStatement.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AbstractRootStatement.java
new file mode 100644 (file)
index 0000000..2cc98a8
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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 java.util.Collection;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.BodyGroup;
+import org.opendaylight.yangtools.yang.model.api.stmt.ContactStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.FeatureStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IdentityStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IncludeStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LinkageGroup;
+import org.opendaylight.yangtools.yang.model.api.stmt.MetaGroup;
+import org.opendaylight.yangtools.yang.model.api.stmt.NotificationStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OrganizationStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RevisionGroup;
+import org.opendaylight.yangtools.yang.model.api.stmt.RevisionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+public abstract class AbstractRootStatement<T extends DeclaredStatement<String>> extends AbstractDeclaredStatement<String>
+        implements LinkageGroup, MetaGroup, RevisionGroup, BodyGroup {
+
+    protected AbstractRootStatement(StmtContext<String, T,?> context) {
+        super(context);
+    }
+
+    @Override
+    public final Collection<? extends ImportStatement> getImports() {
+        return allDeclared(ImportStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends IncludeStatement> getIncludes() {
+        return allDeclared(IncludeStatement.class);
+    }
+
+    @Override
+    public DescriptionStatement getDescription() {
+        return firstDeclared(DescriptionStatement.class);
+    }
+
+    @Override
+    public ReferenceStatement getReference() {
+        return firstDeclared(ReferenceStatement.class);
+    }
+
+    @Override
+    public final OrganizationStatement getOrganization() {
+        return firstDeclared(OrganizationStatement.class);
+    }
+
+    @Override
+    public final ContactStatement getContact() {
+        return firstDeclared(ContactStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends RevisionStatement> getRevisions() {
+        return allDeclared(RevisionStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends ExtensionStatement> getExtensions() {
+        return allDeclared(ExtensionStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends FeatureStatement> getFeatures() {
+        return allDeclared(FeatureStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends IdentityStatement> getIdentities() {
+        return allDeclared(IdentityStatement.class);
+    }
+
+    @Override
+    public Collection<? extends TypedefStatement> getTypedefs() {
+        return allDeclared(TypedefStatement.class);
+    }
+
+    @Override
+    public Collection<? extends GroupingStatement> getGroupings() {
+        return allDeclared(GroupingStatement.class);
+    }
+
+    @Override
+    public Collection<? extends DataDefinitionStatement> getDataDefinitions() {
+        return allDeclared(DataDefinitionStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends AugmentStatement> getAugments() {
+        return allDeclared(AugmentStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends RpcStatement> getRpcs() {
+        return allDeclared(RpcStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends NotificationStatement> getNotifications() {
+        return allDeclared(NotificationStatement.class);
+    }
+
+    @Override
+    public final Collection<? extends DeviationStatement> getDeviations() {
+        return allDeclared(DeviationStatement.class);
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ContainerStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ContainerStatementImpl.java
new file mode 100644 (file)
index 0000000..da3d8bc
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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 java.util.Collection;
+import org.opendaylight.yangtools.yang.common.QName;
+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.ConfigStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ContainerStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DataDefinitionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.MustStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PresenceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
+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;
+
+public class ContainerStatementImpl extends AbstractDeclaredStatement<QName> implements ContainerStatement {
+
+    protected ContainerStatementImpl(StmtContext<QName, ContainerStatement,?> context) {
+        super(context);
+    }
+
+    public static class Definition extends AbstractStatementSupport<QName,ContainerStatement,EffectiveStatement<QName,ContainerStatement>> {
+
+        public Definition() {
+            super(Rfc6020Mapping.Container);
+        }
+
+        @Override
+        public QName parseArgumentValue(StmtContext<?,?,?> ctx, String value) {
+            return Utils.qNameFromArgument(ctx,value);
+        }
+
+        @Override
+        public ContainerStatement createDeclared(StmtContext<QName, ContainerStatement,?> ctx) {
+            return new ContainerStatementImpl(ctx);
+        }
+
+        @Override
+        public EffectiveStatement<QName,ContainerStatement> createEffective(StmtContext<QName,ContainerStatement,EffectiveStatement<QName,ContainerStatement>> ctx) {
+           throw new UnsupportedOperationException();
+        }
+
+    }
+
+    @Override
+    public QName getName() {
+        return argument();
+    }
+
+    @Override
+    public WhenStatement getWhenStatement() {
+        return firstDeclared(WhenStatement.class);
+    }
+
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
+    @Override
+    public Collection<? extends MustStatement> getMusts() {
+        return allDeclared(MustStatement.class);
+    }
+
+    @Override
+    public PresenceStatement getPresence() {
+        return firstDeclared(PresenceStatement.class);
+    }
+
+    @Override
+    public ConfigStatement getConfig() {
+        return firstDeclared(ConfigStatement.class);
+    }
+
+    @Override
+    public StatusStatement getStatus() {
+        return firstDeclared(StatusStatement.class);
+    }
+
+    @Override
+    public DescriptionStatement getDescription() {
+        return firstDeclared(DescriptionStatement.class);
+    }
+
+    @Override
+    public ReferenceStatement getReference() {
+        return firstDeclared(ReferenceStatement.class);
+    }
+
+    @Override
+    public Collection<? extends TypedefStatement> getTypedefs() {
+        return allDeclared(TypedefStatement.class);
+    }
+
+    @Override
+    public Collection<? extends GroupingStatement> getGroupings() {
+        return allDeclared(GroupingStatement.class);
+    }
+
+    @Override
+    public Collection<? extends DataDefinitionStatement> getDataDefinitions() {
+        return allDeclared(DataDefinitionStatement.class);
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java
new file mode 100644 (file)
index 0000000..221dfec
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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 static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SourceLinkage;
+import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
+
+import com.google.common.base.Optional;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.Collection;
+import java.util.Date;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+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.ImportStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl;
+import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
+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.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+public class ImportStatementDefinition extends
+        AbstractStatementSupport<String, ImportStatement, EffectiveStatement<String, ImportStatement>> {
+
+    public ImportStatementDefinition() {
+        super(Rfc6020Mapping.Import);
+    }
+
+    @Override
+    public String parseArgumentValue(StmtContext<?, ?, ?> ctx, String value) {
+        return value;
+    }
+
+    @Override
+    public ImportStatement createDeclared(StmtContext<String, ImportStatement, ?> ctx) {
+        return new ImportStatementImpl(ctx);
+    }
+
+    @Override
+    public EffectiveStatement<String, ImportStatement> createEffective(
+            StmtContext<String, ImportStatement, EffectiveStatement<String, ImportStatement>> ctx) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onLinkageDeclared(final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt)
+            throws InferenceException, SourceException {
+        final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt);
+        ModelActionBuilder importAction = stmt.newInferenceAction(SourceLinkage);
+        final Prerequisite<StmtContext<?, ?, ?>> imported;
+        final Prerequisite<Mutable<?, ?, ?>> linkageTarget;
+        imported = importAction.requiresCtx(stmt, ModuleNamespace.class, impIdentifier, SourceLinkage);
+        linkageTarget = importAction.mutatesCtx(stmt.getRoot(),SourceLinkage);
+
+        importAction.apply(new InferenceAction() {
+
+            @Override
+            public void apply() throws InferenceException {
+                StmtContext<?, ?, ?> importedModule = imported.get();
+                // URI importedNs =
+                // importedModule.firstSubstatement(NamespaceStatement.class).argument();
+                // String prefix =
+                // stmt.firstSubstatement(PrefixStatement.class).argument();
+                linkageTarget.get().addToNs(ImportedModuleContext.class, impIdentifier, importedModule);
+                // prefixTarget.get().addToNs(PrefixToModule.class, prefix,
+                // QNameModule.create(importedNs, null));
+            }
+
+            @Override
+            public void prerequisiteFailed(Collection<? extends Prerequisite<?>> failed) throws InferenceException {
+                if (failed.contains(imported)) {
+                    throw new InferenceException("Imported module was not found.", stmt.getStatementSourceReference());
+                }
+            }
+        });
+    }
+
+    private static ModuleIdentifier getImportedModuleIdentifier(Mutable<String, ImportStatement, ?> stmt) throws SourceException {
+        String moduleName = stmt.getStatementArgument();
+        String revisionArg = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class);
+        final Optional<Date> revision;
+        if (revisionArg != null) {
+            try {
+                revision = Optional.of(SimpleDateFormatUtil.getRevisionFormat().parse(revisionArg));
+            } catch (ParseException e) {
+                throw new SourceException(
+                        String.format("Revision value %s is not in required format yyyy-MM-dd", revisionArg),
+                        stmt.getStatementSourceReference(), e);
+            }
+        } else {
+            revision = Optional.absent();
+        }
+        return new ModuleIdentifierImpl(moduleName, Optional.<URI> absent(), revision);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementImpl.java
new file mode 100644 (file)
index 0000000..df090bd
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.stmt.ImportStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+public class ImportStatementImpl extends AbstractDeclaredStatement<String> implements ImportStatement {
+
+    ImportStatementImpl(StmtContext<String, ImportStatement,?> context) {
+        super(context);
+    }
+
+    @Override
+    public String getModule() {
+        return rawArgument();
+    }
+
+    @Override
+    public PrefixStatement getPrefix() {
+        return firstDeclared(PrefixStatement.class);
+    }
+
+    @Override
+    public RevisionDateStatement getRevisionDate() {
+        return firstDeclared(RevisionDateStatement.class);
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportedModuleContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportedModuleContext.java
new file mode 100644 (file)
index 0000000..629fee2
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ImportedNamespaceContext;
+
+public interface ImportedModuleContext extends ImportedNamespaceContext<ModuleIdentifier> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementImpl.java
new file mode 100644 (file)
index 0000000..497f7c9
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.stmt.ModuleStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+
+public class ModuleStatementImpl extends AbstractRootStatement<ModuleStatement> implements ModuleStatement {
+
+    protected ModuleStatementImpl(StmtContext<String, ModuleStatement,?> context) {
+        super(context);
+    }
+
+    @Override
+    public String getName() {
+        return rawArgument();
+    }
+
+    @Override
+    public YangVersionStatement getYangVersion() {
+        return firstDeclared(YangVersionStatement.class);
+    }
+
+    @Override
+    public NamespaceStatement getNamespace() {
+        return firstDeclared(NamespaceStatement.class);
+    }
+
+    @Override
+    public PrefixStatement getPrefix() {
+        return firstDeclared(PrefixStatement.class);
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementSupport.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ModuleStatementSupport.java
new file mode 100644 (file)
index 0000000..1c3edcd
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
+
+import com.google.common.base.Optional;
+import java.net.URI;
+import java.util.Date;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+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.ModuleStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
+import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl;
+import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
+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.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+public class ModuleStatementSupport extends AbstractStatementSupport<String, ModuleStatement, EffectiveStatement<String,ModuleStatement>> {
+
+    public ModuleStatementSupport() {
+        super(Rfc6020Mapping.Module);
+    }
+
+    @Override
+    public String parseArgumentValue(StmtContext<?,?,?> ctx, String value) {
+        return value;
+    }
+
+    @Override
+    public ModuleStatement createDeclared(StmtContext<String, ModuleStatement,?> ctx) {
+        return new ModuleStatementImpl(ctx);
+    }
+
+    @Override
+    public EffectiveStatement<String,ModuleStatement> createEffective(StmtContext<String, ModuleStatement,EffectiveStatement<String,ModuleStatement>> ctx) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onLinkageDeclared(Mutable<String, ModuleStatement, EffectiveStatement<String, ModuleStatement>> stmt)
+            throws InferenceException, SourceException {
+        URI moduleNs = firstAttributeOf(stmt.declaredSubstatements(),NamespaceStatement.class);
+
+        QNameModule qnameNamespace = QNameModule.create(moduleNs, null);
+        ModuleIdentifierImpl moduleIdentifier = new ModuleIdentifierImpl(stmt.getStatementArgument(), Optional.<URI>absent(), Optional.<Date>absent());
+
+        stmt.addContext(ModuleNamespace.class,moduleIdentifier ,stmt);
+        stmt.addContext(NamespaceToModule.class, qnameNamespace, stmt);
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/NamespaceStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/NamespaceStatementImpl.java
new file mode 100644 (file)
index 0000000..acd9394
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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 java.net.URI;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
+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;
+
+public class NamespaceStatementImpl extends AbstractDeclaredStatement<URI> implements NamespaceStatement {
+
+    public static class Definition extends AbstractStatementSupport<URI,NamespaceStatement,EffectiveStatement<URI,NamespaceStatement>> {
+
+        public Definition() {
+            super(org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Namespace);
+        }
+
+        @Override
+        public URI parseArgumentValue(StmtContext<?, ?,?> ctx, String value) {
+            return URI.create(value);
+        }
+
+        @Override
+        public NamespaceStatement createDeclared(StmtContext<URI, NamespaceStatement,?> ctx) {
+            return new NamespaceStatementImpl(ctx);
+        }
+
+        @Override
+        public EffectiveStatement<URI,NamespaceStatement> createEffective(StmtContext<URI, NamespaceStatement,EffectiveStatement<URI,NamespaceStatement>> ctx) {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    NamespaceStatementImpl(StmtContext<URI, NamespaceStatement,?> context) {
+        super(context);
+    }
+
+    @Override
+    public URI getUri() {
+        return argument();
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/PrefixStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/PrefixStatementImpl.java
new file mode 100644 (file)
index 0000000..df63da0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
+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;
+
+public class PrefixStatementImpl extends AbstractDeclaredStatement<String> implements PrefixStatement {
+
+    public static class Definition extends AbstractStatementSupport<String,PrefixStatement,EffectiveStatement<String,PrefixStatement>> {
+
+        public Definition() {
+            super(Rfc6020Mapping.Prefix);
+        }
+
+        @Override
+        public String parseArgumentValue(StmtContext<?, ?,?> ctx, String value) {
+            return (value);
+        }
+
+        @Override
+        public PrefixStatement createDeclared(StmtContext<String, PrefixStatement,?> ctx) {
+            return new PrefixStatementImpl(ctx);
+        }
+
+        @Override
+        public EffectiveStatement<String,PrefixStatement> createEffective(StmtContext<String, PrefixStatement,EffectiveStatement<String,PrefixStatement>> ctx) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    PrefixStatementImpl(StmtContext<String, PrefixStatement,?> context) {
+        super(context);
+    }
+
+    @Override
+    public String getValue() {
+        return rawArgument();
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UsesStatementImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UsesStatementImpl.java
new file mode 100644 (file)
index 0000000..324eeaf
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 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 java.util.Collection;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+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.meta.StatementSource;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.GroupingStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.WhenStatement;
+import org.opendaylight.yangtools.yang.parser.spi.GroupingNamespace;
+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.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+
+public class UsesStatementImpl extends AbstractDeclaredStatement<QName> implements UsesStatement {
+
+    protected UsesStatementImpl(StmtContext<QName, UsesStatement, ?> context) {
+        super(context);
+    }
+
+    public static class Definition extends
+            AbstractStatementSupport<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> {
+
+        public Definition() {
+            super(Rfc6020Mapping.Uses);
+        }
+
+        @Override
+        public QName parseArgumentValue(StmtContext<?, ?, ?> ctx, String value) {
+            return Utils.qNameFromArgument(ctx, value);
+        }
+
+        public void onStatementDeclared(Mutable<QName, UsesStatement, ?> usesNode) throws InferenceException {
+            ModelActionBuilder modifier = usesNode.newInferenceAction(ModelProcessingPhase.EffectiveModel);
+            final QName groupingName = usesNode.getStatementArgument();
+            final StatementSourceReference usesSource = usesNode.getStatementSourceReference();
+            final Prerequisite<?> targetPre = modifier.mutatesEffectiveCtx(usesNode.getParentContext());
+            final Prerequisite<EffectiveStatement<QName, GroupingStatement>> sourcePre = modifier.requiresEffective(
+                    usesNode, GroupingNamespace.class, groupingName);
+
+            modifier.apply(new InferenceAction() {
+
+                @Override
+                public void apply() throws InferenceException {
+                    Mutable<?, ?, ?> targetCtx = (Mutable<?, ?, ?>) targetPre.get();
+                    EffectiveStatement<QName, GroupingStatement> source = sourcePre.get();
+
+                    throw new UnsupportedOperationException("Copy of not not yet implemented.");
+                }
+
+                @Override
+                public void prerequisiteFailed(Collection<? extends Prerequisite<?>> failed) throws InferenceException {
+                    if(failed.contains(sourcePre)) {
+                        throw new InferenceException("Grouping " + groupingName + "was not found.", usesSource);
+                    }
+                    throw new InferenceException("Unknown error occured.", usesSource);
+                }
+
+            });
+
+        }
+
+        @Override
+        public UsesStatement createDeclared(StmtContext<QName, UsesStatement, ?> ctx) {
+            return new UsesStatementImpl(ctx);
+        }
+
+        @Override
+        public EffectiveStatement<QName, UsesStatement> createEffective(
+                StmtContext<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> ctx) {
+            throw new UnsupportedOperationException("Not implemented yet.");
+        }
+
+    }
+
+    @Override
+    public QName getName() {
+        return argument();
+    }
+
+    @Override
+    public WhenStatement getWhenStatement() {
+        return firstDeclared(WhenStatement.class);
+    }
+
+    @Override
+    public Collection<? extends IfFeatureStatement> getIfFeatures() {
+        return allDeclared(IfFeatureStatement.class);
+    }
+
+    @Override
+    public StatusStatement getStatus() {
+        return firstDeclared(StatusStatement.class);
+    }
+
+    @Override
+    public DescriptionStatement getDescription() {
+        return firstDeclared(DescriptionStatement.class);
+    }
+
+    @Override
+    public ReferenceStatement getReference() {
+        return firstDeclared(ReferenceStatement.class);
+    }
+
+    @Override
+    public Collection<? extends AugmentStatement> getAugments() {
+        return allDeclared(AugmentStatement.class);
+    }
+
+    @Override
+    public Collection<? extends RefineStatement> getRefines() {
+        return allDeclared(RefineStatement.class);
+    }
+
+    @Override
+    public QName argument() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public String rawArgument() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Collection<? extends DeclaredStatement<?>> declaredSubstatements() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public StatementDefinition statementDefinition() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public StatementSource getStatementSource() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java
new file mode 100644 (file)
index 0000000..101038d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.common.QName;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+
+public class Utils {
+
+
+    public static QName qNameFromArgument(StmtContext<?,?,?> ctx, String value) {
+        // TODO: Implement real parsing
+        String prefix = "";
+        ctx.getFromNamespace(PrefixToModule.class, prefix);
+
+        return QName.create(value);
+    }
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java
new file mode 100644 (file)
index 0000000..c16cd19
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.global;
+import static org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.sourceLocal;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+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.stmt.reactor.CrossSourceStatementReactor;
+
+public final class YangInferencePipeline {
+
+    public static final StatementSupportBundle LINKAGE_BUNDLE = StatementSupportBundle.builder()
+            .addSupport(new ModuleStatementSupport())
+            .addSupport(new NamespaceStatementImpl.Definition())
+            .addSupport(new ImportStatementDefinition())
+            .addSupport(new PrefixStatementImpl.Definition())
+            .addSupport(global(ModuleNamespace.class))
+            .addSupport(global(NamespaceToModule.class))
+            .addSupport(sourceLocal(ImportedModuleContext.class))
+            .build();
+
+    private static final StatementSupportBundle STMT_DEF_BUNDLE = StatementSupportBundle.derivedFrom(LINKAGE_BUNDLE).build();
+
+    private static final StatementSupportBundle FULL_DECL_BUNDLE = StatementSupportBundle.derivedFrom(STMT_DEF_BUNDLE).build();
+
+    public static final Map<ModelProcessingPhase, StatementSupportBundle> RFC6020_BUNDLES = ImmutableMap
+            .<ModelProcessingPhase, StatementSupportBundle> builder()
+            .put(ModelProcessingPhase.SourceLinkage, LINKAGE_BUNDLE)
+            .put(ModelProcessingPhase.StatementDefinition,STMT_DEF_BUNDLE)
+            .put(ModelProcessingPhase.FullDeclaration,FULL_DECL_BUNDLE)
+            .put(ModelProcessingPhase.EffectiveModel,FULL_DECL_BUNDLE)
+            .build();
+
+    public static final CrossSourceStatementReactor RFC6020_REACTOR = CrossSourceStatementReactor.builder()
+            .setBundle(ModelProcessingPhase.SourceLinkage, LINKAGE_BUNDLE)
+            .setBundle(ModelProcessingPhase.StatementDefinition,STMT_DEF_BUNDLE)
+            .setBundle(ModelProcessingPhase.FullDeclaration,FULL_DECL_BUNDLE)
+            .setBundle(ModelProcessingPhase.EffectiveModel,FULL_DECL_BUNDLE)
+            .build();
+
+    private YangInferencePipeline() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+}
index 461d8579f5d8717014112568e384cd3fe3701d71..ebe97ad6a17049514e09306c5f245e45406851d8 100644 (file)
@@ -8,9 +8,11 @@
 package org.opendaylight.yangtools.yang.parser.impl.util;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-
+import static org.junit.Assert.assertTrue;
 import java.io.InputStream;
 import org.junit.Test;
 
@@ -24,6 +26,8 @@ public class YangModelDependencyInfoTest {
         assertEquals("ietf-inet-types", info.getName());
         assertEquals("2010-09-24", info.getFormattedRevision());
         assertNotNull(info.getDependencies());
+
+        assertTrue(info.equals(info));
     }
 
     @Test
@@ -45,4 +49,25 @@ public class YangModelDependencyInfoTest {
         assertEquals("module-without-revision", info.getName());
         assertNull(info.getFormattedRevision());
     }
+
+    @Test
+    public void testEquals() {
+       InputStream stream1 = getClass().getResourceAsStream("/ietf/ietf-inet-types@2010-09-24.yang");
+        YangModelDependencyInfo info1 = YangModelDependencyInfo.fromInputStream(stream1);
+        InputStream stream2 = getClass().getResourceAsStream("/no-revision/module-without-revision.yang");
+        YangModelDependencyInfo info2 = YangModelDependencyInfo.fromInputStream(stream2);
+
+       assertTrue(info1.equals(info1));
+       assertFalse(info1.equals(null));
+        assertFalse(info1.equals(stream1));
+        assertFalse(info1.equals(info2));
+    }
+
+    @Test
+    public void testHashcode() {
+        InputStream stream = getClass().getResourceAsStream("/no-revision/module-without-revision.yang");
+        YangModelDependencyInfo info = YangModelDependencyInfo.fromInputStream(stream);
+
+        assertNotEquals("hashcode", 31, info.hashCode());
+    }
 }
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/ImportResolutionTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/ImportResolutionTest.java
new file mode 100644 (file)
index 0000000..afcd486
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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.stmt.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor.BuildAction;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+
+public class ImportResolutionTest {
+
+    private static final TestStatementSource ROOT_WITHOUT_IMPORT = new TestStatementSource("nature");
+    private static final TestStatementSource IMPORT_ROOT = new TestStatementSource("mammal","nature");
+    private static final TestStatementSource IMPORT_DERIVED = new TestStatementSource("human", "mammal");
+    private static final TestStatementSource IMPORT_SELF = new TestStatementSource("egocentric", "egocentric");
+    private static final TestStatementSource CICLE_YIN = new TestStatementSource("cycle-yin", "cycle-yang");
+    private static final TestStatementSource CICLE_YANG = new TestStatementSource("cycle-yang", "cycle-yin");
+
+
+    @Test
+    public void inImportOrderTest() throws SourceException, ReactorException {
+        BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor,ROOT_WITHOUT_IMPORT,IMPORT_ROOT,IMPORT_DERIVED);
+        EffectiveModelContext result = reactor.build();
+        assertNotNull(result);
+    }
+
+    @Test
+    public void inInverseOfImportOrderTest() throws SourceException, ReactorException {
+        BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor,IMPORT_DERIVED,IMPORT_ROOT,ROOT_WITHOUT_IMPORT);
+        EffectiveModelContext result = reactor.build();
+        assertNotNull(result);
+    }
+
+    @Test
+    public void missingImportedSourceTest() throws SourceException {
+        BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor,IMPORT_DERIVED,ROOT_WITHOUT_IMPORT);
+        try {
+            reactor.build();
+            fail("reactor.process should fail doe to misssing imported source");
+        } catch (ReactorException e) {
+            assertTrue(e instanceof SomeModifiersUnresolvedException);
+            assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+        }
+
+    }
+
+    @Test
+    public void circularImportsTest() throws SourceException {
+        BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor,CICLE_YIN,CICLE_YANG);
+        try {
+            reactor.build();
+            fail("reactor.process should fail doe to circular import");
+        } catch (ReactorException e) {
+            assertTrue(e instanceof SomeModifiersUnresolvedException);
+            assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+        }
+    }
+
+    @Test
+    public void selfImportTest() throws SourceException {
+        BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        addSources(reactor,IMPORT_SELF,IMPORT_ROOT,ROOT_WITHOUT_IMPORT);
+        try {
+            reactor.build();
+            fail("reactor.process should fail doe to self import");
+        } catch (ReactorException e) {
+            assertTrue(e instanceof SomeModifiersUnresolvedException);
+            assertEquals(ModelProcessingPhase.SourceLinkage,e.getPhase());
+        }
+    }
+
+
+    private void addSources(BuildAction reactor, TestStatementSource... sources) {
+        for(TestStatementSource source : sources) {
+            reactor.addSource(source);
+        }
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/TestStatementSource.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/TestStatementSource.java
new file mode 100644 (file)
index 0000000..6da6f06
--- /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.stmt.test;
+
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Import;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Module;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Namespace;
+import static org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping.Prefix;
+
+import java.util.Arrays;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
+import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
+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.spi.source.StatementWriter;
+
+class TestStatementSource implements StatementStreamSource {
+
+    private static final String NS_PREFIX = "urn:org:opendaylight:yangtools:test:";
+
+    private final String name;
+    private final List<String> imports;
+    private StatementWriter writer;
+    private StatementSourceReference REF = new StatementSourceReference() {
+
+        @Override
+        public StatementSource getStatementSource() {
+            return StatementSource.DECLARATION;
+        }
+    };
+
+
+    public TestStatementSource(String name, String... imports) {
+        this.name = name;
+        this.imports = Arrays.asList(imports);
+    }
+
+    @Override
+    public void writeFull(StatementWriter writer, QNameToStatementDefinition stmtDef, PrefixToModule prefixes)
+            throws SourceException {
+        this.writer = writer;
+        header();
+        extensions();
+        body();
+        end();
+
+    }
+
+
+
+    @Override
+    public void writeLinkage(StatementWriter writer, QNameToStatementDefinition stmtDef) throws SourceException {
+        this.writer = writer;
+        header().end();
+    }
+
+    @Override
+    public void writeLinkageAndStatementDefinitions(StatementWriter writer, QNameToStatementDefinition stmtDef,
+            PrefixToModule prefixes) throws SourceException {
+        this.writer = writer;
+        header();
+        extensions();
+        end();
+
+    }
+
+    protected void extensions() {
+        // TODO Auto-generated method stub
+
+    }
+
+    protected void body() {
+
+    }
+
+    TestStatementSource header() throws SourceException {
+        stmt(Module).arg(name); {
+            stmt(Namespace).arg(getNamespace()).end();
+            stmt(Prefix).arg(name).end();
+            for(String imp : imports)  {
+                stmt(Import).arg(imp);
+                    stmt(Prefix).arg(imp).end();
+                end();
+            }
+        }
+        return this;
+    }
+
+    private String getNamespace() {
+        return NS_PREFIX + name;
+    }
+
+    protected TestStatementSource arg(String arg) throws SourceException {
+        writer.argumentValue(arg, REF);
+        return this;
+    }
+
+    protected TestStatementSource stmt(Rfc6020Mapping stmt) throws SourceException {
+        writer.startStatement(stmt.getStatementName(), REF);
+        return this;
+    }
+
+    protected TestStatementSource end() throws SourceException {
+        writer.endStatement(REF);
+        return this;
+    }
+
+
+}