AbstractDocumentWriter.java

/*
 * Copyright (C) 2006, 2007, 2009, 2011, 2014, 2015, 2018 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 * Created on 18. October 2007 by Joerg Schaible
 */
package com.thoughtworks.xstream.io.xml;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.core.util.FastStack;
import com.thoughtworks.xstream.io.naming.NameCoder;


/**
 * A generic {@link com.thoughtworks.xstream.io.HierarchicalStreamWriter} for DOM writer implementations. The
 * implementation manages a list of top level DOM nodes. Every time the last node is closed on the node stack, the next
 * started node is added to the list. This list can be retrieved using the {@link DocumentWriter#getTopLevelNodes()}
 * method.
 *
 * @author Laurent Bihanic
 * @author Jörg Schaible
 * @since 1.2.1
 */
public abstract class AbstractDocumentWriter<R, E extends R> extends AbstractXmlWriter implements DocumentWriter<R> {

    private final List<R> result = new ArrayList<>();
    private final FastStack<R> nodeStack = new FastStack<>(16);

    /**
     * Constructs an AbstractDocumentWriter.
     *
     * @param container the top level container for the nodes to create (may be <code>null</code>)
     * @param nameCoder the object that creates XML-friendly names
     * @since 1.4
     */
    public AbstractDocumentWriter(final R container, final NameCoder nameCoder) {
        super(nameCoder);
        if (container != null) {
            nodeStack.push(container);
            result.add(container);
        }
    }

    /**
     * Constructs an AbstractDocumentWriter.
     *
     * @param container the top level container for the nodes to create (may be <code>null</code>)
     * @param replacer the object that creates XML-friendly names
     * @since 1.2.1
     * @deprecated As of 1.4 use {@link AbstractDocumentWriter#AbstractDocumentWriter(Object, NameCoder)} instead.
     */
    @Deprecated
    public AbstractDocumentWriter(final R container, final XmlFriendlyReplacer replacer) {
        this(container, (NameCoder)replacer);
    }

    @Override
    public final void startNode(final String name) {
        final E node = createNode(name);
        nodeStack.push(node);
    }

    /**
     * Create a node. The provided node name is not yet XML friendly. If {@link #getCurrent()} returns <code>null</code>
     * the node is a top level node.
     *
     * @param name the node name
     * @return the new node
     * @since 1.2.1
     */
    protected abstract E createNode(String name);

    @Override
    public final void endNode() {
        endNodeInternally();
        final R node = nodeStack.pop();
        if (nodeStack.size() == 0) {
            result.add(node);
        }
    }

    /**
     * Called when a node ends. Hook for derived implementations.
     *
     * @since 1.2.1
     */
    public void endNodeInternally() {
    }

    /**
     * @since 1.2.1
     */
    protected final R getCurrent() {
        return nodeStack.peek();
    }

    @Override
    public List<R> getTopLevelNodes() {
        return result;
    }

    @Override
    public void flush() {
        // don't need to do anything
    }

    @Override
    public void close() {
        // don't need to do anything
    }
}