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 org.opendaylight.transportpce.common.converter;
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.io.Reader;
13 import java.io.StringWriter;
14 import java.io.Writer;
15 import java.net.URISyntaxException;
16 import java.util.Optional;
17 import javax.annotation.Nonnull;
18 import javax.xml.XMLConstants;
19 import javax.xml.parsers.FactoryConfigurationError;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.stream.XMLInputFactory;
22 import javax.xml.stream.XMLOutputFactory;
23 import javax.xml.stream.XMLStreamException;
24 import javax.xml.stream.XMLStreamReader;
25 import javax.xml.stream.XMLStreamWriter;
26 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
27 import org.opendaylight.transportpce.common.DataStoreContext;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
34 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
35 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
36 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
37 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
38 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
40 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.xml.sax.SAXException;
46 public final class XMLDataObjectConverter extends AbstractDataObjectConverter {
48 private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
50 private final XMLInputFactory xmlInputFactory;
53 * This is the default constructor, which should be used.
55 * @param schemaContext schema context for converter
56 * @param codecRegistry codec registry used for converting
59 private XMLDataObjectConverter(SchemaContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
60 super(schemaContext, codecRegistry);
61 this.xmlInputFactory = XMLInputFactory.newInstance();
65 * Extract codec and schema context (?).
67 * @param dataStoreContextUtil datastore context util used to extract codec and schema context
68 * @return {@link AbstractDataObjectConverter}
70 public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
71 BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
72 dataStoreContextUtil.getBindingToNormalizedNodeCodec();
73 return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
77 * Extract codec and schema context (?).
79 * @param schemaContext schema context for converter
80 * @param codecRegistry codec registry used for converting
81 * @return new {@link XMLDataObjectConverter}
83 public static XMLDataObjectConverter createWithSchemaContext(@Nonnull SchemaContext schemaContext,
84 @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
85 return new XMLDataObjectConverter(schemaContext, codecRegistry);
89 * Transforms the XML input stream into normalized nodes.
91 * @param inputStream of the given XML
92 * @return {@link Optional} instance of {@link NormalizedNode}.
95 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
96 @Nonnull InputStream inputStream) {
98 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
99 return parseInputXML(reader);
100 } catch (XMLStreamException e) {
101 LOG.warn(e.getMessage(), e);
102 return Optional.empty();
106 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
107 @Nonnull Reader inputReader, SchemaNode parentSchema) {
109 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
110 return parseInputXML(reader, parentSchema);
111 } catch (XMLStreamException e) {
112 LOG.warn(e.getMessage(), e);
113 return Optional.empty();
118 * Transforms the XML input stream into normalized nodes.
120 * @param inputReader of the given XML
121 * @return {@link Optional} instance of {@link NormalizedNode}.
124 public Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> transformIntoNormalizedNode(
125 @Nonnull Reader inputReader) {
127 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
128 return parseInputXML(reader);
129 } catch (XMLStreamException e) {
130 LOG.warn(e.getMessage(), e);
131 return Optional.empty();
136 public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
137 ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
138 Writer writer = new StringWriter();
139 XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
140 SchemaPath rpcOutputSchemaPath = SchemaPath.create(true, QName.create(rpcOutputQName.getModule(), rpcName),
142 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter,
143 rpcOutputSchemaPath)) {
144 xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
145 rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
146 xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
147 NormalizedNode<?, ?> rpcOutputNormalizedNode = convertType.toNormalizedNodes(dataObjectClass.cast(object),
148 dataObjectClass).get();
149 for (final NormalizedNode<?, ?> child : ((ContainerNode)rpcOutputNormalizedNode).getValue()) {
150 normalizedNodeWriter.write(child);
152 normalizedNodeWriter.flush();
153 xmlStreamWriter.writeEndElement();
154 xmlStreamWriter.flush();
155 } catch (IOException | XMLStreamException ioe) {
156 throw new IllegalStateException(ioe);
162 * Returns a {@link Writer}.
164 * @param convertType converter used of converting into normalized node
165 * @param dataObjectClass class of converting object
166 * @param object object you want to convert
170 public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
171 ConvertType<T> convertType) {
172 Writer writer = new StringWriter();
174 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer, null)) {
176 .write(convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).get());
177 normalizedNodeWriter.flush();
178 } catch (IOException ioe) {
179 throw new IllegalStateException(ioe);
184 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
185 XMLStreamReader reader) {
186 return parseInputXML(reader, getSchemaContext());
189 private Optional<NormalizedNode<? extends YangInstanceIdentifier.PathArgument, ?>> parseInputXML(
190 XMLStreamReader reader, SchemaNode parentSchemaNode) {
191 NormalizedNodeResult result = new NormalizedNodeResult();
192 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
193 XmlParserStream xmlParser = XmlParserStream.create(streamWriter, getSchemaContext(), parentSchemaNode)) {
194 xmlParser.parse(reader);
195 } catch (XMLStreamException | URISyntaxException | IOException | ParserConfigurationException
197 LOG.warn("An error {} occured during parsing XML input stream", e.getMessage(), e);
198 return Optional.empty();
200 return Optional.ofNullable(result.getResult());
203 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter, SchemaPath pathToParent) {
204 XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
205 NormalizedNodeStreamWriter streamWriter;
206 if (pathToParent == null) {
207 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
210 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter,
211 getSchemaContext(), pathToParent);
213 return NormalizedNodeWriter.forStreamWriter(streamWriter);
216 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter,
217 SchemaPath pathToParent) {
218 NormalizedNodeStreamWriter streamWriter;
219 if (pathToParent == null) {
220 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
223 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(backingWriter,
224 getSchemaContext(), pathToParent);
226 return NormalizedNodeWriter.forStreamWriter(streamWriter);
229 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
230 XMLStreamWriter xmlStreamWriter;
232 XMLOutputFactory factory = XMLOutputFactory.newFactory();
233 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
234 xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
235 } catch (XMLStreamException | FactoryConfigurationError e) {
236 LOG.error("Error [{}] while creating XML writer", e.getMessage(), e);
237 throw new IllegalStateException(e);
239 return xmlStreamWriter;