--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+
+/**
+ * Internal shared helpers.
+ * @author Robert Varga
+ *
+ */
+final class ExportUtils {
+ private ExportUtils() {
+ // Hidden on purpose
+ }
+
+ static Optional<String> statementPrefix(final Map<QNameModule, String> namespaces, final QName stmtName) {
+ final QNameModule namespace = stmtName.getModule();
+ if (YangConstants.RFC6020_YIN_MODULE.equals(namespace)) {
+ return Optional.empty();
+ }
+
+ // Non-default namespace, a prefix is needed
+ @Nullable String prefix = namespaces.get(namespace);
+ if (prefix == null && !namespace.getRevision().isPresent()) {
+ // FIXME: this is an artifact of commonly-bound statements in parser, which means a statement's name
+ // does not have a Revision. We'll need to find a solution to this which is acceptable. There
+ // are multiple ways of fixing this:
+ // - perhaps EffectiveModuleStatement should be giving us a statement-to-EffectiveModule map?
+ // - or DeclaredStatement should provide the prefix?
+ // The second one seems cleaner, as that means we would not have perform any lookup at all...
+ Entry<QNameModule, @NonNull String> match = null;
+ for (Entry<QNameModule, @NonNull String> entry : namespaces.entrySet()) {
+ final QNameModule ns = entry.getKey();
+ if (namespace.equals(ns.withoutRevision()) && (match == null
+ || Revision.compare(match.getKey().getRevision(), ns.getRevision()) < 0)) {
+ match = entry;
+ }
+ }
+
+ if (match != null) {
+ prefix = match.getValue();
+ }
+ }
+
+ checkArgument(prefix != null, "Failed to find prefix for statement %s", stmtName);
+ verify(!prefix.isEmpty(), "Empty prefix for statement %s", stmtName);
+ return Optional.of(prefix);
+ }
+}
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+@Deprecated
final class ExtensionStatement implements StatementDefinition {
- private QName argumentName;
- private QName statementName;
- private boolean yinElement;
+ private final QName argumentName;
+ private final QName statementName;
+ private final boolean yinElement;
private ExtensionStatement(final ExtensionDefinition def) {
statementName = def.getQName();
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.ImmutableListMultimap.Builder;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.NamespaceContext;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.PrefixToEffectiveModuleNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
+
+final class ModuleNamespaceContext implements NamespaceContext {
+ private static final Entry<String, String> YIN_PREFIX_AND_NAMESPACE =
+ new SimpleImmutableEntry<>(XMLConstants.DEFAULT_NS_PREFIX, YangConstants.RFC6020_YIN_NAMESPACE_STRING);
+
+ private final ListMultimap<@NonNull String, @NonNull String> namespaceToPrefix;
+ private final Map<String, @NonNull ModuleEffectiveStatement> prefixToModule;
+ private final Map<QNameModule, @NonNull String> moduleToPrefix;
+
+ ModuleNamespaceContext(final ModuleEffectiveStatement module) {
+ this.prefixToModule = requireNonNull(module.getAll(PrefixToEffectiveModuleNamespace.class));
+ this.moduleToPrefix = requireNonNull(module.getAll(QNameModuleToPrefixNamespace.class));
+
+ final Builder<String, String> namespaces = ImmutableListMultimap.builder();
+ for (Entry<QNameModule, @NonNull String> e : moduleToPrefix.entrySet()) {
+ namespaces.put(e.getKey().getNamespace().toString(), e.getValue());
+ }
+ namespaceToPrefix = namespaces.build();
+ }
+
+ @Override
+ public String getNamespaceURI(final String prefix) {
+ checkArgument(prefix != null);
+
+ switch (prefix) {
+ case XMLConstants.DEFAULT_NS_PREFIX:
+ return YangConstants.RFC6020_YIN_NAMESPACE_STRING;
+ case XMLConstants.XML_NS_PREFIX:
+ return XMLConstants.XML_NS_URI;
+ case XMLConstants.XMLNS_ATTRIBUTE:
+ return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
+ default:
+ final ModuleEffectiveStatement module = prefixToModule.get(prefix);
+ return module != null ? module.localQNameModule().getNamespace().toString()
+ : XMLConstants.NULL_NS_URI;
+ }
+ }
+
+ @Override
+ public String getPrefix(final String namespaceURI) {
+ checkArgument(namespaceURI != null);
+
+ switch (namespaceURI) {
+ case YangConstants.RFC6020_YIN_NAMESPACE_STRING:
+ return XMLConstants.DEFAULT_NS_PREFIX;
+ case XMLConstants.XML_NS_URI:
+ return XMLConstants.XML_NS_PREFIX;
+ case XMLConstants.XMLNS_ATTRIBUTE_NS_URI:
+ return XMLConstants.XMLNS_ATTRIBUTE;
+ default:
+ final List<@NonNull String> prefixes = namespaceToPrefix.get(namespaceURI);
+ return prefixes.isEmpty() ? null : prefixes.get(0);
+ }
+ }
+
+ @Override
+ public Iterator<String> getPrefixes(final String namespaceURI) {
+ checkArgument(namespaceURI != null);
+
+ switch (namespaceURI) {
+ case YangConstants.RFC6020_YIN_NAMESPACE_STRING:
+ return Iterators.singletonIterator(XMLConstants.DEFAULT_NS_PREFIX);
+ case XMLConstants.XML_NS_URI:
+ return Iterators.singletonIterator(XMLConstants.XML_NS_PREFIX);
+ case XMLConstants.XMLNS_ATTRIBUTE_NS_URI:
+ return Iterators.singletonIterator(XMLConstants.XMLNS_ATTRIBUTE);
+ default:
+ return namespaceToPrefix.get(namespaceURI).iterator();
+ }
+ }
+
+ Entry<String, String> prefixAndNamespaceFor(final QNameModule module) {
+ if (YangConstants.RFC6020_YIN_MODULE.equals(module)) {
+ return YIN_PREFIX_AND_NAMESPACE;
+ }
+
+ final String prefix = moduleToPrefix.get(module);
+ checkArgument(prefix != null, "Module %s does not map to a prefix", module);
+ return new SimpleImmutableEntry<>(prefix, module.getNamespace().toString());
+ }
+
+ Entry<String, String> prefixAndNamespaceForStatement(final QName stmtName) {
+ final Optional<String> prefix = ExportUtils.statementPrefix(moduleToPrefix, stmtName);
+ if (!prefix.isPresent()) {
+ return YIN_PREFIX_AND_NAMESPACE;
+ }
+
+ return new SimpleImmutableEntry<>(prefix.get(), stmtName.getNamespace().toString());
+ }
+
+ Map<String, String> prefixesAndNamespaces() {
+ return Maps.transformValues(prefixToModule, module -> module.localQNameModule().getNamespace().toString());
+ }
+}
import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
+@Deprecated
@Beta
@NotThreadSafe
abstract class SchemaContextEmitter {
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Relative;
import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
+@Deprecated
@Beta
@NotThreadSafe
final class SchemaToStatementWriterAdaptor implements YangModuleWriter {
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.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+@Deprecated
@Beta
@NotThreadSafe
class SingleModuleYinStatementWriter implements StatementTextWriter {
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+@Deprecated
interface StatementTextWriter {
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
+@Deprecated
interface YangModuleWriter {
void endNode();
*/
package org.opendaylight.yangtools.yang.model.export;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import static org.eclipse.jdt.annotation.DefaultLocation.PARAMETER;
import static org.eclipse.jdt.annotation.DefaultLocation.RETURN_TYPE;
import java.util.Deque;
import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
+import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.Revision;
-import org.opendaylight.yangtools.yang.common.YangConstants;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
// Add statement prefixed with namespace if needed
final QName stmtName = def.getStatementName();
- final QNameModule namespace = stmtName.getModule();
- if (!YangConstants.RFC6020_YIN_MODULE.equals(namespace)) {
- // Non-default namespace, a prefix is needed
- @Nullable String prefix = namespaces.get(namespace);
- if (prefix == null && !namespace.getRevision().isPresent()) {
- // FIXME: this is an artifact of commonly-bound statements in parser, which means a statement's name
- // does not have a Revision. We'll need to find a solution to this which is acceptable. There
- // are multiple ways of fixing this:
- // - perhaps EffectiveModuleStatement should be giving us a statement-to-EffectiveModule map?
- // - or DeclaredStatement should provide the prefix?
- // The second one seems cleaner, as that means we would not have perform any lookup at all...
- Entry<QNameModule, @NonNull String> match = null;
- for (Entry<QNameModule, @NonNull String> entry : namespaces.entrySet()) {
- final QNameModule ns = entry.getKey();
- if (namespace.equals(ns.withoutRevision()) && (match == null
- || Revision.compare(match.getKey().getRevision(), ns.getRevision()) < 0)) {
- match = entry;
- }
- }
-
- if (match != null) {
- prefix = match.getValue();
- }
- }
-
- checkArgument(prefix != null, "Failed to find prefix for statement %s", stmtName);
- verify(!prefix.isEmpty(), "Empty prefix for statement %s", stmtName);
- strings.add(prefix);
+ final Optional<String> prefix = ExportUtils.statementPrefix(namespaces, stmtName);
+ if (prefix.isPresent()) {
+ strings.add(prefix.get());
strings.add(":");
}
strings.add(stmtName.getLocalName());
*/
package org.opendaylight.yangtools.yang.model.export;
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import java.io.OutputStream;
import java.net.URI;
import java.util.Map;
import java.util.Optional;
+import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamResult;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.common.YangConstants;
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.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
public final class YinExportUtils {
+ private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
+ private static final XMLOutputFactory OUTPUT_FACTORY = XMLOutputFactory.newFactory();
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
+ * @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 Optional<Revision> 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
+ * @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) {
if (revision == null) {
return name + YangConstants.RFC6020_YIN_FILE_EXTENSION;
}
- return Preconditions.checkNotNull(name) + '@' + revision + YangConstants.RFC6020_YIN_FILE_EXTENSION;
+ return requireNonNull(name) + '@' + revision + YangConstants.RFC6020_YIN_FILE_EXTENSION;
+ }
+
+ /**
+ * Write a module as a YIN text into specified {@link OutputStream}. Supplied module must have the
+ * {@link ModuleEffectiveStatement} trait.
+ *
+ * @param module Module to be exported
+ * @throws IllegalArgumentException if the module is not an ModuleEffectiveStatement or if it declared
+ * representation is not available.
+ * @throws NullPointerException if any of of the parameters is null
+ * @throws XMLStreamException if an input-output error occurs
+ */
+ @Beta
+ public static void writeModuleAsYinText(final Module module, final OutputStream output) throws XMLStreamException {
+ requireNonNull(module);
+ checkArgument(module instanceof ModuleEffectiveStatement, "Module %s is not a ModuleEffectiveStatement",
+ module);
+ final ModuleEffectiveStatement effective = (ModuleEffectiveStatement) module;
+ writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(effective), output);
+ }
+
+ /**
+ * Write a submodule as a YIN text into specified {@link OutputStream}. Supplied submodule must have the
+ * {@link SubmoduleEffectiveStatement} trait.
+ *
+ * @param parentModule Parent module
+ * @param submodule Submodule to be exported
+ * @throws IllegalArgumentException if the parent module is not a ModuleEffectiveStatement, if the submodule is not
+ * a SubmoduleEffectiveStatement or if its declared representation is not available
+ * @throws NullPointerException if any of of the parameters is null
+ * @throws XMLStreamException if an input-output error occurs
+ */
+ @Beta
+ public static void writeSubmoduleAsYinText(final Module parentModule, final Module submodule,
+ final OutputStream output) throws XMLStreamException {
+ requireNonNull(parentModule);
+ checkArgument(parentModule instanceof ModuleEffectiveStatement, "Parent %s is not a ModuleEffectiveStatement",
+ parentModule);
+ requireNonNull(submodule);
+ checkArgument(submodule instanceof SubmoduleEffectiveStatement,
+ "Submodule %s is not a SubmoduleEffectiveStatement", submodule);
+ writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(
+ (ModuleEffectiveStatement) parentModule, (SubmoduleEffectiveStatement)submodule), output);
}
/**
* 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
+ * @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 when a streaming problem occurs
+ * @deprecated Use {@link #writeModuleAsYinText(Module, OutputStream)}
+ * or {@link #writeSubmoduleAsYinText(Module, Module, OutputStream)} instead.
*/
+ @Deprecated
public static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str)
throws XMLStreamException {
writeModuleToOutputStream(ctx, module, str, false);
/**
* 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.
- * @param emitInstantiated
- * Option to emit also instantiated statements (e.g. statements
- * added by uses or augment)
- * @throws XMLStreamException
+ * @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.
+ * @param emitInstantiated Option to emit also instantiated statements (e.g. statements added by uses or augment)
+ * @throws XMLStreamException when a streaming problem occurs
+ * @deprecated Use {@link #writeModuleAsYinText(Module, OutputStream)}
+ * or {@link #writeSubmoduleAsYinText(Module, Module, OutputStream)} instead.
*/
+ @Deprecated
public 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);
+ final XMLStreamWriter xmlStreamWriter = OUTPUT_FACTORY.createXMLStreamWriter(str);
writeModuleToOutputStream(ctx, module, xmlStreamWriter, emitInstantiated);
xmlStreamWriter.flush();
}
throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
}
+ private static void writeReaderToOutput(final XMLEventReader reader, final OutputStream output)
+ throws XMLStreamException {
+ try {
+ final Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.transform(new StAXSource(reader), new StreamResult(output));
+ } catch (TransformerException e) {
+ throw new XMLStreamException("Failed to stream XML events", e);
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 com.google.common.collect.Iterators.singletonIterator;
+import static com.google.common.collect.Iterators.transform;
+import static java.util.Collections.emptyIterator;
+import static java.util.Objects.requireNonNull;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import javax.xml.XMLConstants;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+
+final class YinXMLEventReader implements XMLEventReader {
+ private static final class OpenElement {
+ final Iterator<? extends DeclaredStatement<?>> children;
+ final QName name;
+
+ OpenElement(final Iterator<? extends DeclaredStatement<?>> children) {
+ this.children = requireNonNull(children);
+ this.name = null;
+ }
+
+ OpenElement(final QName name, final Iterator<? extends DeclaredStatement<?>> children) {
+ this.children = requireNonNull(children);
+ this.name = requireNonNull(name);
+ }
+ }
+
+ private final Deque<OpenElement> stack = new ArrayDeque<>(8);
+ private final Queue<XMLEvent> events = new ArrayDeque<>();
+ private final ModuleNamespaceContext namespaceContext;
+ private final XMLEventFactory eventFactory;
+
+ YinXMLEventReader(final XMLEventFactory eventFactory, final ModuleNamespaceContext namespaceContext,
+ final DeclaredStatement<?> root) {
+ this.eventFactory = requireNonNull(eventFactory);
+ this.namespaceContext = requireNonNull(namespaceContext);
+
+ events.add(eventFactory.createStartDocument(StandardCharsets.UTF_8.name()));
+
+ final StatementDefinition def = root.statementDefinition();
+ final QName name = def.getStatementName();
+
+ events.add(eventFactory.createStartElement(XMLConstants.DEFAULT_NS_PREFIX, name.getNamespace().toString(),
+ name.getLocalName(), singletonIterator(attribute(def.getArgumentName(), root.rawArgument())),
+ transform(namespaceContext.prefixesAndNamespaces().entrySet().iterator(),
+ e -> eventFactory.createNamespace(e.getKey(), e.getValue())),
+ namespaceContext));
+
+ stack.push(new OpenElement(name, root.declaredSubstatements().iterator()));
+ }
+
+ @Override
+ public XMLEvent next() {
+ XMLEvent event = events.poll();
+ if (event != null) {
+ return event;
+ }
+
+ nextStatement();
+ event = events.poll();
+ if (event == null) {
+ throw new NoSuchElementException("All events have been processed");
+ }
+ return event;
+ }
+
+ @Override
+ public XMLEvent nextEvent() {
+ return next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ if (events.isEmpty()) {
+ nextStatement();
+ return events.isEmpty();
+ }
+ return true;
+ }
+
+ @Override
+ public XMLEvent peek() throws XMLStreamException {
+ if (events.isEmpty()) {
+ nextStatement();
+ }
+
+ return events.peek();
+ }
+
+ @Override
+ public String getElementText() throws XMLStreamException {
+ XMLEvent current = peek();
+ if (current == null) {
+ throw new XMLStreamException("End of event stream");
+ }
+ if (!(current instanceof StartElement)) {
+ throw new XMLStreamException("Current event is " + current);
+ }
+
+ current = next();
+ if (!(current instanceof Characters)) {
+ throw new XMLStreamException("Encountered non-text event " + current);
+ }
+ final String ret = ((Characters)current).getData();
+
+ current = next();
+ if (!(current instanceof EndElement)) {
+ throw new XMLStreamException("Encountered unexpected event " + current);
+ }
+ return ret;
+ }
+
+ @Override
+ public XMLEvent nextTag() throws XMLStreamException {
+ final XMLEvent next = next();
+ if (next instanceof Characters) {
+ throw new XMLStreamException("Significant characters encountered: " + next);
+ }
+ return next;
+ }
+
+ @Override
+ public Object getProperty(final String name) {
+ throw new IllegalArgumentException("Property " + name + " not supported");
+ }
+
+ @Override
+ public void close() {
+ events.clear();
+ stack.clear();
+ }
+
+ private Attribute attribute(final QName qname, final String value) {
+ final Entry<String, String> ns = namespaceContext.prefixAndNamespaceFor(qname.getModule());
+ return eventFactory.createAttribute(ns.getKey(), ns.getValue(), qname.getLocalName(), value);
+ }
+
+ private StartElement startElement(final QName qname) {
+ final Entry<String, String> ns = namespaceContext.prefixAndNamespaceFor(qname.getModule());
+ return eventFactory.createStartElement(ns.getKey(), ns.getValue(), qname.getLocalName(), emptyIterator(),
+ emptyIterator(), namespaceContext);
+ }
+
+ private EndElement endElement(final QName qname) {
+ final Entry<String, String> ns = namespaceContext.prefixAndNamespaceFor(qname.getModule());
+ return eventFactory.createEndElement(ns.getKey(), ns.getValue(), qname.getLocalName());
+ }
+
+ private void nextStatement() {
+ OpenElement current = stack.peek();
+ if (current == null) {
+ return;
+ }
+
+ do {
+ while (current.children.hasNext()) {
+ // We have to mind child statement source and not emit empty implicit children
+ final DeclaredStatement<?> child = current.children.next();
+ switch (child.getStatementSource()) {
+ case CONTEXT:
+ final Iterator<? extends DeclaredStatement<?>> it = child.declaredSubstatements().iterator();
+ if (it.hasNext()) {
+ current = new OpenElement(it);
+ }
+ break;
+ case DECLARATION:
+ addStatement(child);
+ return;
+ default:
+ throw new IllegalStateException("Unhandled statement source " + child.getStatementSource());
+ }
+ }
+
+ if (current.name != null) {
+ events.add(endElement(current.name));
+ }
+ stack.pop();
+ if (stack.isEmpty()) {
+ events.add(eventFactory.createEndDocument());
+ }
+ } while (events.isEmpty());
+ }
+
+ private void addStatement(final DeclaredStatement<?> statement) {
+ final StatementDefinition def = statement.statementDefinition();
+ final QName name = def.getStatementName();
+ final QName argName = def.getArgumentName();
+ if (argName != null) {
+ if (def.isArgumentYinElement()) {
+ events.addAll(Arrays.asList(startElement(name), startElement(argName),
+ eventFactory.createCharacters(statement.rawArgument()), endElement(argName)));
+ } else {
+ final Entry<String, String> ns = namespaceContext.prefixAndNamespaceFor(name.getModule());
+ events.add(eventFactory.createStartElement(ns.getKey(), ns.getValue(), name.getLocalName(),
+ singletonIterator(attribute(argName, statement.rawArgument())), emptyIterator(), namespaceContext));
+ }
+ } else {
+ // No attributes: just emit a start
+ events.add(startElement(name));
+ }
+
+ stack.push(new OpenElement(name, statement.declaredSubstatements().iterator()));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.concurrent.ThreadSafe;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventReader;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
+
+/**
+ * Factory for creating {@link XMLEventReader} instances reporting events equivalent to reading a YIN document defining
+ * a specified {@link ModuleEffectiveStatement}.
+ */
+@Beta
+@ThreadSafe
+public final class YinXMLEventReaderFactory {
+ private static final Location DUMMY_LOCATION = new Location() {
+
+ @Override
+ public int getLineNumber() {
+ return -1;
+ }
+
+ @Override
+ public int getColumnNumber() {
+ return -1;
+ }
+
+ @Override
+ public int getCharacterOffset() {
+ return -1;
+ }
+
+ @Override
+ public String getPublicId() {
+ return null;
+ }
+
+ @Override
+ public String getSystemId() {
+ return null;
+ }
+ };
+
+ private static final YinXMLEventReaderFactory DEFAULT;
+
+ static {
+ final XMLEventFactory eventFactory = XMLEventFactory.newFactory();
+ eventFactory.setLocation(DUMMY_LOCATION);
+ DEFAULT = new YinXMLEventReaderFactory(eventFactory);
+ }
+
+ private final XMLEventFactory eventFactory;
+
+ private YinXMLEventReaderFactory(final XMLEventFactory eventFactory) {
+ this.eventFactory = requireNonNull(eventFactory);
+ }
+
+ /**
+ * Get the system-wide default instance, backed by system-wide default XMLEventFactory.
+ *
+ * @return Default instance.
+ */
+ public static YinXMLEventReaderFactory defaultInstance() {
+ return DEFAULT;
+ }
+
+ public static YinXMLEventReaderFactory ofEventFactory(final XMLEventFactory factory) {
+ return new YinXMLEventReaderFactory(factory);
+ }
+
+ /**
+ * Create a new XMLEventReader iterating of the YIN document equivalent of an effective module.
+ *
+ * @param module Effective module
+ * @return A new XMLEventReader.
+ * @throws NullPointerException if module is null
+ * @throws IllegalArgumentException if the specified module does not expose declared model
+ */
+ public final XMLEventReader createXMLEventReader(final ModuleEffectiveStatement module) {
+ final ModuleStatement declared = module.getDeclared();
+ checkArgument(declared != null, "Module %s does not expose declared model", module);
+
+ return new YinXMLEventReader(eventFactory, new ModuleNamespaceContext(module), declared);
+ }
+
+ /**
+ * Create a new XMLEventReader iterating of the YIN document equivalent of an effective submodule.
+ *
+ * @param module Effective module
+ * @param submodule Effective submodule
+ * @return A new XMLEventReader.
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the specified submodule does not expose declared model
+ */
+ public final XMLEventReader createXMLEventReader(final ModuleEffectiveStatement module,
+ final SubmoduleEffectiveStatement submodule) {
+ final SubmoduleStatement declared = submodule.getDeclared();
+ checkArgument(declared != null, "Submodule %s does not expose declared model", submodule);
+ return new YinXMLEventReader(eventFactory, new ModuleNamespaceContext(module), declared);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.. 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import javax.xml.stream.XMLStreamException;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.ElementNameAndAttributeQualifier;
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+abstract class AbstractYinExportTest {
+ final void exportYinModules(final String yangDir, final String yinDir) throws IOException, SAXException,
+ XMLStreamException {
+ final SchemaContext schemaContext = YangParserTestUtils.parseYangResourceDirectory(yangDir);
+ final Collection<Module> modules = schemaContext.getModules();
+ assertNotEquals(0, modules.size());
+
+ for (Module module : modules) {
+ readAndValidateModule(schemaContext, module, yinDir);
+
+ for (Module submodule : module.getSubmodules()) {
+ readAndValidateSubmodule(schemaContext, module, submodule, yinDir);
+ }
+ }
+ }
+
+ void validateOutput(final String yinDir, final String fileName, final String fileBody) throws IOException,
+ SAXException {
+ assertNotEquals(0, fileBody.length());
+ if (yinDir != null) {
+ final Document doc = YinExportTestUtils.loadDocument(yinDir + "/" + fileName);
+ assertXMLEquals(fileName, doc, fileBody);
+ }
+ }
+
+ private void readAndValidateModule(final SchemaContext schemaContext, final Module module, final String yinDir)
+ throws XMLStreamException, IOException, SAXException {
+ final String fileName = YinExportUtils.wellFormedYinName(module.getName(), module.getRevision());
+ validateOutput(yinDir, fileName, exportLegacy(schemaContext, module));
+ validateOutput(yinDir, fileName, export(module));
+ }
+
+ private void readAndValidateSubmodule(final SchemaContext schemaContext, final Module module,
+ final Module submodule, final String yinDir) throws XMLStreamException, IOException, SAXException {
+ final String fileName = YinExportUtils.wellFormedYinName(submodule.getName(), submodule.getRevision());
+ validateOutput(yinDir, fileName, exportLegacy(schemaContext, submodule));
+ validateOutput(yinDir, fileName, export(module, submodule));
+ }
+
+ private static String export(final Module module) throws XMLStreamException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ YinExportUtils.writeModuleAsYinText(module, bos);
+ return new String(bos.toByteArray(), StandardCharsets.UTF_8);
+ }
+
+ private static String export(final Module module, final Module submodule) throws XMLStreamException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ YinExportUtils.writeSubmoduleAsYinText(module, submodule, bos);
+ return new String(bos.toByteArray(), StandardCharsets.UTF_8);
+ }
+
+ private static String exportLegacy(final SchemaContext schemaContext, final Module module)
+ throws XMLStreamException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ YinExportUtils.writeModuleToOutputStream(schemaContext, module, bos);
+ return new String(bos.toByteArray(), StandardCharsets.UTF_8);
+ }
+
+ private static void assertXMLEquals(final String fileName, 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(fileName, diff, true);
+ }
+}
*/
package org.opendaylight.yangtools.yang.model.export;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSet.Builder;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-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.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.export.YinExportUtils;
-import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-public class Bug2444Test {
+public class Bug2444Test extends AbstractYinExportTest {
@Test
public void test() throws Exception {
- final SchemaContext schema = YangParserTestUtils.parseYangResourceDirectory("/bugs/bug2444/yang");
- assertNotNull(schema);
-
- final ImmutableSet<Module> modulesAndSubmodules = getAllModulesAndSubmodules(schema);
- for (final Module module : modulesAndSubmodules) {
- final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
- try {
- YinExportUtils.writeModuleToOutputStream(schema, module, bufferedOutputStream);
- final String output = byteArrayOutputStream.toString();
- assertNotNull(output);
- assertNotEquals(0, output.length());
-
- final Document doc = YinExportTestUtils.loadDocument("/bugs/bug2444/yin", module);
- assertXMLEquals(module.getName(), doc, output);
- } finally {
- byteArrayOutputStream.close();
- bufferedOutputStream.close();
- }
- }
- }
-
- private static ImmutableSet<Module> getAllModulesAndSubmodules(final SchemaContext schema) {
- final Builder<Module> builder = ImmutableSet.builder();
- builder.addAll(schema.getModules());
- for (final Module module : schema.getModules()) {
- builder.addAll(module.getSubmodules());
- }
- return builder.build();
- }
-
- private static void assertXMLEquals(final String fileName, 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(fileName, diff, true);
+ exportYinModules("/bugs/bug2444/yang", "/bugs/bug2444/yin");
}
}
*/
package org.opendaylight.yangtools.yang.model.export;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
+import java.io.IOException;
+import javax.xml.stream.XMLStreamException;
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.test.util.YangParserTestUtils;
+import org.xml.sax.SAXException;
-public class Bug4504Test {
+public class Bug4504Test extends AbstractYinExportTest {
@Test
- public void test() throws Exception {
- SchemaContext schema = YangParserTestUtils.parseYangResourceDirectory("/bugs/bug4504");
- assertNotNull(schema);
- final File outDir = new File("target/bug4504-export");
- outDir.mkdirs();
- for (final Module module : schema.getModules()) {
- exportModule(schema, module, outDir);
- }
- }
-
- 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)) {
- YinExportUtils.writeModuleToOutputStream(schemaContext, module, output);
- }
- return outFile;
+ public void test() throws IOException, SAXException, XMLStreamException {
+ exportYinModules("/bugs/bug4504", null);
}
}
for (final Module module : schema.getModules()) {
exportModule(schema, module, outDir);
- final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
- try {
+
+ try (OutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
+ try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream)) {
writeModuleToOutputStream(schema, module, bufferedOutputStream, false);
final String output = byteArrayOutputStream.toString();
assertNotNull(output);
final Document doc = YinExportTestUtils.loadDocument("/bugs/bug2444/yin-effective-emitter", module);
assertXMLEquals(module.getName(), doc, output);
- } finally {
- byteArrayOutputStream.close();
- bufferedOutputStream.close();
+ }
}
}
}
package org.opendaylight.yangtools.yang.model.export;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.OutputStream;
import javax.xml.stream.XMLStreamException;
-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.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.export.YinExportUtils;
-import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
-import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-public class SchemaContextEmitterTest {
+public class SchemaContextEmitterTest extends AbstractYinExportTest {
@Test
public void testSchemaContextEmitter() throws IOException, XMLStreamException, SAXException {
- final SchemaContext schemaContext = YangParserTestUtils.parseYangResourceDirectory(
- "/schema-context-emitter-test");
- assertNotNull(schemaContext);
- assertEquals(1, schemaContext.getModules().size());
-
- final OutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream);
-
- for (final Module module : schemaContext.getModules()) {
- YinExportUtils.writeModuleToOutputStream(schemaContext, module, bufferedOutputStream);
- }
-
- final String output = byteArrayOutputStream.toString();
- assertNotNull(output);
- assertNotEquals(0, output.length());
-
- final Document doc = YinExportTestUtils.loadDocument("/schema-context-emitter-test/foo.yin");
- final String expected = YinExportTestUtils.toString(doc.getDocumentElement());
-
- XMLUnit.setIgnoreWhitespace(true);
- XMLUnit.setNormalize(true);
-
- final Diff diff = new Diff(expected, output);
- diff.overrideElementQualifier(new ElementNameAndAttributeQualifier());
- XMLAssert.assertXMLEqual(diff, true);
+ exportYinModules("/schema-context-emitter-test", "/schema-context-emitter-test");
}
}