2 * Copyright © 2016 AT&T and others. All rights reserved.
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
8 package io.fd.honeycomb.transportpce.binding.converter;
10 import io.fd.honeycomb.transportpce.test.common.DataStoreContext;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.Reader;
15 import java.io.StringWriter;
16 import java.io.Writer;
17 import java.net.URISyntaxException;
18 import java.util.Optional;
19 import javax.annotation.Nonnull;
20 import javax.xml.XMLConstants;
21 import javax.xml.parsers.FactoryConfigurationError;
22 import javax.xml.parsers.ParserConfigurationException;
23 import javax.xml.stream.XMLInputFactory;
24 import javax.xml.stream.XMLOutputFactory;
25 import javax.xml.stream.XMLStreamException;
26 import javax.xml.stream.XMLStreamReader;
27 import javax.xml.stream.XMLStreamWriter;
28 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
29 import org.opendaylight.yangtools.yang.binding.DataObject;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
35 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
36 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
37 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
38 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
39 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
41 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.xml.sax.SAXException;
47 public class XMLDataObjectConverter extends AbstractDataObjectConverter {
49 private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
51 private final XMLInputFactory xmlInputFactory;
54 * This is the default constructor, which should be used.
56 * @param schemaContext schema context for converter
57 * @param codecRegistry codec registry used for converting
60 private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
61 super(schemaContext, codecRegistry);
62 this.xmlInputFactory = XMLInputFactory.newInstance();
66 * Extract codec and schema context (?).
68 * @param dataStoreContextUtil datastore context util used to extract codec and schema context
69 * @return {@link AbstractDataObjectConverter}
71 public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
72 BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
73 dataStoreContextUtil.getBindingToNormalizedNodeCodec();
74 return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
78 * Extract codec and schema context (?).
80 * @param schemaContext schema context for converter
81 * @param codecRegistry codec registry used for converting
82 * @return new {@link XMLDataObjectConverter}
84 public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
85 @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
86 return new XMLDataObjectConverter(schemaContext, codecRegistry);
90 * Transforms the XML input stream into normalized nodes.
92 * @param inputStream of the given XML
93 * @return {@link Optional} instance of {@link NormalizedNode}.
96 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
97 @Nonnull InputStream inputStream) {
99 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
100 return parseInputXML(reader);
101 } catch (XMLStreamException e) {
102 LOG.warn(e.getMessage(), e);
103 return Optional.empty();
107 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
108 @Nonnull Reader inputReader, SchemaNode parentSchema) {
110 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
111 return parseInputXML(reader, parentSchema);
112 } catch (XMLStreamException e) {
113 LOG.warn(e.getMessage(), e);
114 return Optional.empty();
119 * Transforms the XML input stream into normalized nodes.
121 * @param inputReader of the given XML
122 * @return {@link Optional} instance of {@link NormalizedNode}.
125 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
126 @Nonnull Reader inputReader) {
128 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
129 return parseInputXML(reader);
130 } catch (XMLStreamException e) {
131 LOG.warn(e.getMessage(), e);
132 return Optional.empty();
137 public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
138 ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
139 Writer writer = new StringWriter();
140 XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
141 SchemaPath rpcOutputSchemaPath = SchemaPath.create(true, QName.create(rpcOutputQName.getModule(), rpcName),
143 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter,
144 rpcOutputSchemaPath)) {
145 xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
146 rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
147 xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
148 NormalizedNode<?, ?> rpcOutputNormalizedNode = convertType.toNormalizedNodes(dataObjectClass.cast(object),
149 dataObjectClass).get();
150 for (final NormalizedNode<?, ?> child : ((ContainerNode)rpcOutputNormalizedNode).getValue()) {
151 normalizedNodeWriter.write(child);
153 normalizedNodeWriter.flush();
154 xmlStreamWriter.writeEndElement();
155 xmlStreamWriter.flush();
156 } catch (IOException | XMLStreamException ioe) {
157 throw new IllegalStateException(ioe);
163 * Returns a {@link Writer}.
165 * @param convertType converter used of converting into normalized node
166 * @param dataObjectClass class of converting object
167 * @param object object you want to convert
171 public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
172 ConvertType<T> convertType) {
173 Writer writer = new StringWriter();
175 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
177 .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
178 normalizedNodeWriter.flush();
179 } catch (IOException ioe) {
180 throw new IllegalStateException(ioe);
185 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
186 XMLStreamReader reader) {
187 return parseInputXML(reader, getSchemaContext());
190 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
191 XMLStreamReader reader, SchemaNode parentSchemaNode) {
192 NormalizedNodeResult result = new NormalizedNodeResult();
193 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
194 XmlParserStream xmlParser = XmlParserStream.create(streamWriter, getSchemaContext(), parentSchemaNode)) {
195 xmlParser.parse(reader);
196 } catch (XMLStreamException | URISyntaxException | IOException | ParserConfigurationException
198 LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
199 return Optional.empty();
201 return Optional.ofNullable(result.getResult());
204 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter, SchemaPath pathToParent) {
205 XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
206 NormalizedNodeStreamWriter streamWriter;
207 if (pathToParent == null) {
208 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
211 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
212 getSchemaContext(), pathToParent);
214 return NormalizedNodeWriter.forStreamWriter(streamWriter);
217 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
218 SchemaPath pathToParent) {
219 NormalizedNodeStreamWriter streamWriter;
220 if (pathToParent == null) {
221 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
224 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
225 getSchemaContext(), pathToParent);
227 return NormalizedNodeWriter.forStreamWriter(streamWriter);
230 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
231 XMLStreamWriter xmlStreamWriter;
233 XMLOutputFactory factory = XMLOutputFactory.newFactory();
234 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
235 xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
236 } catch (XMLStreamException | FactoryConfigurationError e) {
237 LOG.error("Error [{}] while creating XML writer", e.getMessage(), e);
238 throw new IllegalStateException(e);
240 return xmlStreamWriter;