Add YinXMLEventReaderFactory
[yangtools.git] / yang / yang-model-export / src / main / java / org / opendaylight / yangtools / yang / model / export / YinExportUtils.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.model.export;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
12
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;
17 import java.net.URI;
18 import java.util.Map;
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;
37
38 public final class YinExportUtils {
39     private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
40     private static final XMLOutputFactory OUTPUT_FACTORY = XMLOutputFactory.newFactory();
41
42     private YinExportUtils() {
43         throw new UnsupportedOperationException("Utility class");
44     }
45
46     /**
47      * Returns well-formed file name of YIN file as defined in RFC6020.
48      *
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.
52      */
53     public static String wellFormedYinName(final String name, final Optional<Revision> revision) {
54         return wellFormedYinName(name, revision.map(Revision::toString).orElse(null));
55     }
56
57     /**
58      * Returns well-formed file name of YIN file as defined in RFC6020.
59      *
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.
63      */
64     public static String wellFormedYinName(final String name, final String revision) {
65         if (revision == null) {
66             return name + YangConstants.RFC6020_YIN_FILE_EXTENSION;
67         }
68         return requireNonNull(name) + '@' + revision +  YangConstants.RFC6020_YIN_FILE_EXTENSION;
69     }
70
71     /**
72      * Write a module as a YIN text into specified {@link OutputStream}. Supplied module must have the
73      * {@link ModuleEffectiveStatement} trait.
74      *
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
80      */
81     @Beta
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",
85             module);
86         final ModuleEffectiveStatement effective = (ModuleEffectiveStatement) module;
87         writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(effective), output);
88     }
89
90     /**
91      * Write a submodule as a YIN text into specified {@link OutputStream}. Supplied submodule must have the
92      * {@link SubmoduleEffectiveStatement} trait.
93      *
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
100      */
101     @Beta
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",
106             parentModule);
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);
112     }
113
114     /**
115      * Writes YIN representation of supplied module to specified output stream.
116      *
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.
123      */
124     @Deprecated
125     public static void writeModuleToOutputStream(final SchemaContext ctx, final Module module, final OutputStream str)
126             throws XMLStreamException {
127         writeModuleToOutputStream(ctx, module, str, false);
128     }
129
130     /**
131      * Writes YIN representation of supplied module to specified output stream.
132      *
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.
140      */
141     @Deprecated
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();
147     }
148
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,
154                 prefixToNs);
155         SchemaContextEmitter.writeToStatementWriter(module, ctx, yinWriter, emitInstantiated);
156     }
157
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);
165         }
166         return prefixMap;
167     }
168
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();
173             }
174         }
175         throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
176     }
177
178     private static void writeReaderToOutput(final XMLEventReader reader, final OutputStream output)
179             throws XMLStreamException {
180         try {
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);
187         }
188     }
189 }