NPE prevention in log
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / xml / XmlDocumentUtils.java
index b066afd517a7586f87f13c2565c96683cae18deb..ca66967f9dc4ac68cad4e737673d4784256daf83 100644 (file)
@@ -1,9 +1,17 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.yangtools.yang.data.impl.codec.xml;
 
 import static com.google.common.base.Preconditions.checkState;
 
 import java.net.URI;
 import java.util.List;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import javax.activation.UnsupportedDataTypeException;
@@ -12,6 +20,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
@@ -28,7 +37,6 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SimpleValueSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
 import org.slf4j.Logger;
@@ -79,60 +87,9 @@ public class XmlDocumentUtils {
         }
     }
 
-    public static Node<?> toDomNode(Element xmlElement, Optional<DataSchemaNode> schema,
-            Optional<XmlCodecProvider> codecProvider) {
-        if (schema.isPresent()) {
-            return toNodeWithSchema(xmlElement, schema.get(), codecProvider.or(DEFAULT_XML_VALUE_CODEC_PROVIDER));
-        }
-        return toDomNode(xmlElement);
-    }
-
-    public static CompositeNode fromElement(Element xmlElement) {
-        CompositeNodeBuilder<ImmutableCompositeNode> node = ImmutableCompositeNode.builder();
-        node.setQName(qNameFromElement(xmlElement));
-
-        return node.toInstance();
-    }
-
-    private static QName qNameFromElement(Element xmlElement) {
-        String namespace = xmlElement.getNamespaceURI();
-        String localName = xmlElement.getLocalName();
-        return QName.create(namespace != null ? URI.create(namespace) : null, null, localName);
-    }
-
-    private static Node<?> toNodeWithSchema(Element xmlElement, DataSchemaNode schema, XmlCodecProvider codecProvider) {
-        checkQName(xmlElement, schema.getQName());
-        if (schema instanceof DataNodeContainer) {
-            return toCompositeNodeWithSchema(xmlElement, schema.getQName(), (DataNodeContainer) schema, codecProvider);
-        } else if (schema instanceof SimpleValueSchemaNode) {
-            return toSimpleNodeWithType(xmlElement, (SimpleValueSchemaNode) schema, codecProvider);
-        }
-        return null;
-    }
-
-    private static Node<?> toSimpleNodeWithType(Element xmlElement, SimpleValueSchemaNode schema,
-            XmlCodecProvider codecProvider) {
-        TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = codecProvider.codecFor(schema.getType());
-        String text = xmlElement.getTextContent();
-        Object value = codec.deserialize(text);
-        return new SimpleNodeTOImpl<Object>(schema.getQName(), null, value);
-    }
-
-    private static Node<?> toCompositeNodeWithSchema(Element xmlElement, QName qName, DataNodeContainer schema,
-            XmlCodecProvider codecProvider) {
-        List<Node<?>> values = toDomNodes(xmlElement, Optional.fromNullable(schema.getChildNodes()));
-        return new ImmutableCompositeNode(qName, values );
-    }
-
-    private static void checkQName(Element xmlElement, QName qName) {
-        checkState(Objects.equal(xmlElement.getNamespaceURI(), qName.getNamespace().toString()));
-        checkState(qName.getLocalName().equals(xmlElement.getLocalName()));
-    }
-
     private static Element createXmlRootElement(Document doc, Node<?> data, SchemaNode schema,
             XmlCodecProvider codecProvider) throws UnsupportedDataTypeException {
-        QName dataType = data.getNodeType();
-        Element itemEl = createElementFor(doc, dataType);
+        Element itemEl = createElementFor(doc, data);
         if (data instanceof SimpleNode<?>) {
             if (schema instanceof LeafListSchemaNode) {
                 writeValueByType(itemEl, (SimpleNode<?>) data, ((LeafListSchemaNode) schema).getType(),
@@ -165,12 +122,22 @@ public class XmlDocumentUtils {
         return itemEl;
     }
 
-    private static Element createElementFor(Document doc, QName dataType) {
+    private static Element createElementFor(Document doc, Node<?> data) {
+        QName dataType = data.getNodeType();
+        Element ret;
         if (dataType.getNamespace() != null) {
-            return doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
+            ret = doc.createElementNS(dataType.getNamespace().toString(), dataType.getLocalName());
         } else {
-            return doc.createElementNS(null, dataType.getLocalName());
+            ret = doc.createElementNS(null, dataType.getLocalName());
+        }
+        if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
+            for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
+                ret.setAttributeNS(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(),
+                        attribute.getValue());
+            }
+
         }
+        return ret;
     }
 
     public static void writeValueByType(Element element, SimpleNode<?> node, TypeDefinition<?> type,
@@ -188,19 +155,28 @@ public class XmlDocumentUtils {
                 element.setAttribute("xmlns:" + prefix, value.getNamespace().toString());
                 element.setTextContent(prefix + ":" + value.getLocalName());
             } else {
+                Object value = node.getValue();
                 logger.debug("Value of {}:{} is not instance of QName but is {}", baseType.getQName().getNamespace(), //
                         baseType.getQName().getLocalName(), //
-                        node.getValue().getClass());
-                element.setTextContent(String.valueOf(node.getValue()));
+                        node != null ? value.getClass() : "null");
+                if (value != null) {
+                    element.setTextContent(String.valueOf(value));
+                }
             }
         } else {
             if (node.getValue() != null) {
-                try {
-                    String value = codecProvider.codecFor(baseType).serialize(node.getValue());
-                    element.setTextContent(value);
-                } catch (ClassCastException e) {
+                final TypeDefinitionAwareCodec<Object, ?> codec = codecProvider.codecFor(baseType);
+                if (codec != null) {
+                    try {
+                        final String text = codec.serialize(node.getValue());
+                        element.setTextContent(text);
+                    } catch (ClassCastException e) {
+                        logger.error("Provided node did not have type required by mapping. Using stream instead.", e);
+                        element.setTextContent(String.valueOf(node.getValue()));
+                    }
+                } else {
+                    logger.error("Failed to find codec for {}, falling back to using stream", baseType);
                     element.setTextContent(String.valueOf(node.getValue()));
-                    logger.error("Provided node did not have type required by mapping. Using stream instead. {}", e);
                 }
             }
         }
@@ -232,6 +208,79 @@ public class XmlDocumentUtils {
         return null;
     }
 
+    public static Node<?> toDomNode(Element xmlElement, Optional<DataSchemaNode> schema,
+            Optional<XmlCodecProvider> codecProvider) {
+        if (schema.isPresent()) {
+            return toNodeWithSchema(xmlElement, schema.get(), codecProvider.or(DEFAULT_XML_VALUE_CODEC_PROVIDER));
+        }
+        return toDomNode(xmlElement);
+    }
+
+    public static CompositeNode fromElement(Element xmlElement) {
+        CompositeNodeBuilder<ImmutableCompositeNode> node = ImmutableCompositeNode.builder();
+        node.setQName(qNameFromElement(xmlElement));
+
+        return node.toInstance();
+    }
+
+    private static QName qNameFromElement(Element xmlElement) {
+        String namespace = xmlElement.getNamespaceURI();
+        String localName = xmlElement.getLocalName();
+        return QName.create(namespace != null ? URI.create(namespace) : null, null, localName);
+    }
+
+    private static Node<?> toNodeWithSchema(Element xmlElement, DataSchemaNode schema, XmlCodecProvider codecProvider) {
+        checkQName(xmlElement, schema.getQName());
+        if (schema instanceof DataNodeContainer) {
+            return toCompositeNodeWithSchema(xmlElement, schema.getQName(), (DataNodeContainer) schema, codecProvider);
+        } else if (schema instanceof LeafSchemaNode) {
+            return toSimpleNodeWithType(xmlElement, (LeafSchemaNode) schema, codecProvider);
+        } else if (schema instanceof LeafListSchemaNode) {
+            return toSimpleNodeWithType(xmlElement, (LeafListSchemaNode) schema, codecProvider);
+
+        }
+        return null;
+    }
+
+    private static Node<?> toSimpleNodeWithType(Element xmlElement, LeafSchemaNode schema,
+            XmlCodecProvider codecProvider) {
+        TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = codecProvider.codecFor(schema.getType());
+        String text = xmlElement.getTextContent();
+        Object value;
+        if (codec != null) {
+            value = codec.deserialize(text);
+
+        } else {
+            value = xmlElement.getTextContent();
+        }
+        return new SimpleNodeTOImpl<Object>(schema.getQName(), null, value);
+    }
+
+    private static Node<?> toSimpleNodeWithType(Element xmlElement, LeafListSchemaNode schema,
+            XmlCodecProvider codecProvider) {
+        TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> codec = codecProvider.codecFor(schema.getType());
+        String text = xmlElement.getTextContent();
+        Object value;
+        if (codec != null) {
+            value = codec.deserialize(text);
+
+        } else {
+            value = xmlElement.getTextContent();
+        }
+        return new SimpleNodeTOImpl<Object>(schema.getQName(), null, value);
+    }
+
+    private static Node<?> toCompositeNodeWithSchema(Element xmlElement, QName qName, DataNodeContainer schema,
+            XmlCodecProvider codecProvider) {
+        List<Node<?>> values = toDomNodes(xmlElement, Optional.fromNullable(schema.getChildNodes()));
+        return ImmutableCompositeNode.create(qName, values);
+    }
+
+    private static void checkQName(Element xmlElement, QName qName) {
+        checkState(Objects.equal(xmlElement.getNamespaceURI(), qName.getNamespace().toString()));
+        checkState(qName.getLocalName().equals(xmlElement.getLocalName()));
+    }
+
     private static final Optional<DataSchemaNode> findFirstSchema(QName qname, Set<DataSchemaNode> dataSchemaNode) {
         if (dataSchemaNode != null && !dataSchemaNode.isEmpty() && qname != null) {
             for (DataSchemaNode dsn : dataSchemaNode) {
@@ -250,10 +299,6 @@ public class XmlDocumentUtils {
         return Optional.absent();
     }
 
-    public static final XmlCodecProvider defaultValueCodecProvider() {
-        return DEFAULT_XML_VALUE_CODEC_PROVIDER;
-    }
-
     public static Node<?> toDomNode(Document doc) {
         return toDomNode(doc.getDocumentElement());
     }
@@ -281,7 +326,7 @@ public class XmlDocumentUtils {
         if (isSimpleObject) {
             return new SimpleNodeTOImpl<>(qname, null, value);
         }
-        return new ImmutableCompositeNode(qname, values.build());
+        return ImmutableCompositeNode.create(qname, values.build());
     }
 
     public static List<Node<?>> toDomNodes(final Element element, final Optional<Set<DataSchemaNode>> context) {
@@ -308,9 +353,9 @@ public class XmlDocumentUtils {
         ImmutableList.Builder<T> ret = ImmutableList.<T> builder();
         for (int i = 0; i < nodes.getLength(); i++) {
             org.w3c.dom.Node child = nodes.item(i);
-            if(child instanceof Element) {
+            if (child instanceof Element) {
                 Optional<T> result = forBody.apply((Element) child);
-                if(result.isPresent()) {
+                if (result.isPresent()) {
                     ret.add(result.get());
                 }
             }
@@ -318,4 +363,8 @@ public class XmlDocumentUtils {
         return ret.build();
     }
 
+    public static final XmlCodecProvider defaultValueCodecProvider() {
+        return DEFAULT_XML_VALUE_CODEC_PROVIDER;
+    }
+
 }