2 * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.yangtools.yang.data.impl.codec.xml.retest;
11 import com.google.common.annotations.Beta;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
16 import java.util.Map.Entry;
17 import javax.annotation.Nonnull;
18 import javax.xml.stream.XMLStreamException;
19 import javax.xml.stream.XMLStreamWriter;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
23 import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
24 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlCodecProvider;
25 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
28 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * Utility class for bridging JAXP Stream and YANG Data APIs. Note that the definition of this class by no means final
39 * and subject to change as more functionality is centralized here.
41 * @deprecated Used for interim testing, to be removed in near future.
45 public class XmlStreamUtils {
46 private static final Logger LOG = LoggerFactory.getLogger(XmlStreamUtils.class);
47 private final XmlCodecProvider codecProvider;
48 private final Optional<SchemaContext> schemaContext;
50 protected XmlStreamUtils(final XmlCodecProvider codecProvider) {
51 this(codecProvider, null);
54 private XmlStreamUtils(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) {
55 this.codecProvider = Preconditions.checkNotNull(codecProvider);
56 this.schemaContext = Optional.fromNullable(schemaContext);
60 * Create a new instance encapsulating a particular codec provider.
62 * @param codecProvider
64 * @return A new instance
66 public static XmlStreamUtils create(final XmlCodecProvider codecProvider) {
67 return new XmlStreamUtils(codecProvider);
71 * Write an InstanceIdentifier into the output stream. Calling corresponding
72 * {@link XMLStreamWriter#writeStartElement(String)} and {@link XMLStreamWriter#writeEndElement()} is the
73 * responsibility of the caller.
79 * @throws XMLStreamException XMLStreamException object
81 * @deprecated Use {@link #writeInstanceIdentifier(XMLStreamWriter, YangInstanceIdentifier)} instead.
84 public static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final YangInstanceIdentifier id)
85 throws XMLStreamException {
86 Preconditions.checkNotNull(writer, "Writer may not be null");
87 Preconditions.checkNotNull(id, "Variable should contain instance of instance identifier and can't be null");
89 final RandomPrefix prefixes = new RandomPrefix();
90 final String str = XmlUtils.encodeIdentifier(prefixes, id);
91 writeNamespaceDeclarations(writer, prefixes.getPrefixes());
92 writer.writeCharacters(str);
96 static void writeAttribute(final XMLStreamWriter writer, final Entry<QName, String> attribute,
97 final RandomPrefix randomPrefix) throws XMLStreamException {
98 final QName key = attribute.getKey();
99 final String prefix = randomPrefix.encodePrefix(key.getNamespace());
100 writer.writeAttribute("xmlns:" + prefix, key.getNamespace().toString());
101 writer.writeAttribute(prefix, key.getNamespace().toString(), key.getLocalName(), attribute.getValue());
105 * Write a value into a XML stream writer. This method assumes the start and end of element is emitted by the
111 * Schema node that describes the value
115 * optional parameter of a module QName owning the leaf definition
116 * @throws XMLStreamException
117 * if an encoding problem occurs
119 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
120 final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
122 LOG.debug("Value of {}:{} is null, not encoding it", schemaNode.getQName().getNamespace(), schemaNode
123 .getQName().getLocalName());
129 schemaNode instanceof LeafSchemaNode || schemaNode instanceof LeafListSchemaNode,
130 "Unable to write value for node %s, only nodes of type: leaf and leaf-list can be written at this point",
131 schemaNode.getQName());
133 TypeDefinition<?> type = schemaNode instanceof LeafSchemaNode ? ((LeafSchemaNode) schemaNode).getType()
134 : ((LeafListSchemaNode) schemaNode).getType();
136 TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
138 if (schemaContext.isPresent() && baseType instanceof LeafrefTypeDefinition) {
139 LeafrefTypeDefinition leafrefTypeDefinition = (LeafrefTypeDefinition) baseType;
140 baseType = SchemaContextUtil.getBaseTypeForLeafRef(leafrefTypeDefinition, schemaContext.get(), schemaNode);
143 writeValue(writer, baseType, value, parent);
146 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
147 final Object value) throws XMLStreamException {
148 writeValue(writer, schemaNode, value, Optional.<QNameModule> absent());
151 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final SchemaNode schemaNode,
152 final Object value, final QNameModule parent) throws XMLStreamException {
153 writeValue(writer, schemaNode, value, Optional.of(parent));
157 * Write a value into a XML stream writer. This method assumes the start and end of element is emitted by the
163 * data type. In case of leaf ref this should be the type of leaf being referenced
167 * optional parameter of a module QName owning the leaf definition
168 * @throws XMLStreamException
169 * if an encoding problem occurs
171 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
172 final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
174 LOG.debug("Value of {}:{} is null, not encoding it", type.getQName().getNamespace(), type.getQName()
178 TypeDefinition<?> baseType = XmlUtils.resolveBaseTypeFrom(type);
180 if (baseType instanceof IdentityrefTypeDefinition) {
181 if (parent.isPresent()) {
182 write(writer, (IdentityrefTypeDefinition) baseType, value, parent);
184 write(writer, (IdentityrefTypeDefinition) baseType, value, Optional.<QNameModule> absent());
186 } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
187 write(writer, (InstanceIdentifierTypeDefinition) baseType, value);
189 final TypeDefinitionAwareCodec<Object, ?> codec = codecProvider.codecFor(type);
193 text = codec.serialize(value);
194 } catch (ClassCastException e) {
195 LOG.error("Provided node value {} did not have type {} required by mapping. Using stream instead.",
197 text = String.valueOf(value);
200 LOG.error("Failed to find codec for {}, falling back to using stream", type);
201 text = String.valueOf(value);
203 writer.writeCharacters(text);
207 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
208 final Object value, final QNameModule parent) throws XMLStreamException {
209 writeValue(writer, type, value, Optional.of(parent));
212 public void writeValue(@Nonnull final XMLStreamWriter writer, @Nonnull final TypeDefinition<?> type,
213 final Object value) throws XMLStreamException {
214 writeValue(writer, type, value, Optional.<QNameModule> absent());
218 static void write(@Nonnull final XMLStreamWriter writer, @Nonnull final IdentityrefTypeDefinition type,
219 @Nonnull final Object value, final Optional<QNameModule> parent) throws XMLStreamException {
220 if (value instanceof QName) {
221 final QName qname = (QName) value;
222 final String prefix = "x";
224 // in case parent is present and same as element namespace write value without namespace
225 if (parent.isPresent() && qname.getNamespace().equals(parent.get().getNamespace())) {
226 writer.writeCharacters(qname.getLocalName());
228 final String ns = qname.getNamespace().toString();
229 writer.writeNamespace(prefix, ns);
230 writer.writeCharacters(prefix + ':' + qname.getLocalName());
234 LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName()
235 .getLocalName(), value.getClass());
236 writer.writeCharacters(String.valueOf(value));
240 private void write(@Nonnull final XMLStreamWriter writer, @Nonnull final InstanceIdentifierTypeDefinition type,
241 @Nonnull final Object value) throws XMLStreamException {
242 if (value instanceof YangInstanceIdentifier) {
243 writeInstanceIdentifier(writer, (YangInstanceIdentifier) value);
245 LOG.warn("Value of {}:{} is not an InstanceIdentifier but {}", type.getQName().getNamespace(), type
246 .getQName().getLocalName(), value.getClass());
247 writer.writeCharacters(String.valueOf(value));
251 public void writeInstanceIdentifier(final XMLStreamWriter writer, final YangInstanceIdentifier value) throws XMLStreamException {
252 if (schemaContext.isPresent()) {
253 RandomPrefixInstanceIdentifierSerializer iiCodec = new RandomPrefixInstanceIdentifierSerializer(
254 schemaContext.get());
255 String serializedValue = iiCodec.serialize(value);
256 writeNamespaceDeclarations(writer, iiCodec.getPrefixes());
257 writer.writeCharacters(serializedValue);
259 LOG.warn("Schema context not present in {}, serializing {} without schema.", this, value);
260 write(writer, value);
264 private static void writeNamespaceDeclarations(final XMLStreamWriter writer, final Iterable<Entry<URI, String>> prefixes)
265 throws XMLStreamException {
266 for (Entry<URI, String> e : prefixes) {
267 final String ns = e.getKey().toString();
268 final String p = e.getValue();
269 writer.writeNamespace(p, ns);
273 public static XmlStreamUtils create(final XmlCodecProvider codecProvider, final SchemaContext schemaContext) {
274 return new XmlStreamUtils(codecProvider, schemaContext);