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