2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.model.export;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.BiMap;
15 import com.google.common.collect.HashBiMap;
16 import java.io.OutputStream;
19 import java.util.Optional;
20 import javax.xml.stream.XMLEventReader;
21 import javax.xml.stream.XMLOutputFactory;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamWriter;
24 import javax.xml.transform.OutputKeys;
25 import javax.xml.transform.Transformer;
26 import javax.xml.transform.TransformerException;
27 import javax.xml.transform.TransformerFactory;
28 import javax.xml.transform.stax.StAXSource;
29 import javax.xml.transform.stream.StreamResult;
30 import org.opendaylight.yangtools.yang.common.Revision;
31 import org.opendaylight.yangtools.yang.common.YangConstants;
32 import org.opendaylight.yangtools.yang.model.api.Module;
33 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
36 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
38 public final class YinExportUtils {
39 private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
40 private static final XMLOutputFactory OUTPUT_FACTORY = XMLOutputFactory.newFactory();
42 private YinExportUtils() {
43 throw new UnsupportedOperationException("Utility class");
47 * Returns well-formed file name of YIN file as defined in RFC6020.
49 * @param name Module or submodule name
50 * @param revision Revision of module or submodule
51 * @return well-formed file name of YIN file as defined in RFC6020.
53 public static String wellFormedYinName(final String name, final Optional<Revision> revision) {
54 return wellFormedYinName(name, revision.map(Revision::toString).orElse(null));
58 * Returns well-formed file name of YIN file as defined in RFC6020.
60 * @param name name Module or submodule name
61 * @param revision Revision of module or submodule
62 * @return well-formed file name of YIN file as defined in RFC6020.
64 public static String wellFormedYinName(final String name, final String revision) {
65 if (revision == null) {
66 return name + YangConstants.RFC6020_YIN_FILE_EXTENSION;
68 return requireNonNull(name) + '@' + revision + YangConstants.RFC6020_YIN_FILE_EXTENSION;
72 * Write a module as a YIN text into specified {@link OutputStream}. Supplied module must have the
73 * {@link ModuleEffectiveStatement} trait.
75 * @param module Module to be exported
76 * @throws IllegalArgumentException if the module is not an ModuleEffectiveStatement or if it declared
77 * representation is not available.
78 * @throws NullPointerException if any of of the parameters is null
79 * @throws XMLStreamException if an input-output error occurs
82 public static void writeModuleAsYinText(final Module module, final OutputStream output) throws XMLStreamException {
83 requireNonNull(module);
84 checkArgument(module instanceof ModuleEffectiveStatement, "Module %s is not a ModuleEffectiveStatement",
86 final ModuleEffectiveStatement effective = (ModuleEffectiveStatement) module;
87 writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(effective), output);
91 * Write a submodule as a YIN text into specified {@link OutputStream}. Supplied submodule must have the
92 * {@link SubmoduleEffectiveStatement} trait.
94 * @param parentModule Parent module
95 * @param submodule Submodule to be exported
96 * @throws IllegalArgumentException if the parent module is not a ModuleEffectiveStatement, if the submodule is not
97 * a SubmoduleEffectiveStatement or if its declared representation is not available
98 * @throws NullPointerException if any of of the parameters is null
99 * @throws XMLStreamException if an input-output error occurs
102 public static void writeSubmoduleAsYinText(final Module parentModule, final Module submodule,
103 final OutputStream output) throws XMLStreamException {
104 requireNonNull(parentModule);
105 checkArgument(parentModule instanceof ModuleEffectiveStatement, "Parent %s is not a ModuleEffectiveStatement",
107 requireNonNull(submodule);
108 checkArgument(submodule instanceof SubmoduleEffectiveStatement,
109 "Submodule %s is not a SubmoduleEffectiveStatement", submodule);
110 writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(
111 (ModuleEffectiveStatement) parentModule, (SubmoduleEffectiveStatement)submodule), output);
115 * Writes YIN representation of supplied module to specified output stream.
117 * @param ctx Schema Context which contains module and extension definitions to be used during export of model.
118 * @param module Module to be exported.
119 * @param str Output stream to which YIN representation of model will be written.
120 * @throws XMLStreamException when a streaming problem occurs
121 * @deprecated Use {@link #writeModuleAsYinText(Module, OutputStream)}
122 * or {@link #writeSubmoduleAsYinText(Module, Module, OutputStream)} instead.
125 public static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str)
126 throws XMLStreamException {
127 writeModuleToOutputStream(ctx, module, str, false);
131 * Writes YIN representation of supplied module to specified output stream.
133 * @param ctx Schema Context which contains module and extension definitions to be used during export of model.
134 * @param module Module to be exported.
135 * @param str Output stream to which YIN representation of model will be written.
136 * @param emitInstantiated Option to emit also instantiated statements (e.g. statements added by uses or augment)
137 * @throws XMLStreamException when a streaming problem occurs
138 * @deprecated Use {@link #writeModuleAsYinText(Module, OutputStream)}
139 * or {@link #writeSubmoduleAsYinText(Module, Module, OutputStream)} instead.
142 public static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str,
143 final boolean emitInstantiated) throws XMLStreamException {
144 final XMLStreamWriter xmlStreamWriter = OUTPUT_FACTORY.createXMLStreamWriter(str);
145 writeModuleToOutputStream(ctx, module, xmlStreamWriter, emitInstantiated);
146 xmlStreamWriter.flush();
149 private static void writeModuleToOutputStream(final SchemaContext ctx, final Module module,
150 final XMLStreamWriter xmlStreamWriter, final boolean emitInstantiated) {
151 final URI moduleNs = module.getNamespace();
152 final Map<String, URI> prefixToNs = prefixToNamespace(ctx, module);
153 final StatementTextWriter yinWriter = SingleModuleYinStatementWriter.create(xmlStreamWriter, moduleNs,
155 SchemaContextEmitter.writeToStatementWriter(module, ctx, yinWriter, emitInstantiated);
158 private static Map<String, URI> prefixToNamespace(final SchemaContext ctx, final Module module) {
159 final BiMap<String, URI> prefixMap = HashBiMap.create(module.getImports().size() + 1);
160 prefixMap.put(module.getPrefix(), module.getNamespace());
161 for (final ModuleImport imp : module.getImports()) {
162 final String prefix = imp.getPrefix();
163 final URI namespace = getModuleNamespace(ctx, imp.getModuleName());
164 prefixMap.put(prefix, namespace);
169 private static URI getModuleNamespace(final SchemaContext ctx, final String moduleName) {
170 for (final Module module : ctx.getModules()) {
171 if (moduleName.equals(module.getName())) {
172 return module.getNamespace();
175 throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
178 private static void writeReaderToOutput(final XMLEventReader reader, final OutputStream output)
179 throws XMLStreamException {
181 final Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
182 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
183 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
184 transformer.transform(new StAXSource(reader), new StreamResult(output));
185 } catch (TransformerException e) {
186 throw new XMLStreamException("Failed to stream XML events", e);