org.jboss.bpm.console.server.util.DOMUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.bpm.console.server.util.DOMUtils.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.bpm.console.server.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.*;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.util.*;

/**
 * DOM2 utilites
 *
 * @author Thomas.Diesler@jboss.org
 * @author alessio.soldano@jboss.com
 */
public final class DOMUtils {
    private static Log log = LogFactory.getLog(DOMUtils.class);

    // All elements created by the same thread are created by the same builder and belong to the same doc
    private static ThreadLocal<Document> documentThreadLocal = new ThreadLocal<Document>();
    private static ThreadLocal<DocumentBuilder> builderThreadLocal = new ThreadLocal<DocumentBuilder>() {
        protected DocumentBuilder initialValue() {
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setValidating(false);
                factory.setNamespaceAware(true);
                DocumentBuilder builder = factory.newDocumentBuilder();
                setEntityResolver(builder);
                return builder;
            } catch (ParserConfigurationException e) {
                throw new RuntimeException("Failed to create DocumentBuilder", e);
            }
        }

        private void setEntityResolver(DocumentBuilder builder) {
            String[] resolvers = new String[] { "org.jboss.ws.core.utils.JBossWSEntityResolver",
                    "org.jboss.util.xml.JBossEntityResolver" };

            EntityResolver entityResolver = null;
            ClassLoader loader = Thread.currentThread().getContextClassLoader();
            for (String resolver : resolvers) {
                try {
                    Class<?> resolverClass = loader.loadClass(resolver);
                    entityResolver = (EntityResolver) resolverClass.newInstance();
                } catch (Exception ex) {
                    log.debug("Cannot load: " + resolver);
                }
            }

            if (entityResolver != null)
                builder.setEntityResolver(entityResolver);
        }
    };

    public static void clearThreadLocals() {
        documentThreadLocal.remove();
        builderThreadLocal.remove();
    }

    // Hide the constructor
    private DOMUtils() {
    }

    /** Initialize the DocumentBuilder
     */
    public static DocumentBuilder getDocumentBuilder() {
        return builderThreadLocal.get();
    }

    /** Parse the given XML string and return the root Element
     */
    public static Element parse(String xmlString) throws IOException {
        try {
            return parse(new ByteArrayInputStream(xmlString.getBytes("UTF-8")));
        } catch (IOException e) {
            log.error("Cannot parse: " + xmlString);
            throw e;
        }
    }

    /** Parse the given XML stream and return the root Element
     */
    public static Element parse(InputStream xmlStream) throws IOException {
        try {
            return getDocumentBuilder().parse(xmlStream).getDocumentElement();
        } catch (SAXException se) {
            throw new IOException(se.toString());
        } finally {
            xmlStream.close();
        }
    }

    /** Parse the given input source and return the root Element
     */
    public static Element parse(InputSource source) throws IOException {
        try {
            return getDocumentBuilder().parse(source).getDocumentElement();
        } catch (SAXException se) {
            throw new IOException(se.toString());
        } finally {
            InputStream is = source.getByteStream();
            if (is != null) {
                is.close();
            }
            Reader r = source.getCharacterStream();
            if (r != null) {
                r.close();
            }
        }
    }

    /** Create an Element for a given name
     */
    public static Element createElement(String localPart) {
        Document doc = getOwnerDocument();
        log.trace("createElement {}" + localPart);
        return doc.createElement(localPart);
    }

    /** Create an Element for a given name and prefix
     */
    public static Element createElement(String localPart, String prefix) {
        Document doc = getOwnerDocument();
        log.trace("createElement {}" + prefix + ":" + localPart);
        return doc.createElement(prefix + ":" + localPart);
    }

    /** Create an Element for a given name, prefix and uri
     */
    public static Element createElement(String localPart, String prefix, String uri) {
        Document doc = getOwnerDocument();
        if (prefix == null || prefix.length() == 0) {
            log.trace("createElement {" + uri + "}" + localPart);
            return doc.createElementNS(uri, localPart);
        } else {
            log.trace("createElement {" + uri + "}" + prefix + ":" + localPart);
            return doc.createElementNS(uri, prefix + ":" + localPart);
        }
    }

    /** Create an Element for a given QName
     */
    public static Element createElement(QName qname) {
        return createElement(qname.getLocalPart(), qname.getPrefix(), qname.getNamespaceURI());
    }

    /** Create a org.w3c.dom.Text node
     */
    public static Text createTextNode(String value) {
        Document doc = getOwnerDocument();
        return doc.createTextNode(value);
    }

    /** Get the qname of the given node.
     */
    public static QName getElementQName(Element el) {
        String qualifiedName = el.getNodeName();
        return resolveQName(el, qualifiedName);
    }

    /** Transform the given qualified name into a QName
     */
    public static QName resolveQName(Element el, String qualifiedName) {
        QName qname;
        String prefix = "";
        String namespaceURI = "";
        String localPart = qualifiedName;

        int colIndex = qualifiedName.indexOf(":");
        if (colIndex > 0) {
            prefix = qualifiedName.substring(0, colIndex);
            localPart = qualifiedName.substring(colIndex + 1);

            if ("xmlns".equals(prefix)) {
                namespaceURI = "URI:XML_PREDEFINED_NAMESPACE";
            } else {
                Element nsElement = el;
                while (namespaceURI.equals("") && nsElement != null) {
                    namespaceURI = nsElement.getAttribute("xmlns:" + prefix);
                    if (namespaceURI.equals(""))
                        nsElement = getParentElement(nsElement);
                }
            }

            if (namespaceURI.equals(""))
                throw new IllegalArgumentException("Cannot find namespace uri for: " + qualifiedName);
        } else {
            Element nsElement = el;
            while (namespaceURI.equals("") && nsElement != null) {
                namespaceURI = nsElement.getAttribute("xmlns");
                if (namespaceURI.equals(""))
                    nsElement = getParentElement(nsElement);
            }
        }

        qname = new QName(namespaceURI, localPart, prefix);
        return qname;
    }

    /** Get the value from the given attribute
     *
     * @return null if the attribute value is empty or the attribute is not present
     */
    public static String getAttributeValue(Element el, String attrName) {
        return getAttributeValue(el, new QName(attrName));
    }

    /** Get the value from the given attribute
     *
     * @return null if the attribute value is empty or the attribute is not present
     */
    public static String getAttributeValue(Element el, QName attrName) {
        String attr = null;
        if ("".equals(attrName.getNamespaceURI()))
            attr = el.getAttribute(attrName.getLocalPart());
        else
            attr = el.getAttributeNS(attrName.getNamespaceURI(), attrName.getLocalPart());

        if ("".equals(attr))
            attr = null;

        return attr;
    }

    /** Get the qname value from the given attribute
     */
    public static QName getAttributeValueAsQName(Element el, String attrName) {
        return getAttributeValueAsQName(el, new QName(attrName));

    }

    /** Get the qname value from the given attribute
     */
    public static QName getAttributeValueAsQName(Element el, QName attrName) {
        QName qname = null;

        String qualifiedName = getAttributeValue(el, attrName);
        if (qualifiedName != null) {
            qname = resolveQName(el, qualifiedName);
        }

        return qname;
    }

    /** Get the boolean value from the given attribute
     */
    public static boolean getAttributeValueAsBoolean(Element el, String attrName) {
        return getAttributeValueAsBoolean(el, new QName(attrName));
    }

    /** Get the boolean value from the given attribute
     */
    public static boolean getAttributeValueAsBoolean(Element el, QName attrName) {
        String attrVal = getAttributeValue(el, attrName);
        boolean ret = "true".equalsIgnoreCase(attrVal) || "1".equalsIgnoreCase(attrVal);
        return ret;
    }

    /** Get the integer value from the given attribute
     */
    public static Integer getAttributeValueAsInteger(Element el, String attrName) {
        return getAttributeValueAsInteger(el, new QName(attrName));
    }

    /** Get the integer value from the given attribute
     */
    public static Integer getAttributeValueAsInteger(Element el, QName attrName) {
        String attrVal = getAttributeValue(el, attrName);
        return (attrVal != null ? new Integer(attrVal) : null);
    }

    /** Get the attributes as Map<QName, String>
     */
    public static Map getAttributes(Element el) {
        Map attmap = new HashMap();
        NamedNodeMap attribs = el.getAttributes();
        for (int i = 0; i < attribs.getLength(); i++) {
            Attr attr = (Attr) attribs.item(i);
            String name = attr.getName();
            QName qname = resolveQName(el, name);
            String value = attr.getNodeValue();
            attmap.put(qname, value);
        }
        return attmap;
    }

    /** Copy attributes between elements
     */
    public static void copyAttributes(Element destElement, Element srcElement) {
        NamedNodeMap attribs = srcElement.getAttributes();
        for (int i = 0; i < attribs.getLength(); i++) {
            Attr attr = (Attr) attribs.item(i);
            String uri = attr.getNamespaceURI();
            String qname = attr.getName();
            String value = attr.getNodeValue();

            // Prevent DOMException: NAMESPACE_ERR: An attempt is made to create or
            // change an object in a way which is incorrect with regard to namespaces.
            if (uri == null && qname.startsWith("xmlns")) {
                log.trace("Ignore attribute: [uri=" + uri + ",qname=" + qname + ",value=" + value + "]");
            } else {
                destElement.setAttributeNS(uri, qname, value);
            }
        }
    }

    /** True if the node has text child elements only
     */
    public static boolean hasTextChildNodesOnly(Node node) {
        NodeList nodeList = node.getChildNodes();
        if (nodeList.getLength() == 0)
            return false;

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node acksToChildNode = nodeList.item(i);
            if (acksToChildNode.getNodeType() != Node.TEXT_NODE)
                return false;
        }

        return true;
    }

    /** True if the node has child elements
     */
    public static boolean hasChildElements(Node node) {
        NodeList nlist = node.getChildNodes();
        for (int i = 0; i < nlist.getLength(); i++) {
            Node child = nlist.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE)
                return true;
        }
        return false;
    }

    /** Gets child elements
     */
    public static Iterator<Element> getChildElements(Node node) {
        List<Element> list = new LinkedList<Element>();
        NodeList nlist = node.getChildNodes();
        for (int i = 0; i < nlist.getLength(); i++) {
            Node child = nlist.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE)
                list.add((Element) child);
        }
        return list.iterator();
    }

    /** Get the concatenated text content, or null.
     */
    public static String getTextContent(Node node) {
        boolean hasTextContent = false;
        StringBuffer buffer = new StringBuffer();
        NodeList nlist = node.getChildNodes();
        for (int i = 0; i < nlist.getLength(); i++) {
            Node child = nlist.item(i);
            if (child.getNodeType() == Node.TEXT_NODE) {
                buffer.append(child.getNodeValue());
                hasTextContent = true;
            }
        }
        return (hasTextContent ? buffer.toString() : null);
    }

    /** Gets the first child element
     */
    public static Element getFirstChildElement(Node node) {
        return getFirstChildElement(node, false);
    }

    /** Gets the first child element
     */
    public static Element getFirstChildElement(Node node, boolean recursive) {
        return getFirstChildElementIntern(node, null, recursive);
    }

    /** Gets the first child element for a given local name without namespace
     */
    public static Element getFirstChildElement(Node node, String nodeName) {
        return getFirstChildElement(node, nodeName, false);
    }

    /** Gets the first child element for a given local name without namespace
     */
    public static Element getFirstChildElement(Node node, String nodeName, boolean recursive) {
        return getFirstChildElementIntern(node, new QName(nodeName), recursive);
    }

    /** Gets the first child element for a given qname
     */
    public static Element getFirstChildElement(Node node, QName nodeName) {
        return getFirstChildElement(node, nodeName, false);
    }

    /** Gets the first child element for a given qname
     */
    public static Element getFirstChildElement(Node node, QName nodeName, boolean recursive) {
        return getFirstChildElementIntern(node, nodeName, recursive);
    }

    private static Element getFirstChildElementIntern(Node node, QName nodeName, boolean recursive) {
        Element childElement = null;
        Iterator it = getChildElementsIntern(node, nodeName, recursive);
        if (it.hasNext()) {
            childElement = (Element) it.next();
        }
        return childElement;
    }

    /** Gets the child elements for a given local name without namespace
     */
    public static Iterator getChildElements(Node node, String nodeName) {
        return getChildElements(node, nodeName, false);
    }

    /** Gets the child elements for a given local name without namespace
     */
    public static Iterator getChildElements(Node node, String nodeName, boolean recursive) {
        return getChildElementsIntern(node, new QName(nodeName), recursive);
    }

    /** Gets the child element for a given qname
     */
    public static Iterator getChildElements(Node node, QName nodeName) {
        return getChildElements(node, nodeName, false);
    }

    /** Gets the child element for a given qname
     */
    public static Iterator getChildElements(Node node, QName nodeName, boolean recursive) {
        return getChildElementsIntern(node, nodeName, recursive);
    }

    public static List<Element> getChildElementsAsList(Node node, String nodeName) {
        return getChildElementsAsList(node, nodeName, false);
    }

    public static List<Element> getChildElementsAsList(Node node, String nodeName, boolean recursive) {
        return getChildElementsAsListIntern(node, new QName(nodeName), recursive);
    }

    public static List<Element> getChildElementsAsList(Node node, QName nodeName) {
        return getChildElementsAsList(node, nodeName, false);
    }

    public static List<Element> getChildElementsAsList(Node node, QName nodeName, boolean recursive) {
        return getChildElementsAsListIntern(node, nodeName, recursive);
    }

    private static List<Element> getChildElementsAsListIntern(Node node, QName nodeName, boolean recursive) {
        List<Element> list = new LinkedList<Element>();
        NodeList nlist = node.getChildNodes();
        for (int i = 0; i < nlist.getLength(); i++) {
            Node child = nlist.item(i);
            if (child.getNodeType() == Node.ELEMENT_NODE) {
                search(list, (Element) child, nodeName, recursive);
            }
        }
        return list;
    }

    private static void search(List<Element> list, Element baseElement, QName nodeName, boolean recursive) {
        if (nodeName == null) {
            list.add(baseElement);
        } else {
            QName qname;
            if (nodeName.getNamespaceURI().length() > 0) {
                qname = new QName(baseElement.getNamespaceURI(), baseElement.getLocalName());
            } else {
                qname = new QName(baseElement.getLocalName());
            }
            if (qname.equals(nodeName)) {
                list.add(baseElement);
            }
        }
        if (recursive) {
            NodeList nlist = baseElement.getChildNodes();
            for (int i = 0; i < nlist.getLength(); i++) {
                Node child = nlist.item(i);
                if (child.getNodeType() == Node.ELEMENT_NODE) {
                    search(list, (Element) child, nodeName, recursive);
                }
            }
        }
    }

    private static Iterator getChildElementsIntern(Node node, QName nodeName, boolean recursive) {
        return getChildElementsAsListIntern(node, nodeName, recursive).iterator();
    }

    /** Gets parent element or null if there is none
     */
    public static Element getParentElement(Node node) {
        Node parent = node.getParentNode();
        return (parent instanceof Element ? (Element) parent : null);
    }

    /** Get the owner document that is associated with the current thread */
    public static Document getOwnerDocument() {
        Document doc = documentThreadLocal.get();
        if (doc == null) {
            doc = getDocumentBuilder().newDocument();
            documentThreadLocal.set(doc);
        }
        return doc;
    }

    public static Element sourceToElement(Source source) throws IOException {
        Element retElement = null;

        try {
            if (source instanceof StreamSource) {
                StreamSource streamSource = (StreamSource) source;

                InputStream ins = streamSource.getInputStream();
                if (ins != null) {
                    retElement = DOMUtils.parse(ins);
                } else {
                    Reader reader = streamSource.getReader();
                    retElement = DOMUtils.parse(new InputSource(reader));
                }
            } else if (source instanceof DOMSource) {
                DOMSource domSource = (DOMSource) source;
                Node node = domSource.getNode();
                if (node instanceof Element) {
                    retElement = (Element) node;
                } else if (node instanceof Document) {
                    retElement = ((Document) node).getDocumentElement();
                } else {
                    throw new RuntimeException("Unsupported Node type: " + node.getClass().getName());
                }
            } else if (source instanceof SAXSource) {
                // The fact that JAXBSource derives from SAXSource is an implementation detail.
                // Thus in general applications are strongly discouraged from accessing methods defined on SAXSource.
                // The XMLReader object obtained by the getXMLReader method shall be used only for parsing the InputSource object returned by the getInputSource method.

                TransformerFactory tf = TransformerFactory.newInstance();
                ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
                Transformer transformer = tf.newTransformer();
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                transformer.setOutputProperty(OutputKeys.METHOD, "xml");
                transformer.transform(source, new StreamResult(baos));
                retElement = DOMUtils.parse(new ByteArrayInputStream(baos.toByteArray()));
            } else {
                throw new RuntimeException("Source type not implemented: " + source.getClass().getName());
            }

        } catch (TransformerException ex) {
            IOException ioex = new IOException();
            ioex.initCause(ex);
            throw ioex;
        }

        return retElement;
    }
}