2 * Copyright (c) 2018 AT&T and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package io.fd.honeycomb.transportpce.binding.converter;
18 import io.fd.honeycomb.transportpce.test.common.DataStoreContext;
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;
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;
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;
57 public class XMLDataObjectConverter extends AbstractDataObjectConverter {
59 private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
61 private final XMLInputFactory xmlInputFactory;
64 * This is the default constructor, which should be used.
66 * @param schemaContext schema context for converter
67 * @param codecRegistry codec registry used for converting
70 private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
71 super(schemaContext, codecRegistry);
72 this.xmlInputFactory = XMLInputFactory.newInstance();
76 * Extract codec and schema context (?).
78 * @param dataStoreContextUtil datastore context util used to extract codec and schema context
79 * @return {@link AbstractDataObjectConverter}
81 public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
82 BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
83 dataStoreContextUtil.getBindingToNormalizedNodeCodec();
84 return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
88 * Extract codec and schema context (?).
90 * @param schemaContext schema context for converter
91 * @param codecRegistry codec registry used for converting
92 * @return new {@link XMLDataObjectConverter}
94 public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
95 @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
96 return new XMLDataObjectConverter(schemaContext, codecRegistry);
100 * Transforms the XML input stream into normalized nodes.
102 * @param inputStream of the given XML
103 * @return {@link Optional} instance of {@link NormalizedNode}.
106 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
107 @Nonnull InputStream inputStream) {
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();
118 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
119 @Nonnull Reader inputReader, SchemaNode parentSchema) {
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();
130 * Transforms the XML input stream into normalized nodes.
132 * @param inputReader of the given XML
133 * @return {@link Optional} instance of {@link NormalizedNode}.
136 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
137 @Nonnull Reader inputReader) {
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();
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),
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);
164 normalizedNodeWriter.flush();
165 xmlStreamWriter.writeEndElement();
166 xmlStreamWriter.flush();
167 } catch (IOException | XMLStreamException ioe) {
168 throw new IllegalStateException(ioe);
174 * Returns a {@link Writer}.
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
182 public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
183 ConvertType<T> convertType) {
184 Writer writer = new StringWriter();
186 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
188 .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
189 normalizedNodeWriter.flush();
190 } catch (IOException ioe) {
191 throw new IllegalStateException(ioe);
196 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
197 XMLStreamReader reader) {
198 return parseInputXML(reader, getSchemaContext());
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
209 LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
210 return Optional.empty();
212 return Optional.ofNullable(result.getResult());
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,
222 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
223 getSchemaContext(), pathToParent);
225 return NormalizedNodeWriter.forStreamWriter(streamWriter);
228 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
229 SchemaPath pathToParent) {
230 NormalizedNodeStreamWriter streamWriter;
231 if (pathToParent == null) {
232 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
235 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
236 getSchemaContext(), pathToParent);
238 return NormalizedNodeWriter.forStreamWriter(streamWriter);
241 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
242 XMLStreamWriter xmlStreamWriter;
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);
251 return xmlStreamWriter;