* detailed action information. The argument is the name of the action.
*/
@Beta
-public interface ActionDefinition extends OperationDefinition {
-
+public interface ActionDefinition extends OperationDefinition, CopyableNode {
}
--- /dev/null
+/*
+ * Copyright (c) 2017 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.api;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Represents a node that can be added by uses or by augmentation.
+ */
+@Beta
+public interface CopyableNode {
+ /**
+ * Returns <code>true</code> if this node was added by augmentation,
+ * otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this node was added by augmentation,
+ * otherwise returns <code>false</code>
+ */
+ boolean isAugmenting();
+
+ /**
+ * Returns <code>true</code> if this node was added by uses statement,
+ * otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this node was added by uses statement,
+ * otherwise returns <code>false</code>
+ */
+ boolean isAddedByUses();
+}
* @see AnyXmlSchemaNode
* @see AnyDataSchemaNode
*/
-public interface DataSchemaNode extends SchemaNode {
- /**
- * Returns <code>true</code> if the data node was added by augmentation,
- * otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if the data node was added by augmentation,
- * otherwise returns <code>false</code>
- */
- boolean isAugmenting();
-
- /**
- * Returns <code>true</code> if the data node was added by uses statement,
- * otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if the data node was added by uses statement,
- * otherwise returns <code>false</code>
- */
- boolean isAddedByUses();
-
+public interface DataSchemaNode extends SchemaNode, CopyableNode {
/**
* Returns <code>true</code> if the data represents configuration data,
* otherwise returns <code>false</code>.
* Interface describing YANG 'notification' statement. The notification
* statement is used to define a NETCONF notification.
*/
-public interface NotificationDefinition extends SchemaNode, DataNodeContainer, AugmentationTarget {
+public interface NotificationDefinition extends SchemaNode, DataNodeContainer, AugmentationTarget, CopyableNode {
/**
* All implementations should override this method.
private void emitContainer(final ContainerSchemaNode child) {
super.writer.startContainerNode(child.getQName());
-
- //
-
emitConstraints(child.getConstraints());
// FIXME: BUG-2444: whenNode //:Optional
// FIXME: BUG-2444: *(ifFeatureNode )
}
private void emitAction(final ActionDefinition action) {
- // :FIXME add addedByUses & addedByAugmentation in API and perform
- // check here..
+ if (!super.emitInstantiated && (action.isAddedByUses() || action.isAugmenting())) {
+ // We skip instantiated nodes.
+ return;
+ }
super.writer.startActionNode(action.getQName());
emitOperationBody(action);
super.writer.endNode();
}
private void emitNotificationNode(final NotificationDefinition notification) {
- // :FIXME add addedByUses & addedByAugmentation in API and perform
- // check here..
+ if (!super.emitInstantiated && (notification.isAddedByUses() || notification.isAugmenting())) {
+ // We skip instantiated nodes.
+ return;
+ }
super.writer.startNotificationNode(notification.getQName());
// FIXME: BUG-2444: *(ifFeatureNode )
--- /dev/null
+/*
+ * Copyright (c) 2017 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 static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Map;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.common.YangVersion;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.export.SchemaContextEmitter.EffectiveSchemaContextEmitter;
+import org.opendaylight.yangtools.yang.model.export.test.YinExportTestUtils;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public class EffectiveSchemaContextEmitterTest {
+ @Test
+ public void test() throws Exception {
+ final SchemaContext schema = YangParserTestUtils.parseYangResource("/bugs/bug2444/yang/notification.yang");
+ assertNotNull(schema);
+
+ final File outDir = new File("target/bug2444-export");
+ outDir.mkdirs();
+
+ for (final Module module : schema.getModules()) {
+ exportModule(schema, module, outDir);
+ final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
+ try {
+ writeModuleToOutputStream(schema, module, bufferedOutputStream, false);
+ final String output = byteArrayOutputStream.toString();
+ assertNotNull(output);
+ assertNotEquals(0, output.length());
+
+ final Document doc = YinExportTestUtils
+ .loadDocument(String.format("/bugs/bug2444/yin-effective-emitter/%s@%s.yin", module.getName(),
+ SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision())));
+ assertXMLEquals(doc, output);
+ } finally {
+ byteArrayOutputStream.close();
+ bufferedOutputStream.close();
+ }
+ }
+ }
+
+ private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str,
+ final boolean emitInstantiated) throws XMLStreamException {
+ final XMLOutputFactory factory = XMLOutputFactory.newFactory();
+ final XMLStreamWriter xmlStreamWriter = factory.createXMLStreamWriter(str);
+ writeModuleToOutputStream(ctx, module, xmlStreamWriter, emitInstantiated);
+ xmlStreamWriter.flush();
+ }
+
+ private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module,
+ final XMLStreamWriter xmlStreamWriter, final boolean emitInstantiated) {
+ final URI moduleNs = module.getNamespace();
+ final Map<String, URI> prefixToNs = prefixToNamespace(ctx, module);
+ final StatementTextWriter statementWriter = SingleModuleYinStatementWriter.create(xmlStreamWriter, moduleNs,
+ prefixToNs);
+ final YangModuleWriter yangSchemaWriter = SchemaToStatementWriterAdaptor.from(statementWriter);
+ final Map<QName, StatementDefinition> extensions = ExtensionStatement.mapFrom(ctx.getExtensions());
+ new EffectiveSchemaContextEmitter(yangSchemaWriter, extensions,
+ YangVersion.parse(module.getYangVersion()).orElse(null), emitInstantiated).emitModule(module);
+ }
+
+ 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");
+ }
+
+ private static 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)) {
+ writeModuleToOutputStream(schemaContext, module, output, false);
+ }
+ return outFile;
+ }
+
+ private static void assertXMLEquals(final Document expectedXMLDoc, final String output)
+ throws SAXException, IOException {
+ final String expected = YinExportTestUtils.toString(expectedXMLDoc.getDocumentElement());
+
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setNormalize(true);
+ XMLUnit.setNormalizeWhitespace(true);
+
+ final Diff diff = new Diff(expected, output);
+ diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
+ XMLAssert.assertXMLEqual(diff, true);
+ }
+}
}
}
- private ImmutableSet<Module> getAllModulesAndSubmodules(final SchemaContext schema) {
+ private static ImmutableSet<Module> getAllModulesAndSubmodules(final SchemaContext schema) {
final Builder<Module> builder = ImmutableSet.builder();
builder.addAll(schema.getModules());
for (final Module module : schema.getModules()) {
throw new UnsupportedOperationException("Utility class");
}
- static Document loadDocument(final String xmlPath) throws IOException, SAXException {
+ public static Document loadDocument(final String xmlPath) throws IOException, SAXException {
final InputStream resourceAsStream = SchemaContextEmitterTest.class.getResourceAsStream(xmlPath);
final Document currentConfigElement = readXmlToDocument(resourceAsStream);
Preconditions.checkNotNull(currentConfigElement);
return doc;
}
- static String toString(final Node xml) {
+ public static String toString(final Node xml) {
try {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
--- /dev/null
+<module xmlns="urn:ietf:params:xml:ns:yang:yin:1" xmlns:n="notification"
+ name="notification">
+ <yang-version value="1.1"></yang-version>
+ <namespace uri="notification"></namespace>
+ <prefix value="n"></prefix>
+ <revision date="1970-01-01"></revision>
+ <grouping name="grp">
+ <status value="current"></status>
+ <notification name="n5">
+ <status value="current"></status>
+ </notification>
+ </grouping>
+ <container name="r">
+ <presence value="false"></presence>
+ <config value="true"></config>
+ <status value="current"></status>
+ <notification name="n2">
+ <status value="current"></status>
+ </notification>
+ </container>
+ <list name="l">
+ <key value="id"></key>
+ <config value="true"></config>
+ <ordered-by value="system"></ordered-by>
+ <status value="current"></status>
+ <leaf name="id">
+ <type name="int16"></type>
+ <config value="true"></config>
+ <mandatory value="false"></mandatory>
+ <status value="current"></status>
+ </leaf>
+ <notification name="n3">
+ <status value="current"></status>
+ </notification>
+ </list>
+ <augment target-node="/r">
+ <status value="current"></status>
+ <uses name="grp"></uses>
+ <notification name="n4">
+ <status value="current"></status>
+ </notification>
+ </augment>
+ <notification name="n1">
+ <status value="deprecated"></status>
+ <container name="c">
+ <presence value="false"></presence>
+ <config value="true"></config>
+ <status value="current"></status>
+ </container>
+ </notification>
+</module>
\ No newline at end of file
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.NotificationStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
public class NotificationEffectiveStatementImpl extends
private final ConstraintDefinition constraints;
private final Set<AugmentationSchema> augmentations;
private final List<UnknownSchemaNode> unknownNodes;
+ private final boolean augmenting;
+ private final boolean addedByUses;
public NotificationEffectiveStatementImpl(
final StmtContext<QName, NotificationStatement, EffectiveStatement<QName, NotificationStatement>> ctx) {
this.constraints = EffectiveConstraintDefinitionImpl.forParent(this);
// initSubstatementCollections
- List<UnknownSchemaNode> unknownNodesInit = new ArrayList<>();
- Set<AugmentationSchema> augmentationsInit = new LinkedHashSet<>();
- for (EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
+ final List<UnknownSchemaNode> unknownNodesInit = new ArrayList<>();
+ final Set<AugmentationSchema> augmentationsInit = new LinkedHashSet<>();
+ for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
if (effectiveStatement instanceof UnknownSchemaNode) {
- UnknownSchemaNode unknownNode = (UnknownSchemaNode) effectiveStatement;
+ final UnknownSchemaNode unknownNode = (UnknownSchemaNode) effectiveStatement;
unknownNodesInit.add(unknownNode);
}
if (effectiveStatement instanceof AugmentationSchema) {
- AugmentationSchema augmentationSchema = (AugmentationSchema) effectiveStatement;
+ final AugmentationSchema augmentationSchema = (AugmentationSchema) effectiveStatement;
augmentationsInit.add(augmentationSchema);
}
}
this.unknownNodes = ImmutableList.copyOf(unknownNodesInit);
this.augmentations = ImmutableSet.copyOf(augmentationsInit);
+
+ // initCopyType
+ final CopyHistory copyTypesFromOriginal = ctx.getCopyHistory();
+ if (copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
+ this.addedByUses = this.augmenting = true;
+ } else {
+ this.augmenting = copyTypesFromOriginal.contains(CopyType.ADDED_BY_AUGMENTATION);
+ this.addedByUses = copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES);
+ }
}
@Nonnull
return unknownNodes;
}
+ @Override
+ public boolean isAugmenting() {
+ return augmenting;
+ }
+
+ @Override
+ public boolean isAddedByUses() {
+ return addedByUses;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ActionStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
+import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.AbstractEffectiveSchemaNode;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveStmtUtils;
private final ContainerSchemaNode output;
private final Set<TypeDefinition<?>> typeDefinitions;
private final Set<GroupingDefinition> groupings;
+ private final boolean augmenting;
+ private final boolean addedByUses;
public ActionEffectiveStatementImpl(
final StmtContext<QName, ActionStatement, EffectiveStatement<QName, ActionStatement>> ctx) {
this.output = firstEffective(OutputEffectiveStatementImpl.class);
// initSubstatements
- Set<GroupingDefinition> groupingsInit = new HashSet<>();
- Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
- for (EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
+ final Set<GroupingDefinition> groupingsInit = new HashSet<>();
+ final Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
+ for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
if (effectiveStatement instanceof GroupingDefinition) {
- GroupingDefinition groupingDefinition = (GroupingDefinition) effectiveStatement;
+ final GroupingDefinition groupingDefinition = (GroupingDefinition) effectiveStatement;
groupingsInit.add(groupingDefinition);
}
if (effectiveStatement instanceof TypeDefEffectiveStatementImpl) {
- TypeDefEffectiveStatementImpl typeDef = (TypeDefEffectiveStatementImpl) effectiveStatement;
- TypeDefinition<?> type = typeDef.getTypeDefinition();
+ final TypeDefEffectiveStatementImpl typeDef = (TypeDefEffectiveStatementImpl) effectiveStatement;
+ final TypeDefinition<?> type = typeDef.getTypeDefinition();
if (!mutableTypeDefinitions.contains(type)) {
mutableTypeDefinitions.add(type);
} else {
}
this.groupings = ImmutableSet.copyOf(groupingsInit);
this.typeDefinitions = ImmutableSet.copyOf(mutableTypeDefinitions);
+
+ // initCopyType
+ final CopyHistory copyTypesFromOriginal = ctx.getCopyHistory();
+ if (copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
+ this.addedByUses = this.augmenting = true;
+ } else {
+ this.augmenting = copyTypesFromOriginal.contains(CopyType.ADDED_BY_AUGMENTATION);
+ this.addedByUses = copyTypesFromOriginal.contains(CopyType.ADDED_BY_USES);
+ }
}
@Override
return groupings;
}
+ @Override
+ public boolean isAugmenting() {
+ return augmenting;
+ }
+
+ @Override
+ public boolean isAddedByUses() {
+ return addedByUses;
+ }
+
@Override
public int hashCode() {
return Objects.hash(getQName(), getPath());