Refactor implementations to hide XMLStreamWriter
[yangtools.git] / yang / yang-data-codec-xml / src / main / java / org / opendaylight / yangtools / yang / data / codec / xml / XMLStreamNormalizedNodeStreamWriter.java
index 6eb16b97ebe2f46afeabf28e398c81759451ee74..55e4e93b243bd439326b77b7bd459e2e308aa9b3 100644 (file)
@@ -7,7 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.xml;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.base.Strings;
 import java.io.IOException;
 import java.io.StringWriter;
@@ -16,8 +18,6 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 import javax.xml.XMLConstants;
 import javax.xml.namespace.NamespaceContext;
 import javax.xml.stream.XMLStreamException;
@@ -30,6 +30,8 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stax.StAXResult;
 import javax.xml.transform.stream.StreamResult;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
@@ -51,30 +53,32 @@ import org.w3c.dom.Element;
  */
 public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements NormalizedNodeStreamAttributeWriter {
     private static final Logger LOG = LoggerFactory.getLogger(XMLStreamNormalizedNodeStreamWriter.class);
-    private static final String COM_SUN_TRANSFORMER = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
+    private static final String COM_SUN_TRANSFORMER =
+        "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
+
+    static final TransformerFactory TRANSFORMER_FACTORY;
 
-    private static final TransformerFactory TRANSFORMER_FACTORY;
     static {
-        TransformerFactory f = TransformerFactory.newInstance();
-        if (!f.getFeature(StAXResult.FEATURE)) {
+        TransformerFactory fa = TransformerFactory.newInstance();
+        if (!fa.getFeature(StAXResult.FEATURE)) {
             LOG.warn("Platform-default TransformerFactory {} does not support StAXResult, attempting fallback to {}",
-                    f, COM_SUN_TRANSFORMER);
-            f = TransformerFactory.newInstance(COM_SUN_TRANSFORMER, null);
-            if (!f.getFeature(StAXResult.FEATURE)) {
+                    fa, COM_SUN_TRANSFORMER);
+            fa = TransformerFactory.newInstance(COM_SUN_TRANSFORMER, null);
+            if (!fa.getFeature(StAXResult.FEATURE)) {
                 throw new TransformerFactoryConfigurationError("No TransformerFactory supporting StAXResult found.");
             }
         }
 
-        TRANSFORMER_FACTORY = f;
+        TRANSFORMER_FACTORY = fa;
     }
 
     private static final Set<String> BROKEN_NAMESPACES = ConcurrentHashMap.newKeySet();
 
+    private final @NonNull XMLStreamWriter writer;
     private final RandomPrefix prefixes;
-    final XMLStreamWriter writer;
 
     XMLStreamNormalizedNodeStreamWriter(final XMLStreamWriter writer) {
-        this.writer = Preconditions.checkNotNull(writer);
+        this.writer = requireNonNull(writer);
         this.prefixes = new RandomPrefix(writer.getNamespaceContext());
     }
 
@@ -90,7 +94,7 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
     }
 
     /**
-     * Create a new writer with the specified context and rooted in the specified schema path
+     * Create a new writer with the specified context and rooted in the specified schema path.
      *
      * @param writer Output {@link XMLStreamWriter}
      * @param context Associated {@link SchemaContext}.
@@ -98,9 +102,9 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      *
      * @return A new {@link NormalizedNodeStreamWriter}
      */
-    public static NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context,
+    public static @NonNull NormalizedNodeStreamWriter create(final XMLStreamWriter writer, final SchemaContext context,
             final SchemaPath path) {
-        return SchemaAwareXMLStreamNormalizedNodeStreamWriter.newInstance(writer, context, path);
+        return new SchemaAwareXMLStreamNormalizedNodeStreamWriter(writer, context, path);
     }
 
     /**
@@ -111,33 +115,31 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
      *
      * @return A new {@link NormalizedNodeStreamWriter}
      */
-    public static NormalizedNodeStreamWriter createSchemaless(final XMLStreamWriter writer) {
-        return SchemalessXMLStreamNormalizedNodeStreamWriter.newInstance(writer);
+    public static @NonNull NormalizedNodeStreamWriter createSchemaless(final XMLStreamWriter writer) {
+        return new SchemalessXMLStreamNormalizedNodeStreamWriter(writer);
     }
 
-    abstract void writeValue(final XMLStreamWriter xmlWriter, final QName qname,
-            @Nonnull final Object value, T context) throws IOException, XMLStreamException;
-
-    abstract void startList(final NodeIdentifier name);
+    abstract void writeValue(@NonNull XMLStreamWriter xmlWriter, QName qname, @NonNull Object value, T context)
+            throws IOException, XMLStreamException;
 
-    abstract void startListItem(final PathArgument name) throws IOException;
+    abstract void startList(NodeIdentifier name);
 
-    abstract void endNode(XMLStreamWriter xmlWriter) throws IOException, XMLStreamException;
+    abstract void startListItem(PathArgument name) throws IOException;
 
-    private void writeAttributes(@Nonnull final Map<QName, String> attributes) throws IOException {
-        for (final Entry<QName, String> qNameStringEntry : attributes.entrySet()) {
+    private void writeAttributes(final @NonNull Map<QName, String> attributes) throws IOException {
+        for (final Entry<QName, String> entry : attributes.entrySet()) {
             try {
-                final QName qname = qNameStringEntry.getKey();
+                final QName qname = entry.getKey();
                 final String namespace = qname.getNamespace().toString();
 
                 if (!Strings.isNullOrEmpty(namespace)) {
                     final String prefix = getPrefix(qname.getNamespace(), namespace);
-                    writer.writeAttribute(prefix, namespace, qname.getLocalName(), qNameStringEntry.getValue());
+                    writer.writeAttribute(prefix, namespace, qname.getLocalName(), entry.getValue());
                 } else {
-                    writer.writeAttribute(qname.getLocalName(), qNameStringEntry.getValue());
+                    writer.writeAttribute(qname.getLocalName(), entry.getValue());
                 }
             } catch (final XMLStreamException e) {
-                throw new IOException("Unable to emit attribute " + qNameStringEntry, e);
+                throw new IOException("Unable to emit attribute " + entry, e);
             }
         }
     }
@@ -159,22 +161,30 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
     }
 
     private void writeStartElement(final QName qname) throws XMLStreamException {
-        String ns = qname.getNamespace().toString();
+        final String ns = qname.getNamespace().toString();
+        final NamespaceContext context = writer.getNamespaceContext();
+        final boolean needDefaultNs;
+        if (context != null) {
+            final String parentNs = context.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
+            needDefaultNs = !ns.equals(parentNs);
+        } else {
+            needDefaultNs = false;
+        }
+
         writer.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, qname.getLocalName(), ns);
-        if (writer.getNamespaceContext() != null) {
-            String parentNs = writer.getNamespaceContext().getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX);
-            if (!ns.equals(parentNs)) {
-                writer.writeDefaultNamespace(ns);
-            }
+        if (needDefaultNs) {
+            writer.writeDefaultNamespace(ns);
         }
     }
 
-    void writeElement(final QName qname, final Object value, @Nullable final Map<QName, String> attributes,
+    final void writeElement(final QName qname, final Object value, final @Nullable Map<QName, String> attributes,
             final T context) throws IOException {
         try {
             writeStartElement(qname);
 
-            writeAttributes(attributes);
+            if (attributes != null) {
+                writeAttributes(attributes);
+            }
             if (value != null) {
                 writeValue(writer, qname, value, context);
             }
@@ -184,7 +194,7 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
         }
     }
 
-    void startElement(final QName qname) throws IOException {
+    final void startElement(final QName qname) throws IOException {
         try {
             writeStartElement(qname);
         } catch (XMLStreamException e) {
@@ -192,18 +202,27 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
         }
     }
 
-    void anyxmlNode(final QName qname, final Object value) throws IOException {
+    final void endElement() throws IOException {
+        try {
+            writer.writeEndElement();
+        } catch (XMLStreamException e) {
+            throw new IOException("Failed to end element", e);
+        }
+    }
+
+    final void anyxmlNode(final QName qname, final Object value) throws IOException {
         if (value != null) {
-            Preconditions.checkArgument(value instanceof DOMSource, "AnyXML value must be DOMSource, not %s", value);
+            checkArgument(value instanceof DOMSource, "AnyXML value must be DOMSource, not %s", value);
             final DOMSource domSource = (DOMSource) value;
-            Preconditions.checkNotNull(domSource.getNode());
-            Preconditions.checkArgument(domSource.getNode().getNodeName().equals(qname.getLocalName()));
-            Preconditions.checkArgument(domSource.getNode().getNamespaceURI().equals(qname.getNamespace().toString()));
+            requireNonNull(domSource.getNode());
+            checkArgument(domSource.getNode().getNodeName().equals(qname.getLocalName()));
+            checkArgument(domSource.getNode().getNamespaceURI().equals(qname.getNamespace().toString()));
             try {
                 // TODO can the transformer be a constant ? is it thread safe ?
                 final Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
                 // Writer has to be wrapped in a wrapper that ignores endDocument event
-                // EndDocument event forbids any other modification to the writer so a nested anyXml breaks serialization
+                // EndDocument event forbids any other modification to the writer so a nested anyXml breaks
+                // serialization
                 transformer.transform(domSource, new StAXResult(new DelegateWriterNoEndDoc(writer)));
             } catch (final TransformerException e) {
                 throw new IOException("Unable to transform anyXml(" + qname + ") value: " + value, e);
@@ -232,6 +251,11 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
         writeAttributes(attributes);
     }
 
+    @Override
+    public final void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
+        startListItem(name);
+    }
+
     @Override
     public final void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint,
                                         final Map<QName, String> attributes) throws IOException {
@@ -240,13 +264,14 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
     }
 
     @Override
-    public final void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
-        startList(name);
+    public final void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
+            throws IOException {
+        startListItem(identifier);
     }
 
     @Override
-    public final void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
-        startListItem(name);
+    public final void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) {
+        startList(name);
     }
 
     @Override
@@ -254,12 +279,6 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
         startList(name);
     }
 
-    @Override
-    public final void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
-            throws IOException {
-        startListItem(identifier);
-    }
-
     @Override
     public final void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) {
         startList(name);
@@ -267,7 +286,7 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
 
     public static String toString(final Element xml) {
         try {
-            final Transformer transformer = TransformerFactory.newInstance().newTransformer();
+            final Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
 
             final StreamResult result = new StreamResult(new StringWriter());
@@ -275,17 +294,8 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
             transformer.transform(source, result);
 
             return result.getWriter().toString();
-        } catch (IllegalArgumentException | TransformerFactoryConfigurationError | TransformerException e) {
-            throw new RuntimeException("Unable to serialize xml element " + xml, e);
-        }
-    }
-
-    @Override
-    public final void endNode() throws IOException {
-        try {
-            endNode(writer);
-        } catch (XMLStreamException e) {
-            throw new IOException("Failed to end element", e);
+        } catch (IllegalArgumentException | TransformerException e) {
+            throw new IllegalStateException("Unable to serialize xml element " + xml, e);
         }
     }
 
@@ -313,7 +323,7 @@ public abstract class XMLStreamNormalizedNodeStreamWriter<T> implements Normaliz
     private static final class DelegateWriterNoEndDoc implements XMLStreamWriter {
         private final XMLStreamWriter writer;
 
-        public DelegateWriterNoEndDoc(final XMLStreamWriter writer) {
+        DelegateWriterNoEndDoc(final XMLStreamWriter writer) {
             this.writer = writer;
         }