fix some compilation warnings
[transportpce.git] / test-common / src / main / java / org / opendaylight / transportpce / binding / converter / XMLDataObjectConverter.java
1 /*
2  * Copyright © 2016 AT&T 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.transportpce.binding.converter;
9
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.Reader;
13 import java.io.StringWriter;
14 import java.io.Writer;
15 import java.net.URISyntaxException;
16 import java.util.Optional;
17 import javax.annotation.Nonnull;
18 import javax.xml.XMLConstants;
19 import javax.xml.parsers.FactoryConfigurationError;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.stream.XMLInputFactory;
22 import javax.xml.stream.XMLOutputFactory;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamReader;
25 import javax.xml.stream.XMLStreamWriter;
26 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
27 import org.opendaylight.transportpce.test.common.DataStoreContext;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
34 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
35 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
36 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
38 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.xml.sax.SAXException;
45
46 public final class XMLDataObjectConverter extends AbstractDataObjectConverter {
47
48     private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
49
50     private final XMLInputFactory xmlInputFactory;
51
52     /**
53      * This is the default constructor, which should be used.
54      *
55      * @param schemaContext schema context for converter
56      * @param codecRegistry codec registry used for converting
57      *
58      */
59     private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
60         super(schemaContext, codecRegistry);
61         this.xmlInputFactory = XMLInputFactory.newInstance();
62     }
63
64     /**
65      * Extract codec and schema context (?).
66      *
67      * @param dataStoreContextUtil datastore context util used to extract codec and schema context
68      * @return {@link AbstractDataObjectConverter}
69      */
70     public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
71         BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
72                 dataStoreContextUtil.getBindingToNormalizedNodeCodec();
73         return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
74     }
75
76     /**
77      * Extract codec and schema context (?).
78      *
79      * @param schemaContext schema context for converter
80      * @param codecRegistry codec registry used for converting
81      * @return new {@link XMLDataObjectConverter}
82      */
83     public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
84             @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
85         return new XMLDataObjectConverter(schemaContext, codecRegistry);
86     }
87
88     /**
89      * Transforms the XML input stream into normalized nodes.
90      *
91      * @param inputStream of the given XML
92      * @return {@link Optional} instance of {@link NormalizedNode}.
93      */
94     @Override
95     public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
96             @Nonnull InputStream inputStream) {
97         try {
98             XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
99             return parseInputXML(reader);
100         } catch (XMLStreamException e) {
101             LOG.warn(e.getMessage(), e);
102             return Optional.empty();
103         }
104     }
105
106     public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
107             @Nonnull Reader inputReader, SchemaNode parentSchema) {
108         try {
109             XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
110             return parseInputXML(reader, parentSchema);
111         } catch (XMLStreamException e) {
112             LOG.warn(e.getMessage(), e);
113             return Optional.empty();
114         }
115     }
116
117     /**
118      * Transforms the XML input stream into normalized nodes.
119      *
120      * @param inputReader of the given XML
121      * @return {@link Optional} instance of {@link NormalizedNode}.
122      */
123     @Override
124     public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
125             @Nonnull Reader inputReader) {
126         try {
127             XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
128             return parseInputXML(reader);
129         } catch (XMLStreamException e) {
130             LOG.warn(e.getMessage(), e);
131             return Optional.empty();
132         }
133     }
134
135     @Override
136     public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
137             ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
138         Writer writer = new StringWriter();
139         XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
140         SchemaPath rpcOutputSchemaPath = SchemaPath.create(true, QName.create(rpcOutputQName.getModule(), rpcName),
141                 rpcOutputQName);
142         try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter,
143                 rpcOutputSchemaPath)) {
144             xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
145                     rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
146             xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
147             NormalizedNode<?, ?> rpcOutputNormalizedNode = convertType.toNormalizedNodes(dataObjectClass.cast(object),
148                     dataObjectClass).get();
149             for (final NormalizedNode<?, ?> child : ((ContainerNode)rpcOutputNormalizedNode).getValue()) {
150                 normalizedNodeWriter.write(child);
151             }
152             normalizedNodeWriter.flush();
153             xmlStreamWriter.writeEndElement();
154             xmlStreamWriter.flush();
155         } catch (IOException | XMLStreamException ioe) {
156             throw new IllegalStateException(ioe);
157         }
158         return writer;
159     }
160
161     /**
162      * Returns a {@link Writer}.
163      *
164      * @param convertType converter used of converting into normalized node
165      * @param dataObjectClass class of converting object
166      * @param object object you want to convert
167      *
168      */
169     @Override
170     public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
171             ConvertType<T> convertType) {
172         Writer writer = new StringWriter();
173
174         try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
175             normalizedNodeWriter
176                     .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
177             normalizedNodeWriter.flush();
178         } catch (IOException ioe) {
179             throw new IllegalStateException(ioe);
180         }
181         return writer;
182     }
183
184     private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
185             XMLStreamReader reader) {
186         return parseInputXML(reader, getSchemaContext());
187     }
188
189     private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
190             XMLStreamReader reader, SchemaNode parentSchemaNode) {
191         NormalizedNodeResult result = new NormalizedNodeResult();
192         try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
193              XmlParserStream xmlParser = XmlParserStream.create(streamWriter, getSchemaContext(), parentSchemaNode)) {
194             xmlParser.parse(reader);
195         } catch (XMLStreamException | URISyntaxException | IOException | ParserConfigurationException
196                 | SAXException e) {
197             LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
198             return Optional.empty();
199         }
200         return Optional.ofNullable(result.getResult());
201     }
202
203     private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter, SchemaPath pathToParent) {
204         XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
205         NormalizedNodeStreamWriter streamWriter;
206         if (pathToParent == null) {
207             streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
208                     getSchemaContext());
209         } else {
210             streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
211                     getSchemaContext(), pathToParent);
212         }
213         return NormalizedNodeWriter.forStreamWriter(streamWriter);
214     }
215
216     private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
217             SchemaPath pathToParent) {
218         NormalizedNodeStreamWriter streamWriter;
219         if (pathToParent == null) {
220             streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
221                     getSchemaContext());
222         } else {
223             streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
224                     getSchemaContext(), pathToParent);
225         }
226         return NormalizedNodeWriter.forStreamWriter(streamWriter);
227     }
228
229     private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
230         XMLStreamWriter xmlStreamWriter;
231         try {
232             XMLOutputFactory factory = XMLOutputFactory.newFactory();
233             factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
234             xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
235         } catch (XMLStreamException | FactoryConfigurationError e) {
236             LOG.error("Error [{}] while creating XML writer", e.getMessage(), e);
237             throw new IllegalStateException(e);
238         }
239         return xmlStreamWriter;
240     }
241 }