Fix checkstyle in yang-model-export
[yangtools.git] / yang / yang-model-export / src / main / java / org / opendaylight / yangtools / yang / model / export / SingleModuleYinStatementWriter.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 com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.BiMap;
13 import com.google.common.collect.HashBiMap;
14 import java.net.URI;
15 import java.util.Iterator;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import javax.annotation.Nullable;
19 import javax.annotation.concurrent.NotThreadSafe;
20 import javax.xml.XMLConstants;
21 import javax.xml.stream.XMLStreamException;
22 import javax.xml.stream.XMLStreamWriter;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.YangConstants;
25 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
26 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
27 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
28 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
29
30 @Deprecated
31 @Beta
32 @NotThreadSafe
33 final class SingleModuleYinStatementWriter implements StatementTextWriter {
34
35     private final XMLStreamWriter writer;
36     private final URI currentModuleNs;
37     private final BiMap<String, URI> prefixToNamespace;
38     private StatementDefinition currentStatement;
39
40     private SingleModuleYinStatementWriter(final XMLStreamWriter writer, final URI moduleNamespace,
41             final Map<String, URI> prefixToNs) {
42         this.writer = writer;
43         this.currentModuleNs = moduleNamespace;
44         this.prefixToNamespace = HashBiMap.create(prefixToNs);
45         initializeYinNamespaceInXml();
46     }
47
48     private void initializeYinNamespaceInXml() {
49         try {
50             final String defaultNs = writer.getNamespaceContext().getNamespaceURI(XMLConstants.NULL_NS_URI);
51             if (defaultNs == null) {
52                 writer.setDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
53             } else if (!YangConstants.RFC6020_YIN_NAMESPACE.toString().equals(defaultNs)) {
54                 // FIXME: Implement support for exporting YIN as part of other XML document.
55                 throw new UnsupportedOperationException(
56                         "Not implemented support for nesting YIN in different XML element.");
57             }
58         } catch (final XMLStreamException e) {
59             throw new IllegalStateException(e);
60         }
61     }
62
63     static StatementTextWriter create(final XMLStreamWriter writer, final URI moduleNs,
64             final Map<String, URI> prefixToNs) {
65         return new SingleModuleYinStatementWriter(writer, moduleNs, prefixToNs);
66     }
67
68     @Override
69     public void startStatement(final StatementDefinition statement) {
70         currentStatement = Preconditions.checkNotNull(statement);
71         try {
72             writeStartXmlElement(statement.getStatementName());
73             if (YangStmtMapping.MODULE.equals(statement) || YangStmtMapping.SUBMODULE.equals(statement)) {
74                 declareXmlNamespaces();
75             }
76         } catch (final XMLStreamException e) {
77             // FIXME: Introduce proper expression
78             throw new IllegalStateException(e);
79         }
80     }
81
82     @Override
83     public void endStatement() {
84         currentStatement = null;
85         try {
86             writeXmlEndElement();
87         } catch (final XMLStreamException e) {
88             // FIXME: Introduce proper expression
89             throw new IllegalStateException(e);
90         }
91     }
92
93     @Override
94     public void writeArgument(final String strRep) {
95         checkArgumentApplicable();
96         writeArgument0(strRep);
97     }
98
99     @Override
100     public void writeArgument(final QName value) {
101         checkArgumentApplicable();
102         final String valueStr = toPrefixedString(value);
103         writeArgument0(valueStr);
104     }
105
106     @Override
107     public void writeArgument(final SchemaPath targetPath) {
108         checkArgumentApplicable();
109         final StringBuilder valueStr = new StringBuilder();
110         if (targetPath.isAbsolute()) {
111             valueStr.append("/");
112         }
113         final Iterator<QName> argIt = targetPath.getPathFromRoot().iterator();
114         while (argIt.hasNext()) {
115             valueStr.append(toPrefixedString(argIt.next()));
116             if (argIt.hasNext()) {
117                 valueStr.append("/");
118             }
119         }
120         writeArgument0(valueStr.toString());
121     }
122
123     @Override
124     public void writeArgument(final RevisionAwareXPath xpath) {
125         checkArgumentApplicable();
126         // FIXME: This implementation assumes prefixes are unchanged
127         // and were not changed in schema context.
128         writeArgument0(xpath.toString());
129     }
130
131     private void writeArgument0(final String strRep) {
132         try {
133             if (isArgumentYinElement(currentStatement)) {
134                 writeStartXmlElement(currentStatement.getArgumentName());
135                 writeXmlText(strRep);
136                 writeXmlEndElement();
137             } else {
138                 writeXmlArgument(currentStatement.getArgumentName(), strRep);
139             }
140         } catch (final XMLStreamException e) {
141             // FIXME: throw proper exception
142             throw new IllegalStateException(e);
143         }
144     }
145
146     private static boolean isArgumentYinElement(final StatementDefinition currentStatement) {
147         if (currentStatement instanceof YangStmtMapping || currentStatement instanceof ExtensionStatement) {
148             return currentStatement.isArgumentYinElement();
149         }
150         return false;
151     }
152
153     private void checkArgumentApplicable() {
154         Preconditions.checkState(currentStatement != null, "No statement is opened.");
155         Preconditions.checkState(currentStatement.getArgumentName() != null, "Statement %s does not take argument.",
156                 currentStatement.getArgumentName());
157     }
158
159     private static String toPrefixedString(@Nullable final String prefix, final String localName) {
160         if (prefix == null || prefix.isEmpty()) {
161             return localName;
162         }
163         return prefix + ":" + localName;
164     }
165
166     private String toPrefixedString(final QName value) {
167         final URI valueNs = value.getNamespace();
168         final String valueLocal = value.getLocalName();
169         if (currentModuleNs.equals(valueNs)) {
170             return valueLocal;
171         }
172         final String prefix = ensureAndGetXmlNamespacePrefix(valueNs);
173         return toPrefixedString(prefix, valueLocal);
174     }
175
176     private @Nullable String ensureAndGetXmlNamespacePrefix(final URI namespace) {
177         if (YangConstants.RFC6020_YANG_NAMESPACE.equals(namespace)) {
178          // YANG namespace does not have prefix if used in arguments.
179             return null;
180
181         }
182         String prefix = writer.getNamespaceContext().getPrefix(namespace.toString());
183         if (prefix == null) {
184             // FIXME: declare prefix
185             prefix = prefixToNamespace.inverse().get(namespace);
186         }
187         if (prefix == null) {
188             throw new IllegalArgumentException("Namespace " + namespace + " is not bound to imported prefixes.");
189         }
190         return prefix;
191     }
192
193     private void writeXmlText(final String strRep) throws XMLStreamException {
194         writer.writeCharacters(strRep);
195     }
196
197     private void declareXmlNamespaces() {
198         try {
199             writer.writeDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
200             for (final Entry<String, URI> nsDeclaration : prefixToNamespace.entrySet()) {
201                 writer.writeNamespace(nsDeclaration.getKey(), nsDeclaration.getValue().toString());
202             }
203         } catch (final XMLStreamException e) {
204             throw new IllegalStateException(e);
205         }
206     }
207
208     private void writeXmlEndElement() throws XMLStreamException {
209         writer.writeEndElement();
210     }
211
212     private void writeXmlArgument(final QName qname, final String value) throws XMLStreamException {
213         writer.writeAttribute(qname.getNamespace().toString(), qname.getLocalName(), value);
214     }
215
216     private void writeStartXmlElement(final QName name) throws XMLStreamException {
217         writer.writeStartElement(name.getNamespace().toString(), name.getLocalName());
218     }
219 }