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;
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;
55 public class XMLDataObjectConverter extends AbstractDataObjectConverter {
57 private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
59 private final XMLInputFactory xmlInputFactory;
62 * This is the default constructor, which should be used.
64 * @param schemaContext schema context for converter
65 * @param codecRegistry codec registry used for converting
68 private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
69 super(schemaContext, codecRegistry);
70 this.xmlInputFactory = XMLInputFactory.newInstance();
74 * Extract codec and schema context (?).
76 * @param dataStoreContextUtil datastore context util used to extract codec and schema context
77 * @return {@link AbstractDataObjectConverter}
79 public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
80 BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
81 dataStoreContextUtil.getBindingToNormalizedNodeCodec();
82 return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
86 * Extract codec and schema context (?).
88 * @param schemaContext schema context for converter
89 * @param codecRegistry codec registry used for converting
90 * @return new {@link XMLDataObjectConverter}
92 public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
93 @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
94 return new XMLDataObjectConverter(schemaContext, codecRegistry);
98 * Transforms the XML input stream into normalized nodes.
100 * @param inputStream of the given XML
101 * @return {@link Optional} instance of {@link NormalizedNode}.
104 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
105 @Nonnull InputStream inputStream) {
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();
115 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
116 @Nonnull Reader inputReader, SchemaNode parentSchema) {
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();
127 * Transforms the XML input stream into normalized nodes.
129 * @param inputReader of the given XML
130 * @return {@link Optional} instance of {@link NormalizedNode}.
133 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
134 @Nonnull Reader inputReader) {
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();
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),
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);
161 normalizedNodeWriter.flush();
162 xmlStreamWriter.writeEndElement();
163 xmlStreamWriter.flush();
164 } catch (IOException | XMLStreamException ioe) {
165 throw new IllegalStateException(ioe);
171 * Returns a {@link Writer}.
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
179 public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
180 ConvertType<T> convertType) {
181 Writer writer = new StringWriter();
183 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
185 .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
186 normalizedNodeWriter.flush();
187 } catch (IOException ioe) {
188 throw new IllegalStateException(ioe);
193 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
194 XMLStreamReader reader) {
195 return parseInputXML(reader, getSchemaContext());
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
206 LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
207 return Optional.empty();
209 return Optional.ofNullable(result.getResult());
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,
219 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
220 getSchemaContext(), pathToParent);
222 return NormalizedNodeWriter.forStreamWriter(streamWriter);
225 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
226 SchemaPath pathToParent) {
227 NormalizedNodeStreamWriter streamWriter;
228 if (pathToParent == null) {
229 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
232 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
233 getSchemaContext(), pathToParent);
235 return NormalizedNodeWriter.forStreamWriter(streamWriter);
238 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
239 XMLStreamWriter xmlStreamWriter;
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);
248 return xmlStreamWriter;