Merge "Fix supporting-node in topology model so it can actually be used."
authorRobert Varga <nite@hq.sk>
Wed, 25 Feb 2015 06:07:52 +0000 (06:07 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 25 Feb 2015 06:07:52 +0000 (06:07 +0000)
40 files changed:
yang/pom.xml
yang/yang-model-export/pom.xml [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBinary.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBits.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBoolean.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedDecimal.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedEnum.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedIdentityref.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInstanceIdentifier.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInteger.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedLeafref.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedString.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnion.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnsignedInteger.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/ExtensionStatement.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/NormalizatedDerivedType.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/Rfc6020ModuleWriter.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaContextEmitter.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaToStatementWriterAdaptor.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SingleModuleYinStatementWriter.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/StatementTextWriter.java [new file with mode: 0644]
yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/YinExportUtils.java [new file with mode: 0644]
yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/test/SimpleModuleTest.java [new file with mode: 0644]
yang/yang-model-export/src/test/resources/yang/ietf-inet-types@2010-09-24.yang [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractDeclaredStatement.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ImportedNamespaceContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/InferenceException.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelProcessingPhase.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceNotAvailableException.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ReactorException.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/SomeModifiersUnresolvedException.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementFactory.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java [new file with mode: 0644]

index b2c26631842b09e088070f835bb95462813d8109..a229553f39fe9466bf576498a7ddaa72835c2a19 100644 (file)
@@ -35,6 +35,7 @@
         <module>yang-model-util</module>
         <module>yang-parser-api</module>
         <module>yang-parser-impl</module>
+        <module>yang-model-export</module>
         <module>yang-data-composite-node</module>
     </modules>
     <build>
diff --git a/yang/yang-model-export/pom.xml b/yang/yang-model-export/pom.xml
new file mode 100644 (file)
index 0000000..31f8296
--- /dev/null
@@ -0,0 +1,74 @@
+<?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">
+
+    <parent>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yangtools-parent</artifactId>
+        <version>0.7.0-SNAPSHOT</version>
+        <relativePath>/../../common/parent/pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yang-model-export</artifactId>
+    <name>${project.artifactId}</name>
+    <description>${project.artifactId}</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-model-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-parser-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>xmlunit</groupId>
+            <artifactId>xmlunit</artifactId>
+            <version>1.5</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBinary.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBinary.java
new file mode 100644 (file)
index 0000000..e7da96d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedBinary extends NormalizatedDerivedType<BinaryTypeDefinition> implements BinaryTypeDefinition {
+
+    public DerivedBinary(final ExtendedType definition) {
+        super(BinaryTypeDefinition.class, definition);
+    }
+
+    @Override
+    BinaryTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedBinary(base);
+    }
+
+    @Override
+    public List<LengthConstraint> getLengthConstraints() {
+        return delegate().getLengthConstraints();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBits.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBits.java
new file mode 100644 (file)
index 0000000..b9aa628
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedBits extends NormalizatedDerivedType<BitsTypeDefinition> implements BitsTypeDefinition {
+
+    public DerivedBits(final ExtendedType definition) {
+        super(BitsTypeDefinition.class, definition);
+    }
+
+    @Override
+    BitsTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedBits(base);
+    }
+
+    @Override
+    public List<Bit> getBits() {
+        return getBaseType().getBits();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBoolean.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedBoolean.java
new file mode 100644 (file)
index 0000000..4be3ea2
--- /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.model.export;
+
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedBoolean extends NormalizatedDerivedType<BooleanTypeDefinition> implements BooleanTypeDefinition {
+
+    public DerivedBoolean(final ExtendedType definition) {
+        super(BooleanTypeDefinition.class, definition);
+    }
+
+    @Override
+    BooleanTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedBoolean(base);
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedDecimal.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedDecimal.java
new file mode 100644 (file)
index 0000000..ee2845f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedDecimal extends NormalizatedDerivedType<DecimalTypeDefinition> implements DecimalTypeDefinition {
+
+    public DerivedDecimal(final ExtendedType definition) {
+        super(DecimalTypeDefinition.class, definition);
+    }
+
+    @Override
+    DecimalTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedDecimal(base);
+    }
+
+    @Override
+    public List<RangeConstraint> getRangeConstraints() {
+        return delegate().getRangeConstraints();
+    }
+
+    @Override
+    public Integer getFractionDigits() {
+        return delegate().getFractionDigits();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedEnum.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedEnum.java
new file mode 100644 (file)
index 0000000..c030eed
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedEnum extends NormalizatedDerivedType<EnumTypeDefinition> implements EnumTypeDefinition {
+
+    public DerivedEnum(final ExtendedType definition) {
+        super(EnumTypeDefinition.class, definition);
+    }
+
+    @Override
+    EnumTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedEnum(base);
+    }
+
+    @Override
+    public List<EnumPair> getValues() {
+        return getBaseType().getValues();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedIdentityref.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedIdentityref.java
new file mode 100644 (file)
index 0000000..c17cf58
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.model.export;
+
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedIdentityref extends NormalizatedDerivedType<IdentityrefTypeDefinition> implements
+        IdentityrefTypeDefinition {
+
+    public DerivedIdentityref(final ExtendedType definition) {
+        super(IdentityrefTypeDefinition.class, definition);
+    }
+
+    @Override
+    IdentityrefTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedIdentityref(base);
+    }
+
+    @Override
+    public IdentitySchemaNode getIdentity() {
+        // FIXME: Is this really correct?
+        return getBaseType().getIdentity();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInstanceIdentifier.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInstanceIdentifier.java
new file mode 100644 (file)
index 0000000..1a065b5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.export;
+
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedInstanceIdentifier extends NormalizatedDerivedType<InstanceIdentifierTypeDefinition> implements
+        InstanceIdentifierTypeDefinition {
+
+    public DerivedInstanceIdentifier(final ExtendedType definition) {
+        super(InstanceIdentifierTypeDefinition.class, definition);
+    }
+
+    @Override
+    InstanceIdentifierTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedInstanceIdentifier(base);
+    }
+
+    @Override
+    public RevisionAwareXPath getPathStatement() {
+        throw new UnsupportedOperationException("Path statement is not part of instance-identifier type");
+    }
+
+    @Override
+    public boolean requireInstance() {
+        return getBaseType().requireInstance();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInteger.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedInteger.java
new file mode 100644 (file)
index 0000000..3709820
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedInteger extends NormalizatedDerivedType<IntegerTypeDefinition> implements IntegerTypeDefinition {
+
+    public DerivedInteger(final ExtendedType definition) {
+        super(IntegerTypeDefinition.class, definition);
+    }
+
+    @Override
+    IntegerTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedInteger(base);
+    }
+
+    @Override
+    public List<RangeConstraint> getRangeConstraints() {
+        return delegate().getRangeConstraints();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedLeafref.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedLeafref.java
new file mode 100644 (file)
index 0000000..e582956
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.model.export;
+
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedLeafref extends NormalizatedDerivedType<LeafrefTypeDefinition> implements LeafrefTypeDefinition {
+
+    public DerivedLeafref(final ExtendedType definition) {
+        super(LeafrefTypeDefinition.class, definition);
+    }
+
+    @Override
+    LeafrefTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedLeafref(base);
+    }
+
+    @Override
+    public RevisionAwareXPath getPathStatement() {
+        return getBaseType().getPathStatement();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedString.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedString.java
new file mode 100644 (file)
index 0000000..462092e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedString extends NormalizatedDerivedType<StringTypeDefinition> implements StringTypeDefinition {
+
+    public DerivedString(final ExtendedType definition) {
+        super(StringTypeDefinition.class, definition);
+    }
+
+    @Override
+    StringTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedString(base);
+    }
+
+    @Override
+    public List<LengthConstraint> getLengthConstraints() {
+        return delegate().getLengthConstraints();
+    }
+
+    @Override
+    public List<PatternConstraint> getPatternConstraints() {
+        return delegate().getPatternConstraints();
+    }
+
+
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnion.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnion.java
new file mode 100644 (file)
index 0000000..76da06f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedUnion extends NormalizatedDerivedType<UnionTypeDefinition> implements UnionTypeDefinition {
+
+    public DerivedUnion(final ExtendedType definition) {
+        super(UnionTypeDefinition.class, definition);
+    }
+
+    @Override
+    UnionTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedUnion(base);
+    }
+
+    @Override
+    public List<TypeDefinition<?>> getTypes() {
+        return getBaseType().getTypes();
+    }
+
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnsignedInteger.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/DerivedUnsignedInteger.java
new file mode 100644 (file)
index 0000000..5b531a7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.model.export;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+class DerivedUnsignedInteger extends NormalizatedDerivedType<UnsignedIntegerTypeDefinition> implements
+        UnsignedIntegerTypeDefinition {
+
+    public DerivedUnsignedInteger(final ExtendedType definition) {
+        super(UnsignedIntegerTypeDefinition.class, definition);
+    }
+
+    @Override
+    UnsignedIntegerTypeDefinition createDerived(final ExtendedType base) {
+        return new DerivedUnsignedInteger(base);
+    }
+
+    @Override
+    public List<RangeConstraint> getRangeConstraints() {
+        return delegate().getRangeConstraints();
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/ExtensionStatement.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/ExtensionStatement.java
new file mode 100644 (file)
index 0000000..16b195e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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.model.export;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+final class ExtensionStatement implements StatementDefinition {
+
+    private QName argumentName;
+    private QName statementName;
+    private boolean yinElement;
+
+    private ExtensionStatement(final ExtensionDefinition def) {
+        statementName = def.getQName();
+        argumentName = def.getArgument() != null ? QName.create(statementName, def.getArgument()) : null;
+        yinElement = def.isYinElement();
+    }
+
+    static StatementDefinition from(final ExtensionDefinition def) {
+        return new ExtensionStatement(def);
+    }
+
+    static Map<QName,StatementDefinition> mapFrom(final Collection<ExtensionDefinition> definitions) {
+        final HashMap<QName,StatementDefinition> ret = new HashMap<>(definitions.size());
+        for(final ExtensionDefinition def : definitions) {
+            final StatementDefinition value = from(def);
+            ret.put(value.getStatementName(), value);
+        }
+        return ret;
+    }
+
+    @Override
+    public QName getArgumentName() {
+        return argumentName;
+    }
+
+    @Override
+    public QName getStatementName() {
+        return statementName;
+    }
+
+    public boolean isArgumentYinElement() {
+        return yinElement;
+    }
+
+    @Override
+    public Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
+        throw new UnsupportedOperationException("Not defined");
+    }
+
+    @Override
+    public Class<? extends DeclaredStatement<?>> getEffectiveRepresentationClass() {
+        throw new UnsupportedOperationException("Not defined");
+    }
+
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/NormalizatedDerivedType.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/NormalizatedDerivedType.java
new file mode 100644 (file)
index 0000000..760e0df
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * 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.model.export;
+
+import com.google.common.base.Preconditions;
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+
+/**
+ *
+ * Implementations of derived type.
+ *
+ * This is set of utility classes which implements derived YANG type,
+ * preserving original implemented interface instead of {@link ExtendedType}
+ * which does not preserve final type of data.
+ *
+ *  FIXME: Lithium: Should be move to yang-model-util package or deprecated
+ * if linking parser is reworked to adhere to base type contract
+ */
+abstract class NormalizatedDerivedType<T extends TypeDefinition<T>> implements TypeDefinition<T> {
+
+    private final ExtendedType definition;
+    private final Class<T> publicType;
+
+    NormalizatedDerivedType(final Class<T> publicType, final ExtendedType delegate) {
+        this.definition = Preconditions.checkNotNull(delegate);
+        this.publicType = Preconditions.checkNotNull(publicType);
+    }
+
+    static TypeDefinition<?> from(final ExtendedType type) {
+        TypeDefinition<? extends TypeDefinition<?>> baseType = type;
+        while (baseType.getBaseType() != null) {
+            baseType = baseType.getBaseType();
+        }
+        if (baseType instanceof BinaryTypeDefinition) {
+            return new DerivedBinary(type);
+        }
+        if (baseType instanceof BooleanTypeDefinition) {
+            return new DerivedBoolean(type);
+        }
+        if (baseType instanceof DecimalTypeDefinition) {
+            return new DerivedDecimal(type);
+        }
+        if (baseType instanceof IdentityrefTypeDefinition) {
+            return new DerivedIdentityref(type);
+        }
+        if (baseType instanceof InstanceIdentifierTypeDefinition) {
+            return new DerivedInstanceIdentifier(type);
+        }
+        if (baseType instanceof IntegerTypeDefinition) {
+            return new DerivedInteger(type);
+        }
+        if (baseType instanceof LeafrefTypeDefinition) {
+            return new DerivedLeafref(type);
+        }
+        if (baseType instanceof UnsignedIntegerTypeDefinition) {
+            return new DerivedUnsignedInteger(type);
+        }
+        if (baseType instanceof StringTypeDefinition) {
+            return new DerivedString(type);
+        }
+        if(baseType instanceof UnionTypeDefinition) {
+            return new DerivedUnion(type);
+        }
+        if(baseType instanceof EnumTypeDefinition) {
+            return new DerivedEnum(type);
+        }
+        if(baseType instanceof BitsTypeDefinition) {
+            return new DerivedBits(type);
+        }
+        throw new IllegalArgumentException("Not supported base type of " + baseType.getClass());
+    }
+
+    @Override
+    public final QName getQName() {
+        return definition.getQName();
+    }
+
+    @Override
+    public final SchemaPath getPath() {
+        return definition.getPath();
+    }
+
+    @Override
+    public final List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return definition.getUnknownSchemaNodes();
+    }
+
+    @Override
+    public final String getDescription() {
+        return definition.getDescription();
+    }
+
+    @Override
+    public final String getReference() {
+        return definition.getReference();
+    }
+
+    @Override
+    public final String getUnits() {
+        return definition.getUnits();
+    }
+
+    @Override
+    public final Object getDefaultValue() {
+        return definition.getDefaultValue();
+    }
+
+    @Override
+    public final Status getStatus() {
+        return definition.getStatus();
+    }
+
+    @Override
+    public final T getBaseType() {
+        final TypeDefinition<?> base = definition.getBaseType();
+        if (publicType.isInstance(base)) {
+            return publicType.cast(base);
+        } else if (base instanceof ExtendedType) {
+            return createDerived((ExtendedType) base);
+        }
+        throw new IllegalStateException("Unsupported base type.");
+    }
+
+    protected ExtendedType delegate() {
+        return definition;
+    }
+
+    /**
+     *
+     * Creates derived type from supplied ExtendedType, which will implement
+     * proper {@link TypeDefinition} interface.
+     *
+     * @param base Base definition, which does not implement concrete API
+     * @return wrapper which implements proper subinterface of {@link TypeDefinition}.
+     */
+    abstract T createDerived(ExtendedType base);
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/Rfc6020ModuleWriter.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/Rfc6020ModuleWriter.java
new file mode 100644 (file)
index 0000000..9c1444a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * 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.model.export;
+
+import com.google.common.primitives.UnsignedInteger;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+interface Rfc6020ModuleWriter {
+
+    void endNode();
+
+    void startModuleNode(String identifier);
+
+    void startOrganizationNode(String input);
+
+    void startContactNode(String input);
+
+    void startDescriptionNode(String input);
+
+    void startUnitsNode(String input);
+
+    void startYangVersionNode(String input);
+
+    void startNamespaceNode(URI uri);
+
+    void startKeyNode(List<QName> keyList);
+
+    void startPrefixNode(String input);
+
+    void startFeatureNode(QName qName);
+
+    void startExtensionNode(QName qName);
+
+    void startArgumentNode(String input);
+
+    void startStatusNode(Status status);
+
+    void startTypeNode(QName qName);
+
+    void startLeafNode(QName qName);
+
+    void startContainerNode(QName qName);
+
+    void startGroupingNode(QName qName);
+
+    void startRpcNode(QName qName);
+
+    void startInputNode();
+
+    void startOutputNode();
+
+    void startLeafListNode(QName qName);
+
+    void startListNode(QName qName);
+
+    void startChoiceNode(QName qName);
+
+    void startCaseNode(QName qName);
+
+    void startNotificationNode(QName qName);
+
+    void startIdentityNode(QName qName);
+
+    void startBaseNode(QName qName);
+
+    void startTypedefNode(QName qName);
+
+    void startRevisionNode(Date date);
+
+    void startDefaultNode(String string);
+
+    void startMustNode(RevisionAwareXPath xpath);
+
+    void startErrorMessageNode(String input);
+
+    void startErrorAppTagNode(String input);
+
+    void startPatternNode(String regularExpression);
+
+    void startValueNode(Integer integer);
+
+    void startEnumNode(String name);
+
+    void startRequireInstanceNode(boolean require);
+
+    void startPathNode(RevisionAwareXPath revisionAwareXPath);
+
+    void startBitNode(String name);
+
+    void startPositionNode(UnsignedInteger position);
+
+    void startReferenceNode(String input);
+
+    void startRevisionDateNode(Date date);
+
+    void startImportNode(String moduleName);
+
+    void startUsesNode(QName groupingName);
+
+    void startAugmentNode(SchemaPath targetPath);
+
+    void startConfigNode(boolean config);
+
+    void startLengthNode(String lengthString);
+
+    void startMaxElementsNode(Integer max);
+
+    void startMinElementsNode(Integer min);
+
+    void startPresenceNode(boolean presence);
+
+    void startOrderedByNode(String ordering);
+
+    void startRangeNode(String rangeString);
+
+    void startRefineNode(SchemaPath path);
+
+    void startMandatoryNode(boolean mandatory);
+
+    void startAnyxmlNode(QName qName);
+
+    void startUnknownNode(StatementDefinition def);
+
+    void startUnknownNode(StatementDefinition def, String nodeParameter);
+
+    void startFractionDigitsNode(Integer fractionDigits);
+
+    void startYinElementNode(boolean yinElement);
+
+    void startWhenNode(RevisionAwareXPath revisionAwareXPath);
+
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaContextEmitter.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaContextEmitter.java
new file mode 100644 (file)
index 0000000..6ef96bf
--- /dev/null
@@ -0,0 +1,1206 @@
+/*
+ * 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.model.export;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.primitives.UnsignedInteger;
+import java.net.URI;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Deviation;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.MustDefinition;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
+import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.ExtendedType;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
+
+@Beta
+@NotThreadSafe
+class SchemaContextEmitter {
+
+    private final Rfc6020ModuleWriter writer;
+    private final boolean emitInstantiated;
+    private final boolean emitUses;
+    private final Map<QName, StatementDefinition> extensions;
+
+    SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions) {
+        this(writer, extensions,false, true);
+    }
+
+    SchemaContextEmitter(final Rfc6020ModuleWriter writer, final Map<QName, StatementDefinition> extensions, final boolean emitInstantiated, final boolean emitUses) {
+        this.writer = Preconditions.checkNotNull(writer);
+        this.emitInstantiated = emitInstantiated;
+        this.emitUses = emitUses;
+        this.extensions = Preconditions.checkNotNull(extensions);
+    }
+
+    static void writeToStatementWriter(final Module module, final SchemaContext ctx, final StatementTextWriter statementWriter) {
+        final Rfc6020ModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
+        final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
+        new SchemaContextEmitter(yangSchemaWriter,extensions).emitModule(module);
+    }
+
+    void emitModule(final Module input) {
+        writer.startModuleNode(input.getName());
+        emitModuleHeader(input);
+        emitLinkageNodes(input);
+        emitMetaNodes(input);
+        emitRevisionNodes(input);
+        emitBodyNodes(input);
+        writer.endNode();
+    }
+
+    private void emitModuleHeader(final Module input) {
+        emitYangVersionNode(input.getYangVersion());
+        emitNamespace(input.getNamespace());
+        emitPrefixNode(input.getPrefix());
+    }
+
+    @SuppressWarnings("unused")
+    private void emitSubmodule(final String input) {
+        /*
+         * FIXME: BUG-2444:  Implement submodule export
+         *
+         * submoduleHeaderNodes linkageNodes metaNodes revisionNodes bodyNodes
+         * writer.endNode();
+         */
+    }
+
+    @SuppressWarnings("unused")
+    private void emitSubmoduleHeaderNodes(final Module input) {
+        /*
+         * FIXME: BUG-2444:  Implement submodule headers properly
+         *
+         * :yangVersionNode //Optional
+         *
+         * :belongsToNode
+         */
+    }
+
+    private void emitMetaNodes(final Module input) {
+
+        emitOrganizationNode(input.getOrganization()); // FIXME: BUG-2444: Optional
+        emitContact(input.getContact()); // FIXME: BUG-2444: Optional
+        emitDescriptionNode(input.getDescription());
+        emitReferenceNode(input.getReference());
+    }
+
+    private void emitLinkageNodes(final Module input) {
+        for (final ModuleImport importNode : input.getImports()) {
+            emitImport(importNode);
+        }
+        /*
+         * FIXME: BUG-2444:  Emit include statements
+         */
+    }
+
+    private void emitRevisionNodes(final Module input) {
+        /*
+         * FIXME: BUG-2444:  emit revisions properly, when parsed model will provide enough
+         * information
+         */
+        emitRevision(input.getRevision());
+
+    }
+
+    private void emitBodyNodes(final Module input) {
+
+        for (final ExtensionDefinition extension : input.getExtensionSchemaNodes()) {
+            emitExtension(extension);
+        }
+        for (final FeatureDefinition definition : input.getFeatures()) {
+            emitFeature(definition);
+        }
+        for (final IdentitySchemaNode identity : input.getIdentities()) {
+            emitIdentity(identity);
+        }
+
+        emitDataNodeContainer(input);
+
+        for (final AugmentationSchema augmentation : input.getAugmentations()) {
+            emitAugment(augmentation);
+        }
+        for (final RpcDefinition rpc : input.getRpcs()) {
+            emitRpc(rpc);
+        }
+        for (final NotificationDefinition notification : input.getNotifications()) {
+            emitNotificationNode(notification);
+        }
+        for (final Deviation deviation : input.getDeviations()) {
+            emitDeviation(deviation);
+        }
+
+    }
+
+    private void emitDataNodeContainer(final DataNodeContainer input) {
+        for (final TypeDefinition<?> typedef : input.getTypeDefinitions()) {
+            emitTypedefNode(typedef);
+        }
+        for (final GroupingDefinition grouping : input.getGroupings()) {
+            emitGrouping(grouping);
+        }
+        for (final DataSchemaNode child : input.getChildNodes()) {
+            emitDataSchemaNode(child);
+        }
+        for (final UsesNode usesNode : input.getUses()) {
+            emitUsesNode(usesNode);
+        }
+    }
+
+    private void emitDataSchemaNode(final DataSchemaNode child) {
+        if (!emitInstantiated && (child.isAddedByUses() || child.isAugmenting())) {
+            // We skip instantiated nodes.
+            return;
+        }
+
+        if (child instanceof ContainerSchemaNode) {
+            emitContainer((ContainerSchemaNode) child);
+        } else if (child instanceof LeafSchemaNode) {
+            emitLeaf((LeafSchemaNode) child);
+        } else if (child instanceof LeafListSchemaNode) {
+            emitLeafList((LeafListSchemaNode) child);
+        } else if (child instanceof ListSchemaNode) {
+            emitList((ListSchemaNode) child);
+        } else if (child instanceof ChoiceNode) {
+            emitChoice((ChoiceNode) child);
+        } else if (child instanceof AnyXmlSchemaNode) {
+            emitAnyxml((AnyXmlSchemaNode) child);
+        } else {
+            throw new UnsupportedOperationException("Not supported DataSchemaNode type " + child.getClass());
+        }
+    }
+
+    private void emitYangVersionNode(final String input) {
+        writer.startYangVersionNode(input);
+        writer.endNode();
+    }
+
+    private void emitImport(final ModuleImport importNode) {
+        writer.startImportNode(importNode.getModuleName());
+        emitPrefixNode(importNode.getPrefix());
+        emitRevisionDateNode(importNode.getRevision());
+        writer.endNode();
+    }
+
+    @SuppressWarnings("unused")
+    private void emitInclude(final String input) {
+        /*
+         * FIXME: BUG-2444:  Implement proper export of include statements
+         * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
+         *
+         *
+         * :revisionDateNode :writer.endNode();)
+         */
+    }
+
+    private void emitNamespace(final URI uri) {
+        writer.startNamespaceNode(uri);
+        writer.endNode();
+
+    }
+
+    private void emitPrefixNode(final String input) {
+        writer.startPrefixNode(input);
+        writer.endNode();
+
+    }
+
+    @SuppressWarnings("unused")
+    private void emitBelongsTo(final String input) {
+        /*
+         * FIXME: BUG-2444:  Implement proper export of belongs-to statements
+         * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
+         *
+         *
+         * :writer.startBelongsToNode(IdentifierHelper.getIdentifier(String
+         * :input));
+         *
+         *
+         * :prefixNode
+         * :writer.endNode();
+         *
+         */
+
+    }
+
+    private void emitOrganizationNode(final String input) {
+        writer.startOrganizationNode(input);
+        writer.endNode();
+
+    }
+
+    private void emitContact(final String input) {
+        writer.startContactNode(input);
+        writer.endNode();
+
+    }
+
+    private void emitDescriptionNode(@Nullable final String input) {
+        if (!Strings.isNullOrEmpty(input)) {
+            writer.startDescriptionNode(input);
+            writer.endNode();
+        }
+    }
+
+    private void emitReferenceNode(@Nullable final String input) {
+        if (!Strings.isNullOrEmpty(input)) {
+            writer.startReferenceNode(input);
+            writer.endNode();
+        }
+    }
+
+    private void emitUnitsNode(@Nullable final String input) {
+        if (!Strings.isNullOrEmpty(input)) {
+            writer.startUnitsNode(input);
+            writer.endNode();
+        }
+    }
+
+    private void emitRevision(final Date date) {
+        writer.startRevisionNode(date);
+
+        //
+        // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: descriptionNode //FIXME: BUG-2444: Optional
+        // FIXME: BUG-2444: FIXME: BUG-2444: BUG-2417: referenceNode //FIXME: BUG-2444: Optional
+        writer.endNode();
+
+    }
+
+    private void emitRevisionDateNode(@Nullable final Date date) {
+        if (date != null) {
+            writer.startRevisionDateNode(date);
+            writer.endNode();
+        }
+    }
+
+    private void emitExtension(final ExtensionDefinition extension) {
+        writer.startExtensionNode(extension.getQName());
+        emitArgument(extension.getArgument(),extension.isYinElement());
+        emitStatusNode(extension.getStatus());
+        emitDescriptionNode(extension.getDescription());
+        emitReferenceNode(extension.getReference());
+        emitUnknownStatementNodes(extension.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitArgument(final @Nullable String input, final boolean yinElement) {
+        if (input != null) {
+            writer.startArgumentNode(input);
+            emitYinElement(yinElement);
+            writer.endNode();
+        }
+
+    }
+
+    private void emitYinElement(final boolean yinElement) {
+        writer.startYinElementNode(yinElement);
+        writer.endNode();
+
+    }
+
+    private void emitIdentity(final IdentitySchemaNode identity) {
+        writer.startIdentityNode(identity.getQName());
+        if (identity.getBaseIdentity() != null) {
+            emitBase(identity.getBaseIdentity().getQName());
+        }
+        emitStatusNode(identity.getStatus());
+        emitDescriptionNode(identity.getDescription());
+        emitReferenceNode(identity.getReference());
+        writer.endNode();
+
+    }
+
+    private void emitBase(final QName qName) {
+        writer.startBaseNode(qName);
+        writer.endNode();
+
+    }
+
+    private void emitFeature(final FeatureDefinition definition) {
+        writer.startFeatureNode(definition.getQName());
+
+        // FIXME: BUG-2444: FIXME: BUG-2444:  Expose ifFeature *(ifFeatureNode )
+        emitStatusNode(definition.getStatus());
+        emitDescriptionNode(definition.getDescription());
+        emitReferenceNode(definition.getReference());
+        writer.endNode();
+
+    }
+
+    @SuppressWarnings("unused")
+    private void emitIfFeature(final String input) {
+        /*
+         * FIXME: BUG-2444:  Implement proper export of include statements
+         * startIncludeNode(IdentifierHelper.getIdentifier(String :input));
+         *
+         */
+    }
+
+    private void emitTypedefNode(final TypeDefinition<?> typedef) {
+        writer.startTypedefNode(typedef.getQName());
+        // Differentiate between derived type and existing type
+        // name.
+        emitTypeNodeDerived(typedef);
+        emitUnitsNode(typedef.getUnits());
+        emitDefaultNode(typedef.getDefaultValue());
+        emitStatusNode(typedef.getStatus());
+        emitDescriptionNode(typedef.getDescription());
+        emitReferenceNode(typedef.getReference());
+        emitUnknownStatementNodes(typedef.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitTypeNode(final SchemaPath parentPath, final TypeDefinition<?> subtype) {
+        final SchemaPath path = subtype.getPath();
+        if (isPrefix(parentPath.getPathFromRoot(), path.getPathFromRoot())) {
+            emitTypeNodeDerived(subtype);
+        } else {
+            emitTypeNodeReferenced(subtype);
+        }
+    }
+
+    private void emitTypeNodeReferenced(final TypeDefinition<?> typeDefinition) {
+        writer.startTypeNode(typeDefinition.getQName());
+        writer.endNode();
+
+    }
+
+    private void emitTypeNodeDerived(final TypeDefinition<?> typeDefinition) {
+        final TypeDefinition<?> baseType;
+        if (typeDefinition.getBaseType() != null) {
+            baseType = typeDefinition.getBaseType();
+        } else {
+            baseType = typeDefinition;
+        }
+        writer.startTypeNode(baseType.getQName());
+        emitTypeBodyNodes(typeDefinition);
+        writer.endNode();
+
+    }
+
+    private void emitTypeBodyNodes(final TypeDefinition<?> typeDef) {
+        if (typeDef instanceof ExtendedType) {
+            emitTypeBodyNodes(NormalizatedDerivedType.from((ExtendedType) typeDef));
+        } else if (typeDef instanceof UnsignedIntegerTypeDefinition) {
+            emitUnsignedIntegerSpecification((UnsignedIntegerTypeDefinition) typeDef);
+        } else if (typeDef instanceof IntegerTypeDefinition) {
+            emitIntegerSpefication((IntegerTypeDefinition) typeDef);
+        } else if (typeDef instanceof DecimalTypeDefinition) {
+            emitDecimal64Specification((DecimalTypeDefinition) typeDef);
+        } else if (typeDef instanceof StringTypeDefinition) {
+            emitStringRestrictions((StringTypeDefinition) typeDef);
+        } else if (typeDef instanceof EnumTypeDefinition) {
+            emitEnumSpecification((EnumTypeDefinition) typeDef);
+        } else if (typeDef instanceof LeafrefTypeDefinition) {
+            emitLeafrefSpecification((LeafrefTypeDefinition) typeDef);
+        } else if (typeDef instanceof IdentityrefTypeDefinition) {
+            emitIdentityrefSpecification((IdentityrefTypeDefinition) typeDef);
+        } else if (typeDef instanceof InstanceIdentifierTypeDefinition) {
+            emitInstanceIdentifierSpecification((InstanceIdentifierTypeDefinition) typeDef);
+        } else if (typeDef instanceof BitsTypeDefinition) {
+            emitBitsSpecification((BitsTypeDefinition) typeDef);
+        } else if (typeDef instanceof UnionTypeDefinition) {
+            emitUnionSpecification((UnionTypeDefinition) typeDef);
+        } else if (typeDef instanceof BinaryTypeDefinition) {
+            // FIXME: BUG-2444:  Is this realy NOOP?
+            // should at least support length statement
+        } else if (typeDef instanceof BooleanTypeDefinition || typeDef instanceof EmptyTypeDefinition) {
+            // NOOP
+        } else {
+            throw new IllegalArgumentException("Not supported type " + typeDef.getClass());
+        }
+    }
+
+    private void emitIntegerSpefication(final IntegerTypeDefinition typeDef) {
+        emitRangeNodeOptional(typeDef.getRangeConstraints());
+    }
+
+    private void emitUnsignedIntegerSpecification(final UnsignedIntegerTypeDefinition typeDef) {
+        emitRangeNodeOptional(typeDef.getRangeConstraints());
+
+    }
+
+    private void emitRangeNodeOptional(final List<RangeConstraint> list) {
+        // FIXME: BUG-2444:  Wrong decomposition in API, should be LenghtConstraint
+        // which contains ranges.
+        if (!list.isEmpty()) {
+            writer.startRangeNode(toRangeString(list));
+            final RangeConstraint first = list.iterator().next();
+            emitErrorMessageNode(first.getErrorMessage());
+            emitErrorAppTagNode(first.getErrorAppTag());
+            emitDescriptionNode(first.getDescription());
+            emitReferenceNode(first.getReference());
+            writer.endNode();
+        }
+
+    }
+
+    private void emitDecimal64Specification(final DecimalTypeDefinition typeDefinition) {
+        emitFranctionDigitsNode(typeDefinition.getFractionDigits());
+        emitRangeNodeOptional(typeDefinition.getRangeConstraints());
+
+    }
+
+    private void emitFranctionDigitsNode(final Integer fractionDigits) {
+        writer.startFractionDigitsNode(fractionDigits);
+        writer.endNode();
+    }
+
+    private void emitStringRestrictions(final StringTypeDefinition typeDef) {
+
+        // FIXME: BUG-2444:  Wrong decomposition in API, should be LenghtConstraint
+        // which contains ranges.
+        emitLength(typeDef.getLengthConstraints());
+
+        for (final PatternConstraint pattern : typeDef.getPatternConstraints()) {
+            emitPatternNode(pattern);
+        }
+
+    }
+
+    private void emitLength(final List<LengthConstraint> list) {
+        if (!list.isEmpty()) {
+            writer.startLengthNode(toLengthString(list));
+            // FIXME: BUG-2444:  Workaround for incorrect decomposition in API
+            final LengthConstraint first = list.iterator().next();
+            emitErrorMessageNode(first.getErrorMessage());
+            emitErrorAppTagNode(first.getErrorAppTag());
+            emitDescriptionNode(first.getDescription());
+            emitReferenceNode(first.getReference());
+            writer.endNode();
+        }
+
+    }
+
+    private String toLengthString(final List<LengthConstraint> list) {
+        final StringBuilder lengthStr = new StringBuilder();
+        final Iterator<LengthConstraint> constIt = list.iterator();
+        while (constIt.hasNext()) {
+            final LengthConstraint current = constIt.next();
+            if (current.getMin() == current.getMax()) {
+                lengthStr.append(current.getMin());
+            } else {
+                lengthStr.append(current.getMin());
+                lengthStr.append("..");
+                lengthStr.append(current.getMax());
+            }
+            if (constIt.hasNext()) {
+                lengthStr.append("|");
+            }
+        }
+        return lengthStr.toString();
+    }
+
+    private String toRangeString(final List<RangeConstraint> list) {
+        final StringBuilder lengthStr = new StringBuilder();
+        final Iterator<RangeConstraint> constIt = list.iterator();
+        while (constIt.hasNext()) {
+            final RangeConstraint current = constIt.next();
+            if (current.getMin() == current.getMax()) {
+                lengthStr.append(current.getMin());
+            } else {
+                lengthStr.append(current.getMin());
+                lengthStr.append("..");
+                lengthStr.append(current.getMax());
+            }
+            if (constIt.hasNext()) {
+                lengthStr.append("|");
+            }
+        }
+        return lengthStr.toString();
+    }
+
+    private void emitPatternNode(final PatternConstraint pattern) {
+        writer.startPatternNode(pattern.getRegularExpression());
+        emitErrorMessageNode(pattern.getErrorMessage()); // FIXME: BUG-2444: Optional
+        emitErrorAppTagNode(pattern.getErrorAppTag()); // FIXME: BUG-2444: Optional
+        emitDescriptionNode(pattern.getDescription());
+        emitReferenceNode(pattern.getReference()); // FIXME: BUG-2444: Optional
+        writer.endNode();
+    }
+
+    private void emitDefaultNode(@Nullable final Object object) {
+        if (object != null) {
+            writer.startDefaultNode(object.toString());
+            writer.endNode();
+        }
+
+    }
+
+    private void emitEnumSpecification(final EnumTypeDefinition typeDefinition) {
+        for (final EnumPair enumValue : typeDefinition.getValues()) {
+            emitEnumNode(enumValue);
+        }
+    }
+
+    private void emitEnumNode(final EnumPair enumValue) {
+        writer.startEnumNode(enumValue.getName());
+        emitValueNode(enumValue.getValue());
+        emitStatusNode(enumValue.getStatus());
+        emitDescriptionNode(enumValue.getDescription());
+        emitReferenceNode(enumValue.getReference());
+        writer.endNode();
+    }
+
+    private void emitLeafrefSpecification(final LeafrefTypeDefinition typeDefinition) {
+        emitPathNode(typeDefinition.getPathStatement());
+        // FIXME: BUG-2444: requireInstanceNode /Optional removed with (RFC6020 - Errata ID
+        // 2949)
+        // Added in Yang 1.1
+    }
+
+    private void emitPathNode(final RevisionAwareXPath revisionAwareXPath) {
+        writer.startPathNode(revisionAwareXPath);
+        writer.endNode();
+    }
+
+    private void emitRequireInstanceNode(final boolean require) {
+        writer.startRequireInstanceNode(require);
+        writer.endNode();
+    }
+
+    private void emitInstanceIdentifierSpecification(final InstanceIdentifierTypeDefinition typeDefinition) {
+        emitRequireInstanceNode(typeDefinition.requireInstance());
+    }
+
+    private void emitIdentityrefSpecification(final IdentityrefTypeDefinition typeDefinition) {
+        emitBase(typeDefinition.getQName());
+    }
+
+    private void emitUnionSpecification(final UnionTypeDefinition typeDefinition) {
+        for (final TypeDefinition<?> subtype : typeDefinition.getTypes()) {
+            // FIXME: BUG-2444:  What if we have locally modified types here?
+            // is solution to look-up in schema path?
+            emitTypeNode(typeDefinition.getPath(), subtype);
+        }
+    }
+
+    private void emitBitsSpecification(final BitsTypeDefinition typeDefinition) {
+        for (final Bit bit : typeDefinition.getBits()) {
+            emitBit(bit);
+        }
+    }
+
+    private void emitBit(final Bit bit) {
+        writer.startBitNode(bit.getName());
+        emitPositionNode(bit.getPosition());
+        emitStatusNode(bit.getStatus());
+        emitDescriptionNode(bit.getDescription());
+        emitReferenceNode(bit.getReference());
+        writer.endNode();
+    }
+
+    private void emitPositionNode(@Nullable final Long position) {
+        if (position != null) {
+            writer.startPositionNode(UnsignedInteger.valueOf(position));
+            writer.endNode();
+        }
+    }
+
+    private void emitStatusNode(@Nullable final Status status) {
+        if (status != null) {
+            writer.startStatusNode(status);
+            writer.endNode();
+        }
+    }
+
+    private void emitConfigNode(final boolean config) {
+        writer.startConfigNode(config);
+        writer.endNode();
+    }
+
+    private void emitMandatoryNode(final boolean mandatory) {
+        writer.startMandatoryNode(mandatory);
+        writer.endNode();
+    }
+
+    private void emitPresenceNode(final boolean presence) {
+        writer.startPresenceNode(presence);
+        writer.endNode();
+    }
+
+    private void emitOrderedBy(final boolean userOrdered) {
+        if (userOrdered) {
+            writer.startOrderedByNode("user");
+        } else {
+            writer.startOrderedByNode("system");
+        }
+        writer.endNode();
+    }
+
+    private void emitMust(@Nullable final MustDefinition mustCondition) {
+        if(mustCondition != null && mustCondition.getXpath() != null) {
+            writer.startMustNode(mustCondition.getXpath());
+            emitErrorMessageNode(mustCondition.getErrorMessage());
+            emitErrorAppTagNode(mustCondition.getErrorAppTag());
+            emitDescriptionNode(mustCondition.getDescription());
+            emitReferenceNode(mustCondition.getReference());
+            writer.endNode();
+        }
+
+    }
+
+    private void emitErrorMessageNode(@Nullable final String input) {
+        if (input != null && !input.isEmpty()) {
+            writer.startErrorMessageNode(input);
+            writer.endNode();
+        }
+    }
+
+    private void emitErrorAppTagNode(final String input) {
+        if (input != null && !input.isEmpty()) {
+            writer.startErrorAppTagNode(input);
+            writer.endNode();
+        }
+    }
+
+    private void emitMinElementsNode(final Integer min) {
+        if (min != null) {
+            writer.startMinElementsNode(min);
+            writer.endNode();
+        }
+    }
+
+    private void emitMaxElementsNode(final Integer max) {
+        if (max != null) {
+            writer.startMaxElementsNode(max);
+            writer.endNode();
+        }
+    }
+
+    private void emitValueNode(@Nullable final Integer value) {
+        if (value != null) {
+            writer.startValueNode(value);
+            writer.endNode();
+        }
+    }
+
+    private void emitDocumentedNode(final DocumentedNode input) {
+        emitStatusNode(input.getStatus());
+        emitDescriptionNode(input.getDescription());
+        emitReferenceNode(input.getReference());
+    }
+
+    private void emitGrouping(final GroupingDefinition grouping) {
+        writer.startGroupingNode(grouping.getQName());
+        emitDocumentedNode(grouping);
+        emitDataNodeContainer(grouping);
+        emitUnknownStatementNodes(grouping.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitContainer(final ContainerSchemaNode child) {
+        writer.startContainerNode(child.getQName());
+
+        //
+
+        emitConstraints(child.getConstraints());
+        // FIXME: BUG-2444: whenNode //:Optional
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitMustNodes(child.getConstraints().getMustConstraints());
+        emitPresenceNode(child.isPresenceContainer());
+        emitConfigNode(child.isConfiguration());
+        emitDocumentedNode(child);
+        emitDataNodeContainer(child);
+        emitUnknownStatementNodes(child.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitConstraints(final ConstraintDefinition constraints) {
+        emitWhen(constraints.getWhenCondition());
+        for (final MustDefinition mustCondition : constraints.getMustConstraints()) {
+            emitMust(mustCondition);
+        }
+
+    }
+
+    private void emitLeaf(final LeafSchemaNode child) {
+        writer.startLeafNode(child.getQName());
+        emitWhen(child.getConstraints().getWhenCondition());
+        // FIXME: BUG-2444:  *(ifFeatureNode )
+        emitTypeNode(child.getPath(), child.getType());
+        emitUnitsNode(child.getUnits());
+        emitMustNodes(child.getConstraints().getMustConstraints());
+        emitDefaultNode(child.getDefault());
+        emitConfigNode(child.isConfiguration());
+        emitMandatoryNode(child.getConstraints().isMandatory());
+        emitDocumentedNode(child);
+        emitUnknownStatementNodes(child.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitLeafList(final LeafListSchemaNode child) {
+        writer.startLeafListNode(child.getQName());
+
+        emitWhen(child.getConstraints().getWhenCondition());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitTypeNode(child.getPath(), child.getType());
+        // FIXME: BUG-2444: unitsNode /Optional
+        emitMustNodes(child.getConstraints().getMustConstraints());
+        emitConfigNode(child.isConfiguration());
+
+        emitMinElementsNode(child.getConstraints().getMinElements());
+        emitMaxElementsNode(child.getConstraints().getMaxElements());
+        emitOrderedBy(child.isUserOrdered());
+        emitDocumentedNode(child);
+        emitUnknownStatementNodes(child.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitList(final ListSchemaNode child) {
+        writer.startListNode(child.getQName());
+        emitWhen(child.getConstraints().getWhenCondition());
+
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitMustNodes(child.getConstraints().getMustConstraints());
+        emitKey(child.getKeyDefinition());
+        // FIXME: BUG-2444: *(uniqueNode )
+        emitConfigNode(child.isConfiguration());
+        emitMinElementsNode(child.getConstraints().getMinElements());
+        emitMaxElementsNode(child.getConstraints().getMaxElements());
+        emitOrderedBy(child.isUserOrdered());
+        emitDocumentedNode(child);
+        emitDataNodeContainer(child);
+        emitUnknownStatementNodes(child.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitMustNodes(final Set<MustDefinition> mustConstraints) {
+        for (final MustDefinition must : mustConstraints) {
+            emitMust(must);
+        }
+    }
+
+    private void emitKey(final List<QName> keyList) {
+        if (keyList != null && !keyList.isEmpty()) {
+            writer.startKeyNode(keyList);
+            writer.endNode();
+        }
+    }
+
+    @SuppressWarnings("unused")
+    private void emitUnique(final String input) {
+        // FIXME: BUG-2444: writer.startUniqueNode(uniqueArgStr)); Nodeend
+
+    }
+
+    private void emitChoice(final ChoiceNode choice) {
+        writer.startChoiceNode(choice.getQName());
+        emitWhen(choice.getConstraints().getWhenCondition());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        // FIXME: BUG-2444: defaultNode //Optional
+        emitConfigNode(choice.isConfiguration());
+        emitMandatoryNode(choice.getConstraints().isMandatory());
+        emitDocumentedNode(choice);
+        for (final ChoiceCaseNode caze : choice.getCases()) {
+            // TODO: emit short case?
+            emitCaseNode(caze);
+        }
+        emitUnknownStatementNodes(choice.getUnknownSchemaNodes());
+        writer.endNode();
+    }
+
+    private void emitCaseNode(final ChoiceCaseNode caze) {
+        if (!emitInstantiated && caze.isAugmenting()) {
+            return;
+        }
+        writer.startCaseNode(caze.getQName());
+        emitWhen(caze.getConstraints().getWhenCondition());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitDocumentedNode(caze);
+        emitDataNodeContainer(caze);
+        emitUnknownStatementNodes(caze.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitAnyxml(final AnyXmlSchemaNode child) {
+        writer.startAnyxmlNode(child.getQName());
+
+        emitWhen(child.getConstraints().getWhenCondition());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitMustNodes(child.getConstraints().getMustConstraints());
+        emitConfigNode(child.isConfiguration());
+        emitMandatoryNode(child.getConstraints().isMandatory());
+        emitDocumentedNode(child);
+        emitUnknownStatementNodes(child.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitUsesNode(final UsesNode usesNode) {
+        if (emitUses && !usesNode.isAddedByUses() && !usesNode.isAugmenting()) {
+            writer.startUsesNode(usesNode.getGroupingPath().getLastComponent());
+            /*
+             * FIXME: BUG-2444:
+             *  whenNode /
+             *  *(ifFeatureNode )
+             * statusNode // Optional F
+             * : descriptionNode // Optional
+             * referenceNode // Optional
+             */
+            for (final Entry<SchemaPath, SchemaNode> refine : usesNode.getRefines().entrySet()) {
+                emitRefine(refine);
+            }
+            for (final AugmentationSchema aug : usesNode.getAugmentations()) {
+                emitUsesAugmentNode(aug);
+            }
+            writer.endNode();
+        }
+    }
+
+    private void emitRefine(final Entry<SchemaPath, SchemaNode> refine) {
+        final SchemaPath path = refine.getKey();
+        final SchemaNode value = refine.getValue();
+        writer.startRefineNode(path);
+
+        if (value instanceof LeafSchemaNode) {
+            emitRefineLeafNodes((LeafSchemaNode) value);
+        } else if (value instanceof LeafListSchemaNode) {
+            emitRefineLeafListNodes((LeafListSchemaNode) value);
+        } else if (value instanceof ListSchemaNode) {
+            emitRefineListNodes((ListSchemaNode) value);
+        } else if (value instanceof ChoiceNode) {
+            emitRefineChoiceNodes((ChoiceNode) value);
+        } else if (value instanceof ChoiceCaseNode) {
+            emitRefineCaseNodes((ChoiceCaseNode) value);
+        } else if (value instanceof ContainerSchemaNode) {
+            emitRefineContainerNodes((ContainerSchemaNode) value);
+        } else if (value instanceof AnyXmlSchemaNode) {
+            emitRefineAnyxmlNodes((AnyXmlSchemaNode) value);
+        }
+        writer.endNode();
+
+    }
+
+    private <T extends SchemaNode> T getOriginalChecked(final T value) {
+        final Optional<SchemaNode> original = SchemaNodeUtils.getOriginalIfPossible(value);
+        Preconditions.checkArgument(original.isPresent(), "Original unmodified version of node is not present.");
+        @SuppressWarnings("unchecked")
+        final T ret = (T) original.get();
+        return ret;
+    }
+
+    private void emitDocumentedNodeRefine(final DocumentedNode original, final DocumentedNode value) {
+        if (Objects.deepEquals(original.getDescription(), value.getDescription())) {
+            emitDescriptionNode(value.getDescription());
+        }
+        if (Objects.deepEquals(original.getReference(), value.getReference())) {
+            emitReferenceNode(value.getReference());
+        }
+    }
+
+    private void emitRefineContainerNodes(final ContainerSchemaNode value) {
+        final ContainerSchemaNode original = getOriginalChecked(value);
+
+        // emitMustNodes(child.getConstraints().getMustConstraints());
+        if (Objects.deepEquals(original.isPresenceContainer(), value.isPresenceContainer())) {
+            emitPresenceNode(value.isPresenceContainer());
+        }
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitRefineLeafNodes(final LeafSchemaNode value) {
+        final LeafSchemaNode original = getOriginalChecked(value);
+
+        // emitMustNodes(child.getConstraints().getMustConstraints());
+        if (Objects.deepEquals(original.getDefault(), value.getDefault())) {
+            emitDefaultNode(value.getDefault());
+        }
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        emitDocumentedNodeRefine(original, value);
+        if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
+            emitMandatoryNode(value.getConstraints().isMandatory());
+        }
+
+    }
+
+    private void emitRefineLeafListNodes(final LeafListSchemaNode value) {
+        final LeafListSchemaNode original = getOriginalChecked(value);
+
+        // emitMustNodes(child.getConstraints().getMustConstraints());
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
+            emitMinElementsNode(value.getConstraints().getMinElements());
+        }
+        if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
+            emitMaxElementsNode(value.getConstraints().getMaxElements());
+        }
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitRefineListNodes(final ListSchemaNode value) {
+        final ListSchemaNode original = getOriginalChecked(value);
+
+        // emitMustNodes(child.getConstraints().getMustConstraints());
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        if (Objects.deepEquals(original.getConstraints().getMinElements(), value.getConstraints().getMinElements())) {
+            emitMinElementsNode(value.getConstraints().getMinElements());
+        }
+        if (Objects.deepEquals(original.getConstraints().getMaxElements(), value.getConstraints().getMaxElements())) {
+            emitMaxElementsNode(value.getConstraints().getMaxElements());
+        }
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitRefineChoiceNodes(final ChoiceNode value) {
+        final ChoiceNode original = getOriginalChecked(value);
+
+        // FIXME: BUG-2444: defaultNode //FIXME: BUG-2444: Optional
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
+            emitMandatoryNode(value.getConstraints().isMandatory());
+        }
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitRefineCaseNodes(final ChoiceCaseNode value) {
+        final ChoiceCaseNode original = getOriginalChecked(value);
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitRefineAnyxmlNodes(final AnyXmlSchemaNode value) {
+        final AnyXmlSchemaNode original = getOriginalChecked(value);
+
+        // FIXME: BUG-2444:  emitMustNodes(child.getConstraints().getMustConstraints());
+        if (Objects.deepEquals(original.isConfiguration(), value.isConfiguration())) {
+            emitConfigNode(value.isConfiguration());
+        }
+        if (Objects.deepEquals(original.getConstraints().isMandatory(), value.getConstraints().isMandatory())) {
+            emitMandatoryNode(value.getConstraints().isMandatory());
+        }
+        emitDocumentedNodeRefine(original, value);
+
+    }
+
+    private void emitUsesAugmentNode(final AugmentationSchema aug) {
+        /**
+         * differs only in location in schema, otherwise currently (as of
+         * RFC6020) it is same, so we could freely reuse path.
+         */
+        emitAugment(aug);
+    }
+
+    private void emitAugment(final AugmentationSchema augmentation) {
+        writer.startAugmentNode(augmentation.getTargetPath());
+        // FIXME: BUG-2444: whenNode //Optional
+        // FIXME: BUG-2444: *(ifFeatureNode )
+
+        emitStatusNode(augmentation.getStatus());
+        emitDescriptionNode(augmentation.getDescription());
+        emitReferenceNode(augmentation.getReference());
+        for(final UsesNode uses: augmentation.getUses()) {
+            emitUsesNode(uses);
+        }
+
+        for (final DataSchemaNode childNode : augmentation.getChildNodes()) {
+            if (childNode instanceof ChoiceCaseNode) {
+                emitCaseNode((ChoiceCaseNode) childNode);
+            } else {
+                emitDataSchemaNode(childNode);
+            }
+        }
+        emitUnknownStatementNodes(augmentation.getUnknownSchemaNodes());
+        writer.endNode();
+    }
+
+    private void emitUnknownStatementNodes(final List<UnknownSchemaNode> unknownNodes) {
+        for (final UnknownSchemaNode unknonwnNode : unknownNodes) {
+            emitUnknownStatementNode(unknonwnNode);
+        }
+    }
+
+    private void emitUnknownStatementNode(final UnknownSchemaNode node) {
+        final StatementDefinition def = getStatementChecked(node.getNodeType());
+        if (def.getArgumentName() == null) {
+            writer.startUnknownNode(def);
+        } else {
+            writer.startUnknownNode(def, node.getNodeParameter());
+        }
+        emitUnknownStatementNodes(node.getUnknownSchemaNodes());
+        writer.endNode();
+    }
+
+    private StatementDefinition getStatementChecked(final QName nodeType) {
+        final StatementDefinition ret = extensions.get(nodeType);
+        Preconditions.checkArgument(ret != null, "Unknown extension %s used during export.",nodeType);
+        return ret;
+    }
+
+    private void emitWhen(final RevisionAwareXPath revisionAwareXPath) {
+        if(revisionAwareXPath != null) {
+            writer.startWhenNode(revisionAwareXPath);
+            writer.endNode();
+        }
+                // FIXME: BUG-2444: descriptionNode //FIXME: BUG-2444: Optional
+        // FIXME: BUG-2444: referenceNode //FIXME: BUG-2444: Optional
+        // FIXME: BUG-2444: writer.endNode();)
+
+    }
+
+    private void emitRpc(final RpcDefinition rpc) {
+        writer.startRpcNode(rpc.getQName());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitStatusNode(rpc.getStatus());
+        emitDescriptionNode(rpc.getDescription());
+        emitReferenceNode(rpc.getReference());
+
+        for(final TypeDefinition<?> typedef : rpc.getTypeDefinitions()) {
+            emitTypedefNode(typedef);
+        }
+        for(final GroupingDefinition grouping : rpc.getGroupings()) {
+            emitGrouping(grouping);
+        }
+        emitInput(rpc.getInput());
+        emitOutput(rpc.getOutput());
+        emitUnknownStatementNodes(rpc.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+    private void emitInput(@Nullable final ContainerSchemaNode input) {
+        if (input != null) {
+            writer.startInputNode();
+            emitDataNodeContainer(input);
+            emitUnknownStatementNodes(input.getUnknownSchemaNodes());
+            writer.endNode();
+        }
+
+    }
+
+    private void emitOutput(@Nullable final ContainerSchemaNode input) {
+        if (input != null) {
+            writer.startOutputNode();
+            emitDataNodeContainer(input);
+            emitUnknownStatementNodes(input.getUnknownSchemaNodes());
+            writer.endNode();
+        }
+
+    }
+
+    private void emitNotificationNode(final NotificationDefinition notification) {
+        writer.startNotificationNode(notification.getQName());
+        // FIXME: BUG-2444: *(ifFeatureNode )
+        emitDocumentedNode(notification);
+        emitDataNodeContainer(notification);
+        emitUnknownStatementNodes(notification.getUnknownSchemaNodes());
+        writer.endNode();
+
+    }
+
+
+    //FIXME: Probably should be moved to utils bundle.
+    private static <T> boolean  isPrefix(final Iterable<T> prefix, final Iterable<T> other) {
+        final Iterator<T> prefixIt = prefix.iterator();
+        final Iterator<T> otherIt = other.iterator();
+        while(prefixIt.hasNext()) {
+            if(!otherIt.hasNext()) {
+                return false;
+            }
+            if(!Objects.deepEquals(prefixIt.next(), otherIt.next())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void emitDeviation(final Deviation deviation) {
+        /*
+         * FIXME: BUG-2444:  Deviation is not modeled properly and we are loosing lot of
+         * information in order to export it properly
+         *
+         * writer.startDeviationNode(deviation.getTargetPath());
+         *
+         * :descriptionNode //:Optional
+         *
+         *
+         * emitReferenceNode(deviation.getReference());
+         * :(deviateNotSupportedNode :1*(deviateAddNode :deviateReplaceNode
+         * :deviateDeleteNode)) :writer.endNode();
+         */
+    }
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaToStatementWriterAdaptor.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SchemaToStatementWriterAdaptor.java
new file mode 100644 (file)
index 0000000..8dbe7f4
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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.model.export;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.UnsignedInteger;
+import java.net.URI;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.concurrent.NotThreadSafe;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+@Beta
+@NotThreadSafe
+final class SchemaToStatementWriterAdaptor implements Rfc6020ModuleWriter {
+
+    private final StatementTextWriter writer;
+
+    private SchemaToStatementWriterAdaptor(final StatementTextWriter writer) {
+        this.writer = Preconditions.checkNotNull(writer);
+    }
+
+    public static final Rfc6020ModuleWriter from(final StatementTextWriter writer) {
+        return new SchemaToStatementWriterAdaptor(writer);
+    }
+
+    @Override
+    public void endNode() {
+        writer.endStatement();
+    }
+
+    @Override
+    public void startModuleNode(final String identifier) {
+        writer.startStatement(Rfc6020Mapping.Module);
+        writer.writeArgument(identifier);
+    }
+
+    @Override
+    public void startOrganizationNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Organization);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startContactNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Contact);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startDescriptionNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Description);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startReferenceNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Reference);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startUnitsNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Units);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startYangVersionNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.YangVersion);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startNamespaceNode(final URI uri) {
+        writer.startStatement(Rfc6020Mapping.Namespace);
+        writer.writeArgument(uri.toString());
+    }
+
+    @Override
+    public void startKeyNode(final List<QName> keyList) {
+        writer.startStatement(Rfc6020Mapping.Key);
+        final StringBuilder keyStr = new StringBuilder();
+        for (final QName item : keyList) {
+            keyStr.append(item.getLocalName());
+        }
+        writer.writeArgument(keyStr.toString());
+    }
+
+    @Override
+    public void startPrefixNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Prefix);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startFeatureNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Feature);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startExtensionNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Extension);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startArgumentNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.Argument);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startStatusNode(final Status status) {
+        writer.startStatement(Rfc6020Mapping.Status);
+        writer.writeArgument(status.toString().toLowerCase());
+    }
+
+    @Override
+    public void startTypeNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Type);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startLeafNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Leaf);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startContainerNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Container);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startGroupingNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Grouping);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startRpcNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Rpc);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startInputNode() {
+        writer.startStatement(Rfc6020Mapping.Input);
+    }
+
+    @Override
+    public void startOutputNode() {
+        writer.startStatement(Rfc6020Mapping.Output);
+    }
+
+    @Override
+    public void startLeafListNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.LeafList);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startListNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.List);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startChoiceNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Choice);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startCaseNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Case);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startNotificationNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Notification);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startIdentityNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Identity);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startBaseNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Base);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startTypedefNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Typedef);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startRevisionNode(final Date date) {
+        writer.startStatement(Rfc6020Mapping.Revision);
+        writer.writeArgument(SimpleDateFormatUtil.getRevisionFormat().format(date));
+    }
+
+    @Override
+    public void startDefaultNode(final String string) {
+        writer.startStatement(Rfc6020Mapping.Default);
+        writer.writeArgument(string);
+    }
+
+    @Override
+    public void startMustNode(final RevisionAwareXPath xpath) {
+        writer.startStatement(Rfc6020Mapping.Must);
+        writer.writeArgument(xpath);
+    }
+
+    @Override
+    public void startErrorMessageNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.ErrorMessage);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startErrorAppTagNode(final String input) {
+        writer.startStatement(Rfc6020Mapping.ErrorAppTag);
+        writer.writeArgument(input);
+    }
+
+    @Override
+    public void startPatternNode(final String regularExpression) {
+        writer.startStatement(Rfc6020Mapping.Pattern);
+        writer.writeArgument(regularExpression);
+    }
+
+    @Override
+    public void startValueNode(final Integer integer) {
+        writer.startStatement(Rfc6020Mapping.Value);
+        writer.writeArgument(integer.toString());
+    }
+
+    @Override
+    public void startEnumNode(final String name) {
+        writer.startStatement(Rfc6020Mapping.Enum);
+        writer.writeArgument(name);
+    }
+
+    @Override
+    public void startRequireInstanceNode(final boolean require) {
+        writer.startStatement(Rfc6020Mapping.RequireInstance);
+        writer.writeArgument(Boolean.toString(require));
+    }
+
+    @Override
+    public void startPathNode(final RevisionAwareXPath revisionAwareXPath) {
+        writer.startStatement(Rfc6020Mapping.Path);
+        writer.writeArgument(revisionAwareXPath);
+    }
+
+    @Override
+    public void startBitNode(final String name) {
+        writer.startStatement(Rfc6020Mapping.Bit);
+        writer.writeArgument(name);
+    }
+
+    @Override
+    public void startPositionNode(final UnsignedInteger position) {
+        writer.startStatement(Rfc6020Mapping.Position);
+        writer.writeArgument(position.toString());
+    }
+
+    @Override
+    public void startImportNode(final String moduleName) {
+        writer.startStatement(Rfc6020Mapping.Import);
+        writer.writeArgument(moduleName);
+    }
+
+    @Override
+    public void startRevisionDateNode(final Date date) {
+        writer.startStatement(Rfc6020Mapping.RevisionDate);
+        writer.writeArgument(SimpleDateFormatUtil.getRevisionFormat().format(date));
+    }
+
+    @Override
+    public void startUsesNode(final QName groupingName) {
+        writer.startStatement(Rfc6020Mapping.Uses);
+        writer.writeArgument(groupingName);
+    }
+
+    @Override
+    public void startAugmentNode(final SchemaPath targetPath) {
+        writer.startStatement(Rfc6020Mapping.Augment);
+        writer.writeArgument(targetPath);
+    }
+
+    @Override
+    public void startConfigNode(final boolean config) {
+        writer.startStatement(Rfc6020Mapping.Config);
+        writer.writeArgument(Boolean.toString(config));
+    }
+
+    @Override
+    public void startLengthNode(final String lengthString) {
+        writer.startStatement(Rfc6020Mapping.Length);
+        writer.writeArgument(lengthString);
+    }
+
+    @Override
+    public void startMaxElementsNode(final Integer max) {
+        writer.startStatement(Rfc6020Mapping.MaxElements);
+        writer.writeArgument(max.toString());
+    }
+
+    @Override
+    public void startMinElementsNode(final Integer min) {
+        writer.startStatement(Rfc6020Mapping.MinElements);
+        writer.writeArgument(min.toString());
+    }
+
+    @Override
+    public void startPresenceNode(final boolean presence) {
+        writer.startStatement(Rfc6020Mapping.Presence);
+        writer.writeArgument(Boolean.toString(presence));
+    }
+
+    @Override
+    public void startOrderedByNode(final String ordering) {
+        writer.startStatement(Rfc6020Mapping.OrderedBy);
+        writer.writeArgument(ordering);
+    }
+
+    @Override
+    public void startRangeNode(final String rangeString) {
+        writer.startStatement(Rfc6020Mapping.Range);
+        writer.writeArgument(rangeString);
+    }
+
+    @Override
+    public void startFractionDigitsNode(final Integer fractionDigits) {
+        writer.startStatement(Rfc6020Mapping.FractionDigits);
+        writer.writeArgument(fractionDigits.toString());
+    }
+
+    @Override
+    public void startRefineNode(final SchemaPath path) {
+        writer.startStatement(Rfc6020Mapping.Refine);
+        writer.writeArgument(path);
+    }
+
+    @Override
+    public void startMandatoryNode(final boolean mandatory) {
+        writer.startStatement(Rfc6020Mapping.Mandatory);
+        writer.writeArgument(Boolean.toString(mandatory));
+    }
+
+    @Override
+    public void startAnyxmlNode(final QName qName) {
+        writer.startStatement(Rfc6020Mapping.Anyxml);
+        writer.writeArgument(qName);
+    }
+
+    @Override
+    public void startUnknownNode(final StatementDefinition def) {
+        writer.startStatement(def);
+    }
+
+    @Override
+    public void startUnknownNode(final StatementDefinition def, final String nodeParameter) {
+        writer.startStatement(def);
+        writer.writeArgument(nodeParameter);
+    }
+
+    @Override
+    public void startYinElementNode(final boolean yinElement) {
+        writer.startStatement(Rfc6020Mapping.YinElement);
+        writer.writeArgument(Boolean.toString(yinElement));
+    }
+
+    @Override
+    public void startWhenNode(final RevisionAwareXPath revisionAwareXPath) {
+        writer.startStatement(Rfc6020Mapping.When);
+        writer.writeArgument(revisionAwareXPath);
+    }
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SingleModuleYinStatementWriter.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/SingleModuleYinStatementWriter.java
new file mode 100644 (file)
index 0000000..bbc059d
--- /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.model.export;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.net.URI;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.xml.XMLConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+@Beta
+@NotThreadSafe
+class SingleModuleYinStatementWriter implements StatementTextWriter {
+
+    private final XMLStreamWriter writer;
+    private final URI currentModuleNs;
+    private final BiMap<String, URI> prefixToNamespace;
+    private StatementDefinition currentStatement;
+
+    private SingleModuleYinStatementWriter(final XMLStreamWriter writer, final URI moduleNamespace,
+            final Map<String, URI> prefixToNs) {
+        super();
+        this.writer = writer;
+        this.currentModuleNs = moduleNamespace;
+        this.prefixToNamespace = HashBiMap.create(prefixToNs);
+        initializeYinNamespaceInXml();
+
+    }
+
+    private void initializeYinNamespaceInXml() {
+       try {
+            final String defaultNs = writer.getNamespaceContext().getNamespaceURI(XMLConstants.NULL_NS_URI);
+            if (defaultNs == null) {
+                writer.setDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
+            } else if (!YangConstants.RFC6020_YIN_NAMESPACE.toString().equals(defaultNs)) {
+                // FIXME: Implement support for exporting YIN as part of other XML document.
+                throw new UnsupportedOperationException("Not implemented support for nesting YIN in different XML element.");
+            }
+        } catch (final XMLStreamException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    static final StatementTextWriter create(final XMLStreamWriter writer, final URI moduleNs,
+            final Map<String, URI> prefixToNs) {
+        return new SingleModuleYinStatementWriter(writer, moduleNs, prefixToNs);
+    }
+
+    @Override
+    public void startStatement(final StatementDefinition statement) {
+        currentStatement = Preconditions.checkNotNull(statement);
+        try {
+            writeStartXmlElement(statement.getStatementName());
+            if (Rfc6020Mapping.Module.equals(statement) || Rfc6020Mapping.Submodule.equals(statement)) {
+                declareXmlNamespaces(prefixToNamespace);
+            }
+        } catch (final XMLStreamException e) {
+            // FIXME: Introduce proper expression
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public void endStatement() {
+        currentStatement = null;
+        try {
+            writeXmlEndElement();
+        } catch (final XMLStreamException e) {
+            // FIXME: Introduce proper expression
+            throw new IllegalStateException(e);
+        }
+    }
+
+    @Override
+    public void writeArgument(final String strRep) {
+        checkArgumentApplicable();
+        writeArgument0(strRep);
+    }
+
+    @Override
+    public void writeArgument(final QName value) {
+        checkArgumentApplicable();
+        final String valueStr = toPrefixedString(value);
+        writeArgument0(valueStr);
+    }
+
+    @Override
+    public void writeArgument(final SchemaPath targetPath) {
+        checkArgumentApplicable();
+        final StringBuilder valueStr = new StringBuilder();
+        if(targetPath.isAbsolute()) {
+            valueStr.append("/");
+        }
+        final Iterator<QName> argIt = targetPath.getPathFromRoot().iterator();
+        while(argIt.hasNext()) {
+            valueStr.append(toPrefixedString(argIt.next()));
+            if(argIt.hasNext()) {
+                valueStr.append("/");
+            }
+        }
+        writeArgument0(valueStr.toString());
+    }
+
+    @Override
+    public void writeArgument(final RevisionAwareXPath xpath) {
+        checkArgumentApplicable();
+        // FIXME: This implementation assumes prefixes are unchanged
+        // and were not changed in schema context.
+        writeArgument0(xpath.toString());
+    }
+
+
+    private void writeArgument0(final String strRep) {
+        try {
+            if (isArgumentYinElement(currentStatement)) {
+                writeStartXmlElement(currentStatement.getArgumentName());
+                writeXmlText(strRep);
+                writeXmlEndElement();
+            } else {
+                writeXmlArgument(currentStatement.getArgumentName(), strRep);
+            }
+        } catch (final XMLStreamException e) {
+            // FIXME: throw proper exception
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private boolean isArgumentYinElement(StatementDefinition currentStatement2) {
+        // FIXME: Implement this
+        return false;
+    }
+
+    private void checkArgumentApplicable() {
+        Preconditions.checkState(currentStatement != null, "No statement is opened.");
+        Preconditions.checkState(currentStatement.getArgumentName() != null, "Statement %s does not take argument.",
+                currentStatement.getArgumentName());
+    }
+
+
+
+    private String toPrefixedString(@Nullable final String prefix, final String localName) {
+        if (prefix == null || prefix.isEmpty()) {
+            return localName;
+        }
+        return prefix + ":" + localName;
+    }
+
+    private String toPrefixedString(final QName value) {
+        final URI valueNs = value.getNamespace();
+        final String valueLocal = value.getLocalName();
+        if (currentModuleNs.equals(valueNs)) {
+            return valueLocal;
+        }
+        final String prefix = ensureAndGetXmlNamespacePrefix(valueNs);
+        return toPrefixedString(prefix, valueLocal);
+    }
+
+    private @Nullable String ensureAndGetXmlNamespacePrefix(final URI namespace) {
+        if(YangConstants.RFC6020_YANG_NAMESPACE.equals(namespace)) {
+         // YANG namespace does not have prefix if used in arguments.
+            return null;
+
+        }
+        String prefix = writer.getNamespaceContext().getPrefix(namespace.toString());
+        if (prefix == null) {
+            // FIXME: declare prefix
+            prefix =prefixToNamespace.inverse().get(namespace);
+        }
+        if(prefix == null) {
+            throw new IllegalArgumentException("Namespace " + namespace + " is not bound to imported prefixes.");
+        }
+        return prefix;
+    }
+
+    private void writeXmlText(final String strRep) throws XMLStreamException {
+        writer.writeCharacters(strRep);
+    }
+
+    private void declareXmlNamespaces(final Map<String, URI> prefixToNamespace) {
+        try {
+            writer.writeDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
+            for (final Entry<String, URI> nsDeclaration : prefixToNamespace.entrySet()) {
+                writer.writeNamespace(nsDeclaration.getKey(), nsDeclaration.getValue().toString());
+            }
+        } catch (final XMLStreamException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private void writeXmlEndElement() throws XMLStreamException {
+        writer.writeEndElement();
+    }
+
+    private void writeXmlArgument(final QName qName, final String value) throws XMLStreamException {
+        writer.writeAttribute(qName.getNamespace().toString(), qName.getLocalName(), value);
+    }
+
+    private void writeStartXmlElement(final QName name) throws XMLStreamException {
+        writer.writeStartElement(name.getNamespace().toString(), name.getLocalName());
+    }
+
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/StatementTextWriter.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/StatementTextWriter.java
new file mode 100644 (file)
index 0000000..867c297
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.model.export;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+interface StatementTextWriter {
+
+
+    void startStatement(StatementDefinition statement);
+
+    void writeArgument(RevisionAwareXPath xpath);
+
+    void writeArgument(QName name);
+
+    void writeArgument(String argStr);
+
+    void writeArgument(SchemaPath targetPath);
+
+    void endStatement();
+
+}
diff --git a/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/YinExportUtils.java b/yang/yang-model-export/src/main/java/org/opendaylight/yangtools/yang/model/export/YinExportUtils.java
new file mode 100644 (file)
index 0000000..e518050
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.model.export;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Date;
+import java.util.Map;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class YinExportUtils {
+
+
+    private YinExportUtils() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+
+    /**
+     *
+     * Returns well-formed file name of YIN file as defined in RFC6020.
+     *
+     * @param name Module or submodule name
+     * @param revision Revision of module or submodule
+     * @return well-formed file name of YIN file as defined in RFC6020.
+     */
+    public static String wellFormedYinName(final String name, final Date revision) {
+        return wellFormedYinName(name, SimpleDateFormatUtil.getRevisionFormat().format(revision));
+    }
+
+    /**
+     *
+     * Returns well-formed file name of YIN file as defined in RFC6020.
+     *
+     * @param name
+     *            name Module or submodule name
+     * @param revision
+     *            Revision of module or submodule
+     * @return well-formed file name of YIN file as defined in RFC6020.
+     */
+    public static String wellFormedYinName(final String name, final String revision) {
+        return String.format("%s@%s.yin", Preconditions.checkNotNull(name),Preconditions.checkNotNull(revision));
+    }
+
+    /**
+     * Writes YIN representation of supplied module to specified output stream.
+     *
+     * @param ctx
+     *            Schema Context which contains module and extension definitions
+     *            to be used during export of model.
+     * @param module
+     *            Module to be exported.
+     * @param str
+     *            Output stream to which YIN representation of model will be
+     *            written.
+     * @throws XMLStreamException
+     */
+    public static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str) throws XMLStreamException {
+        final XMLOutputFactory factory = XMLOutputFactory.newFactory();
+        final XMLStreamWriter xmlStreamWriter = factory.createXMLStreamWriter(str);
+        writeModuleToOutputStream(ctx,module, xmlStreamWriter);
+    }
+
+    private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final XMLStreamWriter xmlStreamWriter) {
+        final URI moduleNs = module.getNamespace();
+        final Map<String, URI> prefixToNs = prefixToNamespace(ctx,module);
+        final StatementTextWriter yinWriter = SingleModuleYinStatementWriter.create(xmlStreamWriter, moduleNs, prefixToNs);
+        SchemaContextEmitter.writeToStatementWriter(module, ctx,yinWriter);
+    }
+
+    private static Map<String, URI> prefixToNamespace(final SchemaContext ctx, final Module module) {
+        final BiMap<String, URI> prefixMap = HashBiMap.create(module.getImports().size() + 1);
+        prefixMap.put(module.getPrefix(), module.getNamespace());
+        for(final ModuleImport imp : module.getImports()) {
+            final String prefix = imp.getPrefix();
+            final URI namespace = getModuleNamespace(ctx,imp.getModuleName());
+            prefixMap.put(prefix, namespace);
+        }
+        return prefixMap;
+    }
+
+    private static URI getModuleNamespace(final SchemaContext ctx, final String moduleName) {
+        for(final Module module : ctx.getModules()) {
+            if(moduleName.equals(module.getName())) {
+                return module.getNamespace();
+            }
+        }
+        throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
+    }
+
+}
diff --git a/yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/test/SimpleModuleTest.java b/yang/yang-model-export/src/test/java/org/opendaylight/yangtools/yang/model/export/test/SimpleModuleTest.java
new file mode 100644 (file)
index 0000000..1ce27d2
--- /dev/null
@@ -0,0 +1,98 @@
+package org.opendaylight.yangtools.yang.model.export.test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.export.YinExportUtils;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaListenerRegistration;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceListener;
+import org.opendaylight.yangtools.yang.model.repo.util.FilesystemSchemaSourceCache;
+import org.opendaylight.yangtools.yang.parser.repo.SharedSchemaRepository;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+
+public class SimpleModuleTest {
+
+    private static final File TEST_MODELS_FOLDER;
+
+    static {
+        try {
+            TEST_MODELS_FOLDER = new File(SimpleModuleTest.class.getResource("/yang/").toURI());
+        } catch (final URISyntaxException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    private SharedSchemaRepository schemaRegistry;
+    private FilesystemSchemaSourceCache<YangTextSchemaSource> fileSourceProvider;
+    private SchemaContextFactory schemaContextFactory;
+    private Set<SourceIdentifier> allTestSources;
+
+    @Before
+    public void init() {
+        schemaRegistry = new SharedSchemaRepository("test");
+        fileSourceProvider = new FilesystemSchemaSourceCache<YangTextSchemaSource>(schemaRegistry,
+                YangTextSchemaSource.class, TEST_MODELS_FOLDER);
+        final TextToASTTransformer astTransformer = TextToASTTransformer.create(schemaRegistry, schemaRegistry);
+        schemaRegistry.registerSchemaSourceListener(astTransformer);
+
+        schemaContextFactory = schemaRegistry.createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+        allTestSources = new HashSet<>();
+        final SchemaListenerRegistration reg = schemaRegistry.registerSchemaSourceListener(new SchemaSourceListener() {
+
+            @Override
+            public void schemaSourceUnregistered(final PotentialSchemaSource<?> source) {
+                // NOOP
+            }
+
+            @Override
+            public void schemaSourceRegistered(final Iterable<PotentialSchemaSource<?>> sources) {
+                for (final PotentialSchemaSource<?> source : sources) {
+                    allTestSources.add(source.getSourceIdentifier());
+                }
+            }
+
+            @Override
+            public void schemaSourceEncountered(final SchemaSourceRepresentation source) {
+                // NOOP
+            }
+        });
+        reg.close();
+    }
+
+    @Test
+    public void testGenerateAll() throws Exception {
+        testSetOfModules(allTestSources);
+    }
+
+    private void testSetOfModules(final Collection<SourceIdentifier> source) throws Exception {
+        final SchemaContext schemaContext = schemaContextFactory.createSchemaContext(source).checkedGet();
+        final File outDir = new File("target/collection");
+        outDir.mkdirs();
+        for (final Module module : schemaContext.getModules()) {
+            exportModule(schemaContext, module, outDir);
+        }
+    }
+
+    private File exportModule(final SchemaContext schemaContext, final Module module, final File outDir)
+            throws Exception {
+        final File outFile = new File(outDir, YinExportUtils.wellFormedYinName(module.getName(), module.getRevision()));
+        try (OutputStream output = new FileOutputStream(outFile)) {
+            YinExportUtils.writeModuleToOutputStream(schemaContext, module, output);
+        }
+        return outFile;
+    }
+}
diff --git a/yang/yang-model-export/src/test/resources/yang/ietf-inet-types@2010-09-24.yang b/yang/yang-model-export/src/test/resources/yang/ietf-inet-types@2010-09-24.yang
new file mode 100644 (file)
index 0000000..edd285d
--- /dev/null
@@ -0,0 +1,427 @@
+module ietf-inet-types {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types";
+  prefix "inet";
+
+  organization
+   "IETF NETMOD (NETCONF Data Modeling Language) Working Group";
+
+  contact
+   "WG Web:   <http://tools.ietf.org/wg/netmod/>
+    WG List:  <mailto:netmod@ietf.org>
+
+    WG Chair: David Partain
+              <mailto:david.partain@ericsson.com>
+
+    WG Chair: David Kessens
+              <mailto:david.kessens@nsn.com>
+
+    Editor:   Juergen Schoenwaelder
+              <mailto:j.schoenwaelder@jacobs-university.de>";
+
+  description
+   "This module contains a collection of generally useful derived
+    YANG data types for Internet addresses and related things.
+
+    Copyright (c) 2010 IETF Trust and the persons identified as
+    authors of the code.  All rights reserved.
+
+
+
+    Redistribution and use in source and binary forms, with or without
+    modification, is permitted pursuant to, and subject to the license
+    terms contained in, the Simplified BSD License set forth in Section
+    4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
+    (http://trustee.ietf.org/license-info).
+
+    This version of this YANG module is part of RFC 6021; see
+    the RFC itself for full legal notices.";
+
+  revision 2010-09-24 {
+    description
+     "Initial revision.";
+    reference
+     "RFC 6021: Common YANG Data Types";
+  }
+
+  /*** collection of protocol field related types ***/
+
+  typedef ip-version {
+    type enumeration {
+      enum unknown {
+        value "0";
+        description
+         "An unknown or unspecified version of the Internet protocol.";
+      }
+      enum ipv4 {
+        value "1";
+        description
+         "The IPv4 protocol as defined in RFC 791.";
+      }
+      enum ipv6 {
+        value "2";
+        description
+         "The IPv6 protocol as defined in RFC 2460.";
+      }
+    }
+    description
+     "This value represents the version of the IP protocol.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetVersion textual convention of the SMIv2.";
+    reference
+     "RFC  791: Internet Protocol
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  typedef dscp {
+    type uint8 {
+      range "0..63";
+    }
+    description
+     "The dscp type represents a Differentiated Services Code-Point
+      that may be used for marking packets in a traffic stream.
+
+      In the value set and its semantics, this type is equivalent
+      to the Dscp textual convention of the SMIv2.";
+    reference
+     "RFC 3289: Management Information Base for the Differentiated
+                Services Architecture
+      RFC 2474: Definition of the Differentiated Services Field
+                (DS Field) in the IPv4 and IPv6 Headers
+      RFC 2780: IANA Allocation Guidelines For Values In
+                the Internet Protocol and Related Headers";
+  }
+
+  typedef ipv6-flow-label {
+    type uint32 {
+      range "0..1048575";
+    }
+    description
+     "The flow-label type represents flow identifier or Flow Label
+      in an IPv6 packet header that may be used to discriminate
+      traffic flows.
+
+      In the value set and its semantics, this type is equivalent
+      to the IPv6FlowLabel textual convention of the SMIv2.";
+    reference
+     "RFC 3595: Textual Conventions for IPv6 Flow Label
+      RFC 2460: Internet Protocol, Version 6 (IPv6) Specification";
+  }
+
+  typedef port-number {
+    type uint16 {
+      range "0..65535";
+    }
+    description
+     "The port-number type represents a 16-bit port number of an
+      Internet transport layer protocol such as UDP, TCP, DCCP, or
+      SCTP.  Port numbers are assigned by IANA.  A current list of
+      all assignments is available from <http://www.iana.org/>.
+
+      Note that the port number value zero is reserved by IANA.  In
+      situations where the value zero does not make sense, it can
+      be excluded by subtyping the port-number type.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetPortNumber textual convention of the SMIv2.";
+    reference
+     "RFC  768: User Datagram Protocol
+      RFC  793: Transmission Control Protocol
+      RFC 4960: Stream Control Transmission Protocol
+      RFC 4340: Datagram Congestion Control Protocol (DCCP)
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  /*** collection of autonomous system related types ***/
+
+  typedef as-number {
+    type uint32;
+    description
+     "The as-number type represents autonomous system numbers
+      which identify an Autonomous System (AS).  An AS is a set
+      of routers under a single technical administration, using
+      an interior gateway protocol and common metrics to route
+      packets within the AS, and using an exterior gateway
+      protocol to route packets to other ASs'.  IANA maintains
+      the AS number space and has delegated large parts to the
+      regional registries.
+
+      Autonomous system numbers were originally limited to 16
+      bits.  BGP extensions have enlarged the autonomous system
+      number space to 32 bits.  This type therefore uses an uint32
+      base type without a range restriction in order to support
+      a larger autonomous system number space.
+
+      In the value set and its semantics, this type is equivalent
+      to the InetAutonomousSystemNumber textual convention of
+      the SMIv2.";
+    reference
+     "RFC 1930: Guidelines for creation, selection, and registration
+                of an Autonomous System (AS)
+      RFC 4271: A Border Gateway Protocol 4 (BGP-4)
+      RFC 4893: BGP Support for Four-octet AS Number Space
+      RFC 4001: Textual Conventions for Internet Network Addresses";
+  }
+
+  /*** collection of IP address and hostname related types ***/
+
+  typedef ip-address {
+    type union {
+      type inet:ipv4-address;
+      type inet:ipv6-address;
+    }
+    description
+     "The ip-address type represents an IP address and is IP
+      version neutral.  The format of the textual representations
+      implies the IP version.";
+  }
+
+  typedef ipv4-address {
+    type string {
+      pattern
+        '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+      +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+      + '(%[\p{N}\p{L}]+)?';
+    }
+    description
+      "The ipv4-address type represents an IPv4 address in
+       dotted-quad notation.  The IPv4 address may include a zone
+       index, separated by a % sign.
+
+       The zone index is used to disambiguate identical address
+       values.  For link-local addresses, the zone index will
+       typically be the interface index number or the name of an
+       interface.  If the zone index is not present, the default
+       zone of the device will be used.
+
+       The canonical format for the zone index is the numerical
+       format";
+  }
+
+  typedef ipv6-address {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(%[\p{N}\p{L}]+)?';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(%.+)?';
+    }
+    description
+     "The ipv6-address type represents an IPv6 address in full,
+      mixed, shortened, and shortened-mixed notation.  The IPv6
+      address may include a zone index, separated by a % sign.
+
+
+
+
+
+      The zone index is used to disambiguate identical address
+      values.  For link-local addresses, the zone index will
+      typically be the interface index number or the name of an
+      interface.  If the zone index is not present, the default
+      zone of the device will be used.
+
+      The canonical format of IPv6 addresses uses the compressed
+      format described in RFC 4291, Section 2.2, item 2 with the
+      following additional rules: the :: substitution must be
+      applied to the longest sequence of all-zero 16-bit chunks
+      in an IPv6 address.  If there is a tie, the first sequence
+      of all-zero 16-bit chunks is replaced by ::.  Single
+      all-zero 16-bit chunks are not compressed.  The canonical
+      format uses lowercase characters and leading zeros are
+      not allowed.  The canonical format for the zone index is
+      the numerical format as described in RFC 4007, Section
+      11.2.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture
+      RFC 4007: IPv6 Scoped Address Architecture
+      RFC 5952: A Recommendation for IPv6 Address Text Representation";
+  }
+
+  typedef ip-prefix {
+    type union {
+      type inet:ipv4-prefix;
+      type inet:ipv6-prefix;
+    }
+    description
+     "The ip-prefix type represents an IP prefix and is IP
+      version neutral.  The format of the textual representations
+      implies the IP version.";
+  }
+
+  typedef ipv4-prefix {
+    type string {
+      pattern
+         '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}'
+       +  '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
+       + '/(([0-9])|([1-2][0-9])|(3[0-2]))';
+    }
+    description
+     "The ipv4-prefix type represents an IPv4 address prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal to 32.
+
+
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The canonical format of an IPv4 prefix has all bits of
+      the IPv4 address set to zero that are not part of the
+      IPv4 prefix.";
+  }
+
+  typedef ipv6-prefix {
+    type string {
+      pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}'
+            + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|'
+            + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}'
+            + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))'
+            + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))';
+      pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|'
+            + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)'
+            + '(/.+)';
+    }
+    description
+     "The ipv6-prefix type represents an IPv6 address prefix.
+      The prefix length is given by the number following the
+      slash character and must be less than or equal 128.
+
+      A prefix length value of n corresponds to an IP address
+      mask that has n contiguous 1-bits from the most
+      significant bit (MSB) and all other bits set to 0.
+
+      The IPv6 address should have all bits that do not belong
+      to the prefix set to zero.
+
+      The canonical format of an IPv6 prefix has all bits of
+      the IPv6 address set to zero that are not part of the
+      IPv6 prefix.  Furthermore, IPv6 address is represented
+      in the compressed format described in RFC 4291, Section
+      2.2, item 2 with the following additional rules: the ::
+      substitution must be applied to the longest sequence of
+      all-zero 16-bit chunks in an IPv6 address.  If there is
+      a tie, the first sequence of all-zero 16-bit chunks is
+      replaced by ::.  Single all-zero 16-bit chunks are not
+      compressed.  The canonical format uses lowercase
+      characters and leading zeros are not allowed.";
+    reference
+     "RFC 4291: IP Version 6 Addressing Architecture";
+  }
+
+
+  /*** collection of domain name and URI types ***/
+
+  typedef domain-name {
+    type string {
+      pattern '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*'
+           +  '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)'
+           +  '|\.';
+      length "1..253";
+    }
+    description
+     "The domain-name type represents a DNS domain name.  The
+      name SHOULD be fully qualified whenever possible.
+
+      Internet domain names are only loosely specified.  Section
+      3.5 of RFC 1034 recommends a syntax (modified in Section
+      2.1 of RFC 1123).  The pattern above is intended to allow
+      for current practice in domain name use, and some possible
+      future expansion.  It is designed to hold various types of
+      domain names, including names used for A or AAAA records
+      (host names) and other records, such as SRV records.  Note
+      that Internet host names have a stricter syntax (described
+      in RFC 952) than the DNS recommendations in RFCs 1034 and
+      1123, and that systems that want to store host names in
+      schema nodes using the domain-name type are recommended to
+      adhere to this stricter standard to ensure interoperability.
+
+      The encoding of DNS names in the DNS protocol is limited
+      to 255 characters.  Since the encoding consists of labels
+      prefixed by a length bytes and there is a trailing NULL
+      byte, only 253 characters can appear in the textual dotted
+      notation.
+
+      The description clause of schema nodes using the domain-name
+      type MUST describe when and how these names are resolved to
+      IP addresses.  Note that the resolution of a domain-name value
+      may require to query multiple DNS records (e.g., A for IPv4
+      and AAAA for IPv6).  The order of the resolution process and
+      which DNS record takes precedence can either be defined
+      explicitely or it may depend on the configuration of the
+      resolver.
+
+      Domain-name values use the US-ASCII encoding.  Their canonical
+      format uses lowercase US-ASCII characters.  Internationalized
+      domain names MUST be encoded in punycode as described in RFC
+      3492";
+    reference
+     "RFC  952: DoD Internet Host Table Specification
+      RFC 1034: Domain Names - Concepts and Facilities
+      RFC 1123: Requirements for Internet Hosts -- Application
+                and Support
+      RFC 2782: A DNS RR for specifying the location of services
+                (DNS SRV)
+      RFC 3492: Punycode: A Bootstring encoding of Unicode for
+                Internationalized Domain Names in Applications
+                (IDNA)
+      RFC 5891: Internationalizing Domain Names in Applications
+                (IDNA): Protocol";
+  }
+
+  typedef host {
+    type union {
+      type inet:ip-address;
+      type inet:domain-name;
+    }
+    description
+     "The host type represents either an IP address or a DNS
+      domain name.";
+  }
+
+  typedef uri {
+    type string;
+    description
+     "The uri type represents a Uniform Resource Identifier
+      (URI) as defined by STD 66.
+
+      Objects using the uri type MUST be in US-ASCII encoding,
+      and MUST be normalized as described by RFC 3986 Sections
+      6.2.1, 6.2.2.1, and 6.2.2.2.  All unnecessary
+      percent-encoding is removed, and all case-insensitive
+      characters are set to lowercase except for hexadecimal
+      digits, which are normalized to uppercase as described in
+      Section 6.2.2.1.
+
+      The purpose of this normalization is to help provide
+      unique URIs.  Note that this normalization is not
+      sufficient to provide uniqueness.  Two URIs that are
+      textually distinct after this normalization may still be
+      equivalent.
+
+      Objects using the uri type may restrict the schemes that
+      they permit.  For example, 'data:' and 'urn:' schemes
+      might not be appropriate.
+
+      A zero-length URI is not a valid URI.  This can be used to
+      express 'URI absent' where required.
+
+      In the value set and its semantics, this type is equivalent
+      to the Uri SMIv2 textual convention defined in RFC 5017.";
+    reference
+     "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+      RFC 3305: Report from the Joint W3C/IETF URI Planning Interest
+                Group: Uniform Resource Identifiers (URIs), URLs,
+                and Uniform Resource Names (URNs): Clarifications
+                and Recommendations
+      RFC 5017: MIB Textual Conventions for Uniform Resource
+                Identifiers (URIs)";
+  }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractDeclaredStatement.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractDeclaredStatement.java
new file mode 100644 (file)
index 0000000..01ca560
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+
+/**
+ * Utility abstract base class for implementing declared statements.
+ *
+ *
+ * @param <A> Argument type.
+ */
+public abstract class AbstractDeclaredStatement<A> implements DeclaredStatement<A> {
+
+
+    private final A argument;
+    private final String rawArgument;
+    private final ImmutableList<? extends DeclaredStatement<?>> substatements;
+    private final StatementDefinition definition;
+    private final StatementSource source;
+
+    protected AbstractDeclaredStatement(StmtContext<A,?,?> context) {
+        rawArgument = context.rawStatementArgument();
+        argument = context.getStatementArgument();
+        source = context.getStatementSource();
+        definition = context.getPublicDefinition();
+        /*
+         *  Collections.transform could not be used here, since it is lazily
+         *  transformed and retains pointer to original collection, which may
+         *  contains references to mutable context.
+         *
+         *  FluentIterable.tranform().toList() - actually performs transformation
+         *  and creates immutable list from transformed results.
+         */
+        substatements = FluentIterable.from(context.declaredSubstatements()).transform(StmtContextUtils.buildDeclared()).toList();
+    }
+
+    protected final <S extends DeclaredStatement<?>> S firstDeclared(Class<S> type) {
+        return type.cast(Iterables.find(substatements, Predicates.instanceOf(type)));
+    }
+
+    @Override
+    public String rawArgument() {
+        return rawArgument;
+    }
+
+    @Override
+    public A argument() {
+        return argument;
+    }
+
+    @Override
+    public StatementDefinition statementDefinition() {
+        return definition;
+    }
+
+    @Override
+    public Collection<? extends DeclaredStatement<?>> declaredSubstatements() {
+        return substatements;
+    }
+
+    @Override
+    public StatementSource getStatementSource() {
+        return source;
+    }
+
+    @SuppressWarnings("unchecked")
+    protected final <S extends DeclaredStatement<?>> Collection<? extends S> allDeclared(Class<S> type) {
+        return Collection.class.cast(Collections2.filter(substatements,Predicates.instanceOf(type)));
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java
new file mode 100644 (file)
index 0000000..b891518
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Preconditions;
+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.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+/**
+ *
+ * Class providing necessary support for processing YANG statement.
+ *
+ * This class is intended to be subclassed by developers, which want to
+ * introduce support of statement to parser.
+ *
+ * @param <A>
+ *            Argument type
+ * @param <D>
+ *            Declared Statement representation
+ * @param <E>
+ *            Effective Statement representation
+ */
+public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+        implements StatementDefinition, StatementFactory<A, D, E>, StatementSupport<A, D, E> {
+
+    private final StatementDefinition type;
+
+    protected AbstractStatementSupport(StatementDefinition publicDefinition) {
+        Preconditions.checkArgument(publicDefinition != this);
+        this.type = Preconditions.checkNotNull(publicDefinition);
+    }
+
+    @Override
+    public final QName getStatementName() {
+        return type.getStatementName();
+    }
+
+    @Override
+    public final QName getArgumentName() {
+        return type.getArgumentName();
+    }
+
+    @Override
+    public final Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
+        return type.getDeclaredRepresentationClass();
+    }
+
+    @Override
+    public final Class<? extends DeclaredStatement<?>> getEffectiveRepresentationClass() {
+        return type.getEffectiveRepresentationClass();
+    }
+
+    @Override
+    public final StatementDefinition getPublicView() {
+        return type;
+    }
+
+    @Override
+    public abstract A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value) throws SourceException;
+
+    @Override
+    public void onStatementAdded(StmtContext.Mutable<A, D, E> stmt) {
+        // NOOP for most implementations
+    };
+
+    /**
+     *
+     * {@inheritDoc}
+     *
+     * Subclasses of this class may override this method to perform actions on
+     * this event or register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     */
+    @Override
+    public void onLinkageDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException, SourceException {
+        // NOOP for most implementations
+    }
+
+    /**
+     *
+     * {@inheritDoc}
+     *
+     * Subclasses of this class may override this method to perform actions on
+     * this event or register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     */
+    @Override
+    public void onStatementDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException,
+            SourceException {
+        // NOOP for most implementations
+    }
+
+    /**
+     *
+     * {@inheritDoc}
+     *
+     * Subclasses of this class may override this method to perform actions on
+     * this event or register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     */
+    @Override
+    public void onFullDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException, SourceException {
+        // NOOP for most implementations
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ImportedNamespaceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ImportedNamespaceContext.java
new file mode 100644 (file)
index 0000000..6197562
--- /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.meta;
+
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+
+/**
+ *
+ * Special namespace which allows import of namespaces from other sources.
+ *
+ * <p>
+ * This namespace and its subclasses are used by model processor to
+ * link / import namespaces to context node from supplied {@link StmtContext}.
+ * <p>
+ * This abstraction allows for imports and includes be implement as derived
+ * namespaces of this, but is not tied only for import and include statements.
+ *
+ * @param <K> Imported context identifier
+ */
+public interface ImportedNamespaceContext<K> extends IdentifierNamespace<K, StmtContext<?, ?, ?>> {
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/InferenceException.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/InferenceException.java
new file mode 100644 (file)
index 0000000..8e5cce1
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.spi.meta;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+
+/**
+ *
+ * Thrown when there was inference error
+ *
+ */
+public class InferenceException extends SourceException {
+
+
+    private static final long serialVersionUID = 1L;
+
+    public InferenceException(@Nonnull String message, @Nonnull StatementSourceReference source, Throwable cause) {
+        super(message, source, cause);
+    }
+
+    public InferenceException(@Nonnull String message, @Nonnull StatementSourceReference source) {
+        super(message, source);
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java
new file mode 100644 (file)
index 0000000..68e4a51
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Supplier;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+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.StmtContext.Mutable;
+
+
+/**
+ * Builder for effective model inference action.
+ *
+ * Model inference action is core principle of transforming
+ * declared model into effective model.
+ *
+ * Since YANG allows forward references, some inference actions
+ * needs to be taken at later point, where reference is actually
+ * resolved. Referenced objects are not retrieved directly
+ * but are represented as {@link Prerequisite} (prerequisite) for
+ * inference action to be taken.
+ *
+ * Some existing YANG statements are more complex and also object,
+ * for which effective model may be inferred is also represented
+ * as {@link Prerequisite} which once, when reference is available
+ * will contain target context, which may be used for inference
+ * action.
+ *
+ * <h2>Implementing inference action</h2>
+ *
+ * Effective inference action could always be splitted into two
+ * separate tasks:
+ * <ol>
+ * <li>Declaration of inference action and its prerequisites</li>
+ * <li>Execution of inference action</li>
+ * </ol>
+ * In order to declare inference action following steps needs
+ * to be taken:
+ *
+ * <ol>
+ * <li>Use {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)} to obtain
+ * {@link ModelActionBuilder}.
+ * <li>Use builder to specify concrete prerequisites of inference action
+ * (other statements, values from identifier namespaces)
+ * <li>Use builder to specify concrete set of nodes (or forward references to nodes)
+ * which will inference action mutate.
+ * <li>Use {@link #apply(InferenceAction)} with {@link InferenceAction} implementation
+ * to register inference action.
+ * </ol>
+ *
+ * Action will be executed when:
+ * <ul>
+ * <li> {@link InferenceAction#apply()} - all prerequisites (and declared forward references) are met,
+ * action could dereference them and start applying changes.
+ * </li>
+ * <li>{@link InferenceAction#prerequisiteFailed(Collection)} - semantic parser finished all other satisfied
+ * inference actions and some of declared prerequisites was still not met.
+ * </li>
+ * </ul>
+ *
+ * TODO: Insert real word example
+ *
+ * <h2>Design notes</h2>
+ * {@link java.util.concurrent.Future} seems as viable and more standard
+ * alternative to {@link Prerequisite}, but futures also carries
+ * promise that resolution of it is carried in other
+ * thread, which will actually put additional constraints on
+ * semantic parser.
+ *
+ * Also listening on multiple futures is costly, so we opted
+ * out of future and designed API, which later may introduce
+ * futures.
+ *
+ */
+public interface ModelActionBuilder {
+
+    public interface Prerequisite<T> extends Supplier<T> {
+
+        /**
+         *
+         * Returns associated prerequisite once it is resolved.
+         *
+         * @return associated prerequisite once it is resolved.
+         *
+         */
+        @Override
+        public T get();
+
+        boolean isDone();
+
+    }
+
+    /**
+     * User-defined inference action.
+     *
+     */
+    public interface InferenceAction {
+
+        /**
+         * Invoked once all prerequisites were met and forward references
+         * were resolved and inference action should be applied.
+         *
+         * Implementors may do necessary changes to mutable objects
+         * which were declared.
+         *
+         * @throws InferenceException If inference action can not be processed.
+         *      Note that this exception be used for user to debug YANG sources,
+         *      so should provide helpful context to fix issue in sources.
+         */
+        void apply() throws InferenceException;
+
+        /**
+         * Invoked once one of prerequisites was not met,
+         * even after all other satifiable inference actions were processed.
+         *
+         * Implementors MUST throw {@link InferenceException} if semantic processing
+         * of model should be stopped and failed.
+         *
+         * List of failed prerequisites should be used to select right message / error
+         * type to debug problem in YANG sources.
+         *
+         * @throws InferenceException If inference action can not be processed.
+         *      Note that this exception be used for user to debug YANG sources,
+         *      so should provide helpful context to fix issue in sources.
+         */
+        void prerequisiteFailed(Collection<? extends Prerequisite<?>> failed) throws InferenceException;
+    }
+
+    @Nonnull <D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(StmtContext<?,? extends D,?> context);
+
+    @Nonnull <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<D> requiresDeclared(StmtContext<?,?,?> context,Class<N> namespace, K key);
+
+    @Nonnull <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<StmtContext<?, D, ?>>requiresDeclaredCtx(StmtContext<?,?,?> context,Class<N> namespace, K key);
+
+    @Nonnull <E extends EffectiveStatement<?,?>> Prerequisite<E> requiresEffective(StmtContext<?,?,? extends E> stmt);
+
+    @Nonnull <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<E> requiresEffective(StmtContext<?,?,?> context,Class<N> namespace, K key);
+
+    @Nonnull <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<StmtContext<?,?,E>> requiresEffectiveCtx(StmtContext<?,?,?> context,Class<N> namespace, K key);
+
+    @Nonnull <N extends IdentifierNamespace<? ,?>> Prerequisite<Mutable<?,?,?>> mutatesNs(Mutable<?,?, ?> ctx, Class<N> namespace);
+
+    @Nonnull <T extends Mutable<?,?,?>> Prerequisite<T> mutatesEffectiveCtx(T stmt);
+
+    @Nonnull  <K,E extends EffectiveStatement<?,?>,N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<Mutable<?,?,E>> mutatesEffectiveCtx(StmtContext<?,?,?> context,Class<N> namespace, K key);
+
+    void apply(InferenceAction action) throws InferenceException;
+
+    @Nonnull <A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> Prerequisite<StmtContext<A, D, E>> requiresCtx(StmtContext<A, D, E> context, ModelProcessingPhase phase);
+
+    @Nonnull <K, N extends StatementNamespace<K, ?, ? >> Prerequisite<StmtContext<?,?,?>> requiresCtx(StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase);
+
+    @Nonnull <C extends StmtContext.Mutable<?,?,?>, CT extends C> Prerequisite<C> mutatesCtx(CT root, ModelProcessingPhase phase);
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelProcessingPhase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelProcessingPhase.java
new file mode 100644 (file)
index 0000000..1bb6d82
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.meta;
+
+import javax.annotation.Nullable;
+
+public enum ModelProcessingPhase {
+
+    /**
+     *
+     * Cross-source relationship resolution phase.
+     * <p>
+     * In this phase of processing only statements which affects
+     * cross-source relationship (e.g. imports / includes)
+     * are processed.
+     * <p>
+     * At end of this phase all source related contexts should
+     * be bind to their imports and includes to allow
+     * visibility of custom defined statements in following
+     * phases.
+     */
+    SourceLinkage(null),
+    StatementDefinition(SourceLinkage),
+    FullDeclaration(StatementDefinition),
+    EffectiveModel(FullDeclaration);
+
+
+    private final ModelProcessingPhase previousPhase;
+
+    private ModelProcessingPhase(@Nullable ModelProcessingPhase previous) {
+        this.previousPhase = previous;
+    }
+
+    public ModelProcessingPhase getPreviousPhase() {
+        return previousPhase;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java
new file mode 100644 (file)
index 0000000..0f795cc
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+
+/**
+ * Definition / implementation of specific Identifier Namespace behaviour.
+ *
+ * Namespace behaviour is build on top of tree of {@link NamespaceStorageNode}
+ * which represents local context of one of types defined in {@link StorageNodeType}.
+ *
+ * For common behaviour models please use static factories {@link #global(Class)},
+ * {@link #sourceLocal(Class)} and {@link #treeScoped(Class)}.
+ *
+ * @param <K> Key type
+ * @param <V> Value type
+ * @param <N> Namespace Type
+ */
+public abstract class NamespaceBehaviour<K,V, N extends IdentifierNamespace<K, V>> implements Identifiable<Class<N>>{
+
+    public enum StorageNodeType {
+        Global,
+        SourceLocalSpecial,
+        StatementLocal
+    }
+
+    public interface Registry {
+
+        abstract <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type);
+
+    }
+
+    public interface NamespaceStorageNode {
+
+        StorageNodeType getStorageNodeType();
+
+        @Nullable NamespaceStorageNode getParentNamespaceStorage();
+
+        @Nullable  <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key);
+
+        @Nullable  <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value);
+
+    }
+
+    private final Class<N> identifier;
+
+
+    protected NamespaceBehaviour(Class<N> identifier) {
+        this.identifier = Preconditions.checkNotNull(identifier);
+    }
+
+    /**
+     *
+     * Creates global namespace behaviour for supplied namespace type.
+     *
+     * Global behaviour stores and loads all values from root {@link NamespaceStorageNode}
+     * with type of {@link StorageNodeType#Global}.
+     *
+     * @param identifier Namespace identifier.
+     * @return global namespace behaviour for supplied namespace type.
+     */
+    public static @Nonnull <K,V, N extends IdentifierNamespace<K, V>>  NamespaceBehaviour<K,V,N> global(Class<N> identifier) {
+        return new StorageSpecific<>(identifier, StorageNodeType.Global);
+    }
+
+    /**
+     *
+     * Creates source-local namespace behaviour for supplied namespace type.
+     *
+     * Source-local namespace behaviour stores and loads all values from closest
+     * {@link NamespaceStorageNode} ancestor with type of
+     * {@link StorageNodeType#SourceLocalSpecial}.
+     *
+     * @param identifier Namespace identifier.
+     * @return source-local namespace behaviour for supplied namespace type.
+     */
+    public static <K,V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K,V,N> sourceLocal(Class<N> identifier) {
+        return new StorageSpecific<>(identifier, StorageNodeType.SourceLocalSpecial);
+    }
+
+    /**
+    *
+    * Creates tree-scoped namespace behaviour for supplied namespace type.
+    *
+    * Tree-scoped namespace behaviour search for value in all storage nodes
+    * up to the root and stores values in supplied node.
+    *
+    * @param identifier Namespace identifier.
+    * @return tree-scoped namespace behaviour for supplied namespace type.
+    */
+    public static <K,V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K,V,N> treeScoped(Class<N> identifier) {
+        return new TreeScoped<>(identifier);
+    }
+
+    public abstract V getFrom(NamespaceStorageNode storage, K key);
+    public abstract void addTo(NamespaceStorageNode storage,K key,V value);
+
+
+    @Override
+    public Class<N> getIdentifier() {
+        return identifier;
+    }
+
+    protected final V getFromLocalStorage(NamespaceStorageNode storage, K key) {
+        return storage.getFromLocalStorage(getIdentifier(), key);
+    }
+
+    protected final void addToStorage(NamespaceStorageNode storage,K key,V value) {
+        storage.addToLocalStorage(getIdentifier(),key,value);
+    }
+
+    static class StorageSpecific<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+
+        StorageNodeType storageType;
+
+        public StorageSpecific(Class<N> identifier, StorageNodeType type) {
+            super(identifier);
+            storageType = Preconditions.checkNotNull(type);
+        }
+
+        @Override
+        public V getFrom(final NamespaceStorageNode storage, final K key) {
+            NamespaceStorageNode current = storage;
+            while(current.getParentNamespaceStorage() != null) {
+                current = current.getParentNamespaceStorage();
+            }
+            return getFromLocalStorage(current,key);
+        }
+
+        @Override
+        public void addTo(NamespaceBehaviour.NamespaceStorageNode storage, K key, V value) {
+            NamespaceStorageNode current = storage;
+            while(current.getStorageNodeType() != storageType) {
+                current = current.getParentNamespaceStorage();
+            }
+            addToStorage(current, key, value);
+        }
+
+    }
+
+    static class TreeScoped<K,V, N extends IdentifierNamespace<K, V>> extends NamespaceBehaviour<K, V, N> {
+
+        public TreeScoped(Class<N> identifier) {
+            super(identifier);
+        }
+
+        @Override
+        public V getFrom(final NamespaceStorageNode storage, final K key) {
+            NamespaceStorageNode current = storage;
+            while(current != null) {
+                final V val = getFromLocalStorage(current, key);
+                if(val != null) {
+                    return val;
+                }
+                current = current.getParentNamespaceStorage();
+            }
+            return null;
+        }
+
+        @Override
+        public void addTo(NamespaceStorageNode storage,K key, V value) {
+            addToStorage(storage, key, value);
+        }
+
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceNotAvailableException.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceNotAvailableException.java
new file mode 100644 (file)
index 0000000..40f8a4e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Preconditions;
+
+/**
+ *
+ * Thrown when identifier namespace is not available (supported)
+ * in specific model processing phase.
+ *
+ */
+public class NamespaceNotAvailableException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public NamespaceNotAvailableException(String message) {
+        super(Preconditions.checkNotNull(message));
+    }
+
+    public NamespaceNotAvailableException(String message, Throwable cause) {
+        super(Preconditions.checkNotNull(message), cause);
+    }
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ReactorException.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ReactorException.java
new file mode 100644 (file)
index 0000000..1ea15e2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.spi.meta;
+
+import com.google.common.base.Preconditions;
+
+
+public class ReactorException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+    private final ModelProcessingPhase phase;
+
+    public ReactorException(ModelProcessingPhase phase, String message, Throwable cause) {
+        super(message, cause);
+        this.phase = Preconditions.checkNotNull(phase);
+    }
+
+    public ReactorException(ModelProcessingPhase phase, String message) {
+        super(message);
+        this.phase = Preconditions.checkNotNull(phase);
+    }
+
+    public final ModelProcessingPhase getPhase() {
+        return phase;
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/SomeModifiersUnresolvedException.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/SomeModifiersUnresolvedException.java
new file mode 100644 (file)
index 0000000..169a75a
--- /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.meta;
+
+public class SomeModifiersUnresolvedException extends ReactorException {
+
+    private static final long serialVersionUID = 1L;
+
+    public SomeModifiersUnresolvedException(ModelProcessingPhase phase) {
+        super(phase,"Some of " + phase + " modifiers for statements were not resolved.");
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementFactory.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementFactory.java
new file mode 100644 (file)
index 0000000..1ee9f37
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.parser.spi.meta;
+
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+public interface StatementFactory<A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> {
+
+    D createDeclared(StmtContext<A,D,?> ctx);
+
+    E createEffective(StmtContext<A,D,E> ctx);
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementNamespace.java
new file mode 100644 (file)
index 0000000..02840c6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.meta;
+
+import javax.annotation.Nullable;
+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;
+
+public interface StatementNamespace<K, D extends DeclaredStatement<?>,E extends EffectiveStatement<?,D>>  extends IdentifierNamespace<K, E>  {
+
+    @Override
+    @Nullable E get(K key);
+
+    public interface TreeScoped<K, D extends DeclaredStatement<?>,E extends EffectiveStatement<?,D>> extends StatementNamespace<K,D,E> {
+
+        TreeScoped<K,D,E> getParentContext();
+
+    }
+
+    public interface TreeBased<K,D extends DeclaredStatement<?>,E extends EffectiveStatement<?,D>> {
+
+    }
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java
new file mode 100644 (file)
index 0000000..321c3e9
--- /dev/null
@@ -0,0 +1,116 @@
+package org.opendaylight.yangtools.yang.parser.spi.meta;
+
+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.parser.spi.source.SourceException;
+
+/**
+ *
+ * Support for processing concrete YANG statement.
+ *
+ * This interface is intended to be implemented by developers, which want to
+ * introduce support of statement to parser. Consider subclassing
+ * {@link AbstractStatementSupport} for easier implementation of this interface.
+ *
+ * @param <A>
+ *            Argument type
+ * @param <D>
+ *            Declared Statement representation
+ * @param <E>
+ *            Effective Statement representation
+ */
+public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends StatementDefinition, StatementFactory<A, D, E> {
+
+    /**
+     * Returns public statement definition, which will be present in builded statements.
+     *
+     * Public statement definition may be used to provide different implementation
+     * of statement definition, which will not retain any build specific data
+     * or context.
+     *
+     * @return public statement definition, which will be present in builded statements.
+     */
+     StatementDefinition getPublicView();
+
+    /**
+     *
+     * Parses textual representation of argument in object representation.
+     *
+     * @param ctx Context, which may be used to access source-specific namespaces
+     * required for parsing.
+     * @param value String representation of value, as was present in text source.
+     * @return Parsed value
+     */
+     A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value) throws SourceException;
+
+    /**
+     *
+     * Invoked when statement is added to build context.
+     *
+     * @param stmt
+     *            Context of added statement. No substatement are available.
+     */
+     void onStatementAdded(StmtContext.Mutable<A, D, E> stmt);
+
+    /**
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#StatementDefinition} phase.
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#StatementDefinition} phase, only substatements from
+     * this and previous phase are available.
+     *
+     * Implementation may use method to perform actions on this event or
+     * register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     * @param stmt
+     *            Context of added statement.
+     */
+     void onLinkageDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException,
+            SourceException;
+
+    /**
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#StatementDefinition} phase.
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#StatementDefinition} phase, only substatements from
+     * this phase are available.
+     *
+     * Implementation may use method to perform actions on this event or
+     * register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     * @param stmt
+     *            Context of added statement. Argument and statement parent is
+     *            accessible.
+     */
+     void onStatementDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException,
+            SourceException;
+
+    /**
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#FullDeclaration} phase.
+     *
+     * Invoked when statement is closed during
+     * {@link ModelProcessingPhase#FullDeclaration} phase, only substatements
+     * from this phase are available.
+     *
+     * Implementation may use method to perform actions on this event or
+     * register modification action using
+     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     *
+     *
+     * @param stmt
+     *            Context of added statement. Argument and statement parent is
+     *            accessible.
+     */
+     void onFullDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt) throws InferenceException,
+            SourceException;
+
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupportBundle.java
new file mode 100644 (file)
index 0000000..504a70d
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+
+public final class StatementSupportBundle implements Immutable,NamespaceBehaviour.Registry {
+
+    private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, ImmutableMap.<QName, StatementSupport<?, ?, ?>>of(), ImmutableMap.<Class<?>, NamespaceBehaviour<?, ?, ?>>of());
+
+    private final StatementSupportBundle parent;
+    private final ImmutableMap<QName, StatementSupport<?,?,?>> definitions;
+    private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions;
+
+    private StatementSupportBundle(StatementSupportBundle parent,
+            ImmutableMap<QName, StatementSupport<?, ?, ?>> statements,
+            ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces) {
+        this.parent = parent;
+        this.definitions = statements;
+        this.namespaceDefinitions = namespaces;
+    }
+
+    public static final Builder builder() {
+        return new Builder(EMPTY);
+    }
+
+    public static final Builder derivedFrom(StatementSupportBundle parent) {
+        return new Builder(parent);
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> namespace)
+            throws NamespaceNotAvailableException {
+        NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace);
+        if (potential != null) {
+            Preconditions.checkState(namespace.equals(potential.getIdentifier()));
+
+            /*
+             * Safe cast, previous checkState checks equivalence of key from
+             * which type argument are derived
+             */
+            @SuppressWarnings("unchecked")
+            NamespaceBehaviour<K, V, N> casted = (NamespaceBehaviour<K, V, N>) potential;
+            return casted;
+        }
+        if (parent != null) {
+            return parent.getNamespaceBehaviour(namespace);
+        }
+        return null;
+    }
+
+    public <K, V, N extends IdentifierNamespace<K, V>> boolean hasNamespaceBehaviour(Class<N> namespace) {
+        if (namespaceDefinitions.containsKey(namespace)) {
+            return true;
+        }
+        if (parent != null) {
+            return parent.hasNamespaceBehaviour(namespace);
+        }
+        return false;
+    }
+
+    public StatementSupport<?, ?,?> getStatementDefinition(QName stmtName) {
+        StatementSupport<?,?, ?> potential = definitions.get(stmtName);
+        if (potential != null) {
+            return potential;
+        }
+        if (parent != null) {
+            return parent.getStatementDefinition(stmtName);
+        }
+        return null;
+    }
+
+    public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> {
+
+        private final StatementSupportBundle parent;
+        private final Map<QName, StatementSupport<?,?,?>> statements = new HashMap<>();
+        private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>();
+
+        Builder(StatementSupportBundle parent) {
+            this.parent = parent;
+        }
+
+        public Builder addSupport(StatementSupport<?, ?,?> definition) {
+            QName identifier = definition.getStatementName();
+            Preconditions.checkState(!statements.containsKey(identifier), "Statement %s already defined.",identifier);
+            Preconditions.checkState(parent.getStatementDefinition(identifier) == null, "Statement %s already defined.",identifier);
+            statements.put(identifier, definition);
+            return this;
+        }
+
+       public <K, V, N extends IdentifierNamespace<K, V>> Builder addSupport(NamespaceBehaviour<K, V, N> namespaceSupport) {
+            Class<N> identifier = namespaceSupport.getIdentifier();
+            Preconditions.checkState(!namespaces.containsKey(identifier));
+            Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier));
+            namespaces.put(identifier, namespaceSupport);
+            return this;
+        }
+
+       @Override
+        public StatementSupportBundle build() {
+            return new StatementSupportBundle(parent, ImmutableMap.copyOf(statements), ImmutableMap.copyOf(namespaces));
+        }
+
+    }
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContext.java
new file mode 100644 (file)
index 0000000..124d6bf
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.meta;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+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.source.StatementSourceReference;
+
+
+public interface StmtContext<A,D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
+
+    @Nonnull StatementSource getStatementSource();
+
+    @Nonnull StatementSourceReference getStatementSourceReference();
+
+    @Nonnull StatementDefinition getPublicDefinition();
+
+    @Nullable StmtContext<?,?,?> getParentContext();
+
+    @Nullable String rawStatementArgument();
+
+    @Nullable A getStatementArgument();
+
+    @Nonnull <K,VT, V extends VT,N extends IdentifierNamespace<K, V>> VT getFromNamespace(Class<N> type, K key) throws NamespaceNotAvailableException;
+
+    @Nonnull StmtContext<?,?,?> getRoot();
+
+    @Nonnull Collection<? extends StmtContext<?,?,?>> declaredSubstatements();
+
+    D buildDeclared();
+
+    E buildEffective();
+
+    interface Mutable<A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> extends StmtContext<A,D,E> {
+
+        @Override
+        StmtContext.Mutable<?,?,?> getParentContext();
+
+        <K,V,VT extends V,N extends IdentifierNamespace<K, V>> void addToNs(Class<N> type, K key, VT value) throws NamespaceNotAvailableException;
+
+        @Override
+        StmtContext.Mutable<?,?,?> getRoot();
+
+        ModelActionBuilder newInferenceAction(ModelProcessingPhase phase);
+
+        <K,KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(Class<N> namepsace, KT key,
+                StmtContext<?, ?, ?> stmt);
+
+    }
+
+
+
+}
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java
new file mode 100644 (file)
index 0000000..9e3cd70
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.meta;
+
+import com.google.common.base.Function;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+public final class StmtContextUtils {
+
+    private static final Function<StmtContext<?, ?,?>, DeclaredStatement<?>> BUILD_DECLARED = new Function<StmtContext<?,?,?>, DeclaredStatement<?>>() {
+
+        @Override
+        public DeclaredStatement<?> apply(StmtContext<?,?,?> input) {
+            return input.buildDeclared();
+        }
+
+    };
+
+    private static final Function<StmtContext<?, ?,?>, EffectiveStatement<?,?>> BUILD_EFFECTIVE = new Function<StmtContext<?,?,?>, EffectiveStatement<?,?>>() {
+
+        @Override
+        public EffectiveStatement<?,?> apply(StmtContext<?,?,?> input) {
+            return input.buildEffective();
+        }
+
+    };
+
+    private StmtContextUtils() {
+        throw new UnsupportedOperationException("Utility class");
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static final <D extends DeclaredStatement<?>> Function<StmtContext<?, ? extends D, ?>, D> buildDeclared() {
+        return Function.class.cast(BUILD_DECLARED);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static final <E extends EffectiveStatement<?,?>> Function<StmtContext<?, ?,? extends E>, E> buildEffective() {
+        return Function.class.cast(BUILD_EFFECTIVE);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static final <AT,DT extends DeclaredStatement<AT>> AT firstAttributeOf(Iterable<? extends StmtContext<?,?,?>> contexts, Class<DT> declaredType) {
+        for(StmtContext<?, ?, ?> ctx : contexts) {
+            if(producesDeclared(ctx,declaredType)) {
+                return (AT) ctx.getStatementArgument();
+            }
+        }
+        return null;
+    }
+
+    public static final boolean producesDeclared(StmtContext<?, ?, ?> ctx, Class<? extends DeclaredStatement<?>> type) {
+        return type.isAssignableFrom(ctx.getPublicDefinition().getDeclaredRepresentationClass());
+    }
+
+
+
+}