<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>
--- /dev/null
+<?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>
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+
+}
--- /dev/null
+/*
+ * 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();
+ */
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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)";
+ }
+
+}