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.test.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.stream.XMLInputFactory;
21 import javax.xml.stream.XMLOutputFactory;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamReader;
24 import javax.xml.stream.XMLStreamWriter;
25 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
26 import org.opendaylight.transportpce.test.DataStoreContext;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
32 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
33 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
34 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
35 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
36 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
37 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
38 import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
39 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
40 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
41 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
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(EffectiveModelContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
60 super(schemaContext, codecRegistry);
61 this.xmlInputFactory = XMLInputFactory.newInstance();
62 // set external DTD and schema to null to avoid vulnerability (sonar report)
63 this.xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
64 this.xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
68 * Extract codec and schema context (?).
70 * @param dataStoreContextUtil datastore context util used to extract codec and schema context
71 * @return {@link AbstractDataObjectConverter}
73 public static XMLDataObjectConverter createWithDataStoreUtil(@Nonnull DataStoreContext dataStoreContextUtil) {
74 BindingNormalizedNodeSerializer bindingToNormalizedNodeCodec =
75 dataStoreContextUtil.getBindingDOMCodecServices();
76 return new XMLDataObjectConverter(dataStoreContextUtil.getSchemaContext(), bindingToNormalizedNodeCodec);
80 * Extract codec and schema context (?).
82 * @param schemaContext schema context for converter
83 * @param codecRegistry codec registry used for converting
84 * @return new {@link XMLDataObjectConverter}
86 public static XMLDataObjectConverter createWithSchemaContext(@Nonnull EffectiveModelContext schemaContext,
87 @Nonnull BindingNormalizedNodeSerializer codecRegistry) {
88 return new XMLDataObjectConverter(schemaContext, codecRegistry);
92 * Transforms the XML input stream into normalized nodes.
94 * @param inputStream of the given XML
95 * @return {@link Optional} instance of {@link NormalizedNode}.
98 public Optional<NormalizedNode> transformIntoNormalizedNode(@Nonnull InputStream inputStream) {
100 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
101 return parseInputXML(reader);
102 } catch (XMLStreamException e) {
103 LOG.warn("XMLStreamException: {}", e.getMessage());
104 return Optional.empty();
109 public Optional<NormalizedNode> transformIntoNormalizedNode(@Nonnull Reader inputReader) {
111 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
112 return parseInputXML(reader);
113 } catch (XMLStreamException e) {
114 LOG.warn("XMLStreamException: {}", e.getMessage());
115 return Optional.empty();
120 public Optional<NormalizedNode> transformIntoNormalizedNode(Reader inputReader, SchemaNode parentSchema) {
121 throw new UnsupportedOperationException("Not Implemented yet");
125 * Transforms the XML input stream into normalized nodes.
127 * @param inputReader of the given XML
128 * @return {@link Optional} instance of {@link NormalizedNode}.
130 public Optional<NormalizedNode> transformInschemaContexttoNormalizedNode(@Nonnull Reader inputReader) {
132 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
133 return parseInputXML(reader);
134 } catch (XMLStreamException e) {
135 LOG.warn("XMLStreamException: {}", e.getMessage());
136 return Optional.empty();
141 public <T extends DataObject> Writer writerFromRpcDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
142 ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
143 Writer writer = new StringWriter();
144 XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
145 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter)) {
146 xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
147 rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
148 xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
149 NormalizedNode rpcOutputNormalizedNode = convertType.toNormalizedNodes(dataObjectClass.cast(object),
150 dataObjectClass).get();
151 for (final NormalizedNode child : ((ContainerNode)rpcOutputNormalizedNode).body()) {
152 normalizedNodeWriter.write(child);
154 normalizedNodeWriter.flush();
155 xmlStreamWriter.writeEndElement();
156 xmlStreamWriter.flush();
157 } catch (IOException | XMLStreamException ioe) {
158 throw new IllegalStateException(ioe);
164 * Returns a {@link Writer}.
166 * @param convertType converter used of converting into normalized node
167 * @param dataObjectClass class of converting object
168 * @param object object you want to convert
172 public <T extends DataObject> Writer writerFromDataObject(@Nonnull DataObject object, Class<T> dataObjectClass,
173 ConvertType<T> convertType) {
175 Writer writer = new StringWriter();
176 Optional<NormalizedNode> normalizedNode = convertType
177 .toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass);
178 if (normalizedNode.isEmpty()) {
179 LOG.warn("enable to convert {} to {}", dataObjectClass, object.getClass());
183 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer)) {
184 normalizedNodeWriter.write(normalizedNode.get());
185 normalizedNodeWriter.flush();
186 } catch (IOException ioe) {
187 throw new IllegalStateException(ioe);
192 private Optional<NormalizedNode> parseInputXML(XMLStreamReader reader) {
193 return parseInputXML(reader, getSchemaContext());
196 private Optional<NormalizedNode> parseInputXML(XMLStreamReader reader, SchemaNode parentSchemaNode) {
197 NormalizedNodeResult result = new NormalizedNodeResult();
198 EffectiveStatementInference schema = SchemaInferenceStack.of(getSchemaContext()).toInference();
199 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
200 XmlParserStream xmlParser = XmlParserStream
201 .create(streamWriter, schema)) {
202 xmlParser.parse(reader);
203 } catch (XMLStreamException | URISyntaxException | IOException | SAXException e) {
204 LOG.warn("An error occured during parsing XML input stream", e);
205 return Optional.empty();
207 return Optional.ofNullable(result.getResult());
210 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter) {
211 XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
212 NormalizedNodeStreamWriter streamWriter;
213 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter, getSchemaContext());
214 return NormalizedNodeWriter.forStreamWriter(streamWriter);
217 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter) {
218 Inference rootNode = SchemaInferenceStack.of(getSchemaContext()).toInference();
219 NormalizedNodeStreamWriter streamWriter = XMLStreamNormalizedNodeStreamWriter
220 .create(backingWriter, rootNode);
221 return NormalizedNodeWriter.forStreamWriter(streamWriter);
224 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
225 XMLStreamWriter xmlStreamWriter;
227 XMLOutputFactory factory = XMLOutputFactory.newFactory();
228 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
229 xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
230 } catch (XMLStreamException | FactoryConfigurationError e) {
231 LOG.error("Error while creating XML writer: ", e);
232 throw new IllegalStateException(e);
234 return xmlStreamWriter;