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.util.Optional;
16 import javax.xml.XMLConstants;
17 import javax.xml.parsers.FactoryConfigurationError;
18 import javax.xml.stream.XMLInputFactory;
19 import javax.xml.stream.XMLOutputFactory;
20 import javax.xml.stream.XMLStreamException;
21 import javax.xml.stream.XMLStreamReader;
22 import javax.xml.stream.XMLStreamWriter;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
25 import org.opendaylight.transportpce.test.DataStoreContext;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
31 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
32 import org.opendaylight.yangtools.yang.data.codec.xml.XMLStreamNormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
34 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
35 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
36 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
37 import org.opendaylight.yangtools.yang.model.api.EffectiveStatementInference;
38 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
39 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
40 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 public final class XMLDataObjectConverter extends AbstractDataObjectConverter {
46 private static final Logger LOG = LoggerFactory.getLogger(XMLDataObjectConverter.class);
48 private final XMLInputFactory xmlInputFactory;
51 * This is the default constructor, which should be used.
53 * @param schemaContext schema context for converter
54 * @param codecRegistry codec registry used for converting
57 private XMLDataObjectConverter(EffectiveModelContext schemaContext, BindingNormalizedNodeSerializer codecRegistry) {
58 super(schemaContext, codecRegistry);
59 this.xmlInputFactory = XMLInputFactory.newInstance();
60 // set external DTD and schema to null to avoid vulnerability (sonar report)
61 this.xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
62 this.xmlInputFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
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.getBindingDOMCodecServices();
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 EffectiveModelContext 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> transformIntoNormalizedNode(@NonNull InputStream inputStream) {
98 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputStream);
99 return parseInputXML(reader);
100 } catch (XMLStreamException e) {
101 LOG.warn("XMLStreamException: {}", e.getMessage());
102 return Optional.empty();
107 public Optional<NormalizedNode> transformIntoNormalizedNode(@NonNull Reader inputReader) {
109 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
110 return parseInputXML(reader);
111 } catch (XMLStreamException e) {
112 LOG.warn("XMLStreamException: {}", e.getMessage());
113 return Optional.empty();
118 public Optional<NormalizedNode> transformIntoNormalizedNode(Reader inputReader, SchemaNode parentSchema) {
119 throw new UnsupportedOperationException("Not Implemented yet");
123 * Transforms the XML input stream into normalized nodes.
125 * @param inputReader of the given XML
126 * @return {@link Optional} instance of {@link NormalizedNode}.
128 public Optional<NormalizedNode> transformInschemaContexttoNormalizedNode(@NonNull Reader inputReader) {
130 XMLStreamReader reader = this.xmlInputFactory.createXMLStreamReader(inputReader);
131 return parseInputXML(reader);
132 } catch (XMLStreamException e) {
133 LOG.warn("XMLStreamException: {}", e.getMessage());
134 return Optional.empty();
139 public <T extends DataObject> Writer writerFromRpcDataObject(@NonNull DataObject object, Class<T> dataObjectClass,
140 ConvertType<T> convertType, QName rpcOutputQName, String rpcName) {
141 Writer writer = new StringWriter();
142 XMLStreamWriter xmlStreamWriter = createXmlStreamWriter(writer);
143 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(xmlStreamWriter)) {
144 xmlStreamWriter.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX,
145 rpcOutputQName.getLocalName(), rpcOutputQName.getNamespace().toString());
146 xmlStreamWriter.writeDefaultNamespace(rpcOutputQName.getNamespace().toString());
147 NormalizedNode rpcOutputNormalizedNode =
148 convertType.toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass).orElseThrow();
149 for (final NormalizedNode child : ((ContainerNode)rpcOutputNormalizedNode).body()) {
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) {
173 Writer writer = new StringWriter();
174 Optional<NormalizedNode> normalizedNode = convertType
175 .toNormalizedNodes(dataObjectClass.cast(object), dataObjectClass);
176 if (normalizedNode.isEmpty()) {
177 LOG.warn("enable to convert {} to {}", dataObjectClass, object.getClass());
181 try (NormalizedNodeWriter normalizedNodeWriter = createWriterBackedNormalizedNodeWriter(writer)) {
182 normalizedNodeWriter.write(normalizedNode.orElseThrow());
183 normalizedNodeWriter.flush();
184 } catch (IOException ioe) {
185 throw new IllegalStateException(ioe);
190 private Optional<NormalizedNode> parseInputXML(XMLStreamReader reader) {
191 return parseInputXML(reader, getSchemaContext());
194 private Optional<NormalizedNode> parseInputXML(XMLStreamReader reader, SchemaNode parentSchemaNode) {
195 NormalizationResultHolder result = new NormalizationResultHolder();
196 EffectiveStatementInference schema = SchemaInferenceStack.of(getSchemaContext()).toInference();
197 try (NormalizedNodeStreamWriter streamWriter = ImmutableNormalizedNodeStreamWriter.from(result);
198 XmlParserStream xmlParser = XmlParserStream
199 .create(streamWriter, schema)) {
200 xmlParser.parse(reader);
201 } catch (XMLStreamException | IOException e) {
202 LOG.warn("An error occured during parsing XML input stream", e);
203 return Optional.empty();
205 return Optional.ofNullable(result.getResult().data());
208 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(Writer backingWriter) {
209 XMLStreamWriter createXMLStreamWriter = createXmlStreamWriter(backingWriter);
210 NormalizedNodeStreamWriter streamWriter;
211 streamWriter = XMLStreamNormalizedNodeStreamWriter.create(createXMLStreamWriter, getSchemaContext());
212 return NormalizedNodeWriter.forStreamWriter(streamWriter);
215 private NormalizedNodeWriter createWriterBackedNormalizedNodeWriter(XMLStreamWriter backingWriter) {
216 Inference rootNode = SchemaInferenceStack.of(getSchemaContext()).toInference();
217 NormalizedNodeStreamWriter streamWriter = XMLStreamNormalizedNodeStreamWriter
218 .create(backingWriter, rootNode);
219 return NormalizedNodeWriter.forStreamWriter(streamWriter);
222 private static XMLStreamWriter createXmlStreamWriter(Writer backingWriter) {
223 XMLStreamWriter xmlStreamWriter;
225 XMLOutputFactory factory = XMLOutputFactory.newFactory();
226 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
227 xmlStreamWriter = factory.createXMLStreamWriter(backingWriter);
228 } catch (XMLStreamException | FactoryConfigurationError e) {
229 LOG.error("Error while creating XML writer: ", e);
230 throw new IllegalStateException(e);
232 return xmlStreamWriter;