From e5b7380c874745c989d1816b8f552504f038e1bc Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 26 Sep 2013 20:33:20 +0000 Subject: 2.0 branch for possible maintenance release git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1526672 13f79535-47bb-0310-9956-ffa450edef68 --- .../tuscany/sca/common/xml/dom/DOMHelper.java | 302 +++++++++++++++++++++ .../tuscany/sca/common/xml/dom/ParserPool.java | 102 +++++++ .../sca/common/xml/dom/impl/SAX2DOMAdapter.java | 244 +++++++++++++++++ 3 files changed, 648 insertions(+) create mode 100644 sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java create mode 100644 sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java create mode 100644 sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java (limited to 'sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom') diff --git a/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java new file mode 100644 index 0000000000..c5e7015364 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/DOMHelper.java @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.common.xml.dom; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamResult; + +import org.apache.tuscany.sca.common.xml.dom.impl.SAX2DOMAdapter; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.core.LifeCycleListener; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + +/** + * Helper for DOM + * + * @version $Rev$ $Date$ + * @tuscany.spi.extension.asclient + */ +public class DOMHelper implements LifeCycleListener { + protected static final int INITIAL_POOL_SIZE = 8; + protected static final int MAX_POOL_SIZE = 64; + private DocumentBuilderFactory documentBuilderFactory; + private TransformerFactory transformerFactory; + protected ParserPool builderPool; + protected ParserPool transformerPool; + + public static DOMHelper getInstance(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + return utilities.getUtility(DOMHelper.class); + } + + public DOMHelper(ExtensionPointRegistry registry) { + FactoryExtensionPoint factories = registry.getExtensionPoint(FactoryExtensionPoint.class); + documentBuilderFactory = factories.getFactory(DocumentBuilderFactory.class); + documentBuilderFactory.setNamespaceAware(true); + transformerFactory = factories.getFactory(TransformerFactory.class); + } + + /** + * @param documentBuilderFactory + * @param transformerFactory + */ + public DOMHelper(DocumentBuilderFactory documentBuilderFactory, TransformerFactory transformerFactory) { + super(); + this.documentBuilderFactory = documentBuilderFactory; + this.transformerFactory = transformerFactory; + } + + public Document newDocument() { + DocumentBuilder builder = newDocumentBuilder(); + try { + return builder.newDocument(); + } finally { + returnDocumentBuilder(builder); + } + + } + + public DocumentBuilder newDocumentBuilder() { + return builderPool.borrowFromPool(); + } + + public void returnDocumentBuilder(DocumentBuilder builder) { + builderPool.returnToPool(builder); + } + + private DocumentBuilder createDocumentBuilder() { + try { + return documentBuilderFactory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new IllegalArgumentException(e); + } + } + + public Document load(String xmlString) throws IOException, SAXException { + DocumentBuilder builder = newDocumentBuilder(); + try { + InputSource is = new InputSource(new StringReader(xmlString)); + return builder.parse(is); + } finally { + returnDocumentBuilder(builder); + } + } + + public Document load(Source source) { + Transformer transformer = newTransformer(); + DOMResult result = new DOMResult(newDocument()); + try { + transformer.transform(source, result); + } catch (TransformerException e) { + throw new IllegalArgumentException(e); + } finally { + transformerPool.returnToPool(transformer); + } + return (Document)result.getNode(); + } + + public NodeContentHandler createContentHandler(Node root) { + if (root == null) { + root = newDocument(); + } + return new SAX2DOMAdapter(root); + } + + public String saveAsString(Node node) { + Transformer transformer = newTransformer(); + StringWriter sw = new StringWriter(); + StreamResult result = new StreamResult(sw); + try { + transformer.transform(new DOMSource(node), result); + } catch (TransformerException e) { + throw new IllegalArgumentException(e); + } finally { + returnTransformer(transformer); + } + return result.getWriter().toString(); + } + + public Transformer newTransformer() { + return transformerPool.borrowFromPool(); + } + + public void returnTransformer(Transformer transformer) { + transformerPool.returnToPool(transformer); + } + + private Transformer createTransformer() { + Transformer transformer = null; + try { + transformer = transformerFactory.newTransformer(); + } catch (TransformerConfigurationException e) { + throw new IllegalArgumentException(e); + } + return transformer; + } + + public void saveAsSAX(Node node, ContentHandler contentHandler) { + Transformer transformer = transformerPool.borrowFromPool(); + SAXResult result = new SAXResult(contentHandler); + try { + transformer.transform(new DOMSource(node), result); + } catch (TransformerException e) { + throw new IllegalArgumentException(e); + } finally { + returnTransformer(transformer); + } + } + + public static QName getQName(Node node) { + String ns = node.getNamespaceURI(); + String prefix = node.getPrefix(); + String localName = node.getLocalName(); + if (localName == null) { + localName = node.getNodeName(); + } + if (ns == null) { + ns = ""; + } + if (prefix == null) { + prefix = ""; + } + return new QName(ns, localName, prefix); + } + + public static Element createElement(Document document, QName name) { + String prefix = name.getPrefix(); + String qname = + (prefix != null && prefix.length() > 0) ? prefix + ":" + name.getLocalPart() : name.getLocalPart(); + return document.createElementNS(name.getNamespaceURI(), qname); + } + + /** + * Wrap an element as a DOM document + * @param node + * @return + */ + public static Document promote(Node node) { + if (node instanceof Document) { + return (Document)node; + } + Element element = (Element)node; + Document doc = element.getOwnerDocument(); + if (doc.getDocumentElement() == element) { + return doc; + } + doc = (Document)element.getOwnerDocument().cloneNode(false); + Element schema = (Element)doc.importNode(element, true); + doc.appendChild(schema); + Node parent = element.getParentNode(); + while (parent instanceof Element) { + Element root = (Element)parent; + NamedNodeMap nodeMap = root.getAttributes(); + for (int i = 0; i < nodeMap.getLength(); i++) { + Attr attr = (Attr)nodeMap.item(i); + String name = attr.getName(); + if ("xmlns".equals(name) || name.startsWith("xmlns:")) { + if (schema.getAttributeNode(name) == null) { + schema.setAttributeNodeNS((Attr)doc.importNode(attr, true)); + } + } + } + parent = parent.getParentNode(); + } + return doc; + } + + public static String getPrefix(Element element, String namespace) { + if (element.isDefaultNamespace(namespace)) { + return XMLConstants.DEFAULT_NS_PREFIX; + } + return element.lookupPrefix(namespace); + } + + public static String getNamespaceURI(Element element, String prefix) { + if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) { + prefix = null; + } + return element.lookupNamespaceURI(prefix); + } + + public static interface NodeContentHandler extends ContentHandler, LexicalHandler { + Node getNode(); + } + + @Override + public void start() { + builderPool = new ParserPool(MAX_POOL_SIZE, INITIAL_POOL_SIZE) { + + @Override + protected DocumentBuilder newInstance() { + return createDocumentBuilder(); + } + + @Override + protected void resetInstance(DocumentBuilder obj) { + obj.reset(); + } + }; + + transformerPool = new ParserPool(64, 8) { + + @Override + protected Transformer newInstance() { + return createTransformer(); + } + + @Override + protected void resetInstance(Transformer obj) { + obj.reset(); + } + }; + } + + @Override + public void stop() { + builderPool.clear(); + transformerPool.clear(); + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java new file mode 100644 index 0000000000..e8187d481d --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/ParserPool.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.tuscany.sca.common.xml.dom; + +import java.util.IdentityHashMap; +import java.util.Map; + +public abstract class ParserPool { + private int maxSize; + private Map objects; + + public ParserPool() { + this(32, 0); + } + + public ParserPool(int maxSize, int initialSize) { + super(); + this.maxSize = maxSize; + this.objects = new IdentityHashMap(maxSize); + for (int i = 0; i < Math.min(initialSize, maxSize); i++) { + objects.put(newInstance(), Boolean.FALSE); + } + } + + public synchronized V borrowFromPool() { + while (true) { + for (Map.Entry e : objects.entrySet()) { + if (Boolean.FALSE.equals(e.getValue())) { + // setValue fails on some Harmony based JDKs, see https://issues.apache.org/jira/browse/HARMONY-6419 + //e.setValue(Boolean.TRUE); // in use + V key = e.getKey(); + objects.put(key, Boolean.TRUE); // in use + return key; + } + } + if (objects.size() < maxSize) { + V obj = newInstance(); + objects.put(obj, Boolean.TRUE); + return obj; + } + try { + wait(); + } catch (InterruptedException e1) { + throw new IllegalStateException(e1); + } + } + } + + public synchronized void returnToPool(V obj) { + resetInstance(obj); + objects.put(obj, Boolean.FALSE); + notifyAll(); + } + + public synchronized void clear() { + objects.clear(); + } + + public synchronized int inUse() { + int size = 0; + for (Map.Entry e : objects.entrySet()) { + if (Boolean.TRUE.equals(e.getValue())) { + size++; + } + } + return size; + } + + /** + * Create a new instance + * @return + */ + protected abstract V newInstance(); + + /** + * Reset the instance before returning to the pool + * @param obj + */ + protected abstract void resetInstance(V obj); + + // Expose it for testing purpose + public Map getObjects() { + return objects; + } +} diff --git a/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java new file mode 100644 index 0000000000..11d692c81e --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/common-xml/src/main/java/org/apache/tuscany/sca/common/xml/dom/impl/SAX2DOMAdapter.java @@ -0,0 +1,244 @@ +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tuscany.sca.common.xml.dom.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +import org.apache.tuscany.sca.common.xml.dom.DOMHelper; +import org.apache.tuscany.sca.common.xml.dom.DOMHelper.NodeContentHandler; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.UtilityExtensionPoint; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + +/** + * SAX2DOM adapter + * + * @version $Rev$ $Date$ + */ +public class SAX2DOMAdapter implements DOMHelper.NodeContentHandler { + public static final String EMPTYSTRING = ""; + public static final String XML_PREFIX = "xml"; + public static final String XMLNS_PREFIX = "xmlns"; + public static final String XMLNS_STRING = "xmlns:"; + public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; + + private Node root; + + private Document document; + + private Node nextSibling; + + private Stack nodeStk = new Stack(); + + private List namespaceDecls; + + private Node lastSibling; + + public SAX2DOMAdapter(ExtensionPointRegistry registry) { + UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class); + DOMHelper domHelper = utilities.getUtility(DOMHelper.class); + this.document = domHelper.newDocument(); + this.root = document; + } + + public SAX2DOMAdapter(Node root, Node nextSibling) { + this.root = root; + if (root instanceof Document) { + this.document = (Document)root; + } else if (root != null) { + this.document = root.getOwnerDocument(); + } + + this.nextSibling = nextSibling; + } + + public SAX2DOMAdapter(Node root) { + this(root, null); + } + + public Node getNode() { + return root; + } + + public void characters(char[] ch, int start, int length) { + final Node last = nodeStk.peek(); + + // No text nodes can be children of root (DOM006 exception) + if (last != document) { + final String text = new String(ch, start, length); + if (lastSibling != null && lastSibling.getNodeType() == Node.TEXT_NODE) { + ((Text)lastSibling).appendData(text); + } else if (last == root && nextSibling != null) { + lastSibling = last.insertBefore(document.createTextNode(text), nextSibling); + } else { + lastSibling = last.appendChild(document.createTextNode(text)); + } + + } + } + + public void startDocument() { + nodeStk.push(root); + } + + public void endDocument() { + nodeStk.pop(); + } + + public void startElement(String namespace, String localName, String qName, Attributes attrs) { + final Element tmp = document.createElementNS(namespace, qName); + + // Add namespace declarations first + if (namespaceDecls != null) { + final int nDecls = namespaceDecls.size(); + for (int i = 0; i < nDecls; i++) { + final String prefix = namespaceDecls.get(i++); + + if (prefix == null || prefix.equals(EMPTYSTRING)) { + tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX, namespaceDecls.get(i)); + } else { + tmp.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix, namespaceDecls.get(i)); + } + } + namespaceDecls.clear(); + } + + // Add attributes to element + final int nattrs = attrs.getLength(); + for (int i = 0; i < nattrs; i++) { + if (attrs.getLocalName(i) == null) { + tmp.setAttribute(attrs.getQName(i), attrs.getValue(i)); + } else { + tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i), attrs.getValue(i)); + } + } + + // Append this new node onto current stack node + Node last = nodeStk.peek(); + + // If the SAX2DOM is created with a non-null next sibling node, + // insert the result nodes before the next sibling under the root. + if (last == root && nextSibling != null) { + last.insertBefore(tmp, nextSibling); + } else { + last.appendChild(tmp); + } + + // Push this node onto stack + nodeStk.push(tmp); + lastSibling = null; + } + + public void endElement(String namespace, String localName, String qName) { + nodeStk.pop(); + lastSibling = null; + } + + public void startPrefixMapping(String prefix, String uri) { + if (namespaceDecls == null) { + namespaceDecls = new ArrayList(2); + } + namespaceDecls.add(prefix); + namespaceDecls.add(uri); + } + + public void endPrefixMapping(String prefix) { + // do nothing + } + + /** + * This class is only used internally so this method should never be called. + */ + public void ignorableWhitespace(char[] ch, int start, int length) { + } + + /** + * adds processing instruction node to DOM. + */ + public void processingInstruction(String target, String data) { + final Node last = nodeStk.peek(); + ProcessingInstruction pi = document.createProcessingInstruction(target, data); + if (pi != null) { + if (last == root && nextSibling != null) { + last.insertBefore(pi, nextSibling); + } else { + last.appendChild(pi); + } + + lastSibling = pi; + } + } + + /** + * This class is only used internally so this method should never be called. + */ + public void setDocumentLocator(Locator locator) { + } + + /** + * This class is only used internally so this method should never be called. + */ + public void skippedEntity(String name) { + } + + /** + * Lexical Handler method to create comment node in DOM tree. + */ + public void comment(char[] ch, int start, int length) { + final Node last = nodeStk.peek(); + Comment comment = document.createComment(new String(ch, start, length)); + if (comment != null) { + if (last == root && nextSibling != null) { + last.insertBefore(comment, nextSibling); + } else { + last.appendChild(comment); + } + + lastSibling = comment; + } + } + + // Lexical Handler methods- not implemented + public void startCDATA() { + } + + public void endCDATA() { + } + + public void startEntity(java.lang.String name) { + } + + public void endDTD() { + } + + public void endEntity(String name) { + } + + public void startDTD(String name, String publicId, String systemId) throws SAXException { + } + +} -- cgit v1.2.3