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