Bug 2497: Added YIN Export for Effective Schema Context. 58/15258/7
authorTony Tkacik <ttkacik@cisco.com>
Thu, 29 Jan 2015 17:16:53 +0000 (18:16 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Tue, 24 Feb 2015 08:20:58 +0000 (09:20 +0100)
Added initial implementation of YIN schema export,
which uses current Schema Context and effective API
to infer model.

Once the parser will be updated to preserve declared model,
this implementation will be hugely simplified only to subset
of current implemention - which is implementation
of StatementTextWriter interface.

Change-Id: I2c57ab90b6cb9f42c6156253c8600709c19b349e
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
24 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]

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)";
+  }
+
+}