Remove useless UnsupportedOperationException throws
[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.XMLStreamException;
22 import javax.xml.transform.OutputKeys;
23 import javax.xml.transform.Transformer;
24 import javax.xml.transform.TransformerException;
25 import javax.xml.transform.TransformerFactory;
26 import javax.xml.transform.stax.StAXSource;
27 import javax.xml.transform.stream.StreamResult;
28 import org.opendaylight.yangtools.yang.common.Revision;
29 import org.opendaylight.yangtools.yang.common.YangConstants;
30 import org.opendaylight.yangtools.yang.model.api.Module;
31 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
35
36 public final class YinExportUtils {
37     private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
38
39     private YinExportUtils() {
40         // Hidden on purpose
41     }
42
43     /**
44      * Returns well-formed file name of YIN file as defined in RFC6020.
45      *
46      * @param name Module or submodule name
47      * @param revision Revision of module or submodule
48      * @return well-formed file name of YIN file as defined in RFC6020.
49      */
50     public static String wellFormedYinName(final String name, final Optional<Revision> revision) {
51         return wellFormedYinName(name, revision.map(Revision::toString).orElse(null));
52     }
53
54     /**
55      * Returns well-formed file name of YIN file as defined in RFC6020.
56      *
57      * @param name name Module or submodule name
58      * @param revision Revision of module or submodule
59      * @return well-formed file name of YIN file as defined in RFC6020.
60      */
61     public static String wellFormedYinName(final String name, final String revision) {
62         if (revision == null) {
63             return name + YangConstants.RFC6020_YIN_FILE_EXTENSION;
64         }
65         return requireNonNull(name) + '@' + revision +  YangConstants.RFC6020_YIN_FILE_EXTENSION;
66     }
67
68     /**
69      * Write a module as a YIN text into specified {@link OutputStream}. Supplied module must have the
70      * {@link ModuleEffectiveStatement} trait.
71      *
72      * @param module Module to be exported
73      * @throws IllegalArgumentException if the module is not an ModuleEffectiveStatement or if it declared
74      *                                  representation is not available.
75      * @throws NullPointerException if any of of the parameters is null
76      * @throws XMLStreamException if an input-output error occurs
77      */
78     @Beta
79     public static void writeModuleAsYinText(final Module module, final OutputStream output) throws XMLStreamException {
80         requireNonNull(module);
81         checkArgument(module instanceof ModuleEffectiveStatement, "Module %s is not a ModuleEffectiveStatement",
82             module);
83         final ModuleEffectiveStatement effective = (ModuleEffectiveStatement) module;
84         writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(effective), output);
85     }
86
87     /**
88      * Write a submodule as a YIN text into specified {@link OutputStream}. Supplied submodule must have the
89      * {@link SubmoduleEffectiveStatement} trait.
90      *
91      * @param parentModule Parent module
92      * @param submodule Submodule to be exported
93      * @throws IllegalArgumentException if the parent module is not a ModuleEffectiveStatement, if the submodule is not
94      *                                  a SubmoduleEffectiveStatement or if its declared representation is not available
95      * @throws NullPointerException if any of of the parameters is null
96      * @throws XMLStreamException if an input-output error occurs
97      */
98     @Beta
99     public static void writeSubmoduleAsYinText(final Module parentModule, final Module submodule,
100             final OutputStream output) throws XMLStreamException {
101         requireNonNull(parentModule);
102         checkArgument(parentModule instanceof ModuleEffectiveStatement, "Parent %s is not a ModuleEffectiveStatement",
103             parentModule);
104         requireNonNull(submodule);
105         checkArgument(submodule instanceof SubmoduleEffectiveStatement,
106             "Submodule %s is not a SubmoduleEffectiveStatement", submodule);
107         writeReaderToOutput(YinXMLEventReaderFactory.defaultInstance().createXMLEventReader(
108             (ModuleEffectiveStatement) parentModule, (SubmoduleEffectiveStatement)submodule), output);
109     }
110
111     private static Map<String, URI> prefixToNamespace(final SchemaContext ctx, final Module module) {
112         final BiMap<String, URI> prefixMap = HashBiMap.create(module.getImports().size() + 1);
113         prefixMap.put(module.getPrefix(), module.getNamespace());
114         for (final ModuleImport imp : module.getImports()) {
115             final String prefix = imp.getPrefix();
116             final URI namespace = getModuleNamespace(ctx, imp.getModuleName());
117             prefixMap.put(prefix, namespace);
118         }
119         return prefixMap;
120     }
121
122     private static URI getModuleNamespace(final SchemaContext ctx, final String moduleName) {
123         for (final Module module : ctx.getModules()) {
124             if (moduleName.equals(module.getName())) {
125                 return module.getNamespace();
126             }
127         }
128         throw new IllegalArgumentException("Module " + moduleName + "does not exists in provided schema context");
129     }
130
131     private static void writeReaderToOutput(final XMLEventReader reader, final OutputStream output)
132             throws XMLStreamException {
133         try {
134             final Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
135             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
136             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
137             transformer.transform(new StAXSource(reader), new StreamResult(output));
138         } catch (TransformerException e) {
139             throw new XMLStreamException("Failed to stream XML events", e);
140         }
141     }
142 }