Mercurial > dive4elements > river
view flys-aft/src/main/java/de/intevation/utils/XML.java @ 5779:ebec12def170
Datacage: Add a pool of builders to make it multi threadable.
XML DOM is not thread safe. Therefore the old implementation only allowed one thread
to use the builder at a time. As the complexity of the configuration
has increased over time this has become a bottleneck of the whole application
because it took quiet some time to build a result. Furthermore the builder code path
is visited very frequent. So many concurrent requests were piled up
resulting in long waits for the users.
To mitigate this problem a round robin pool of builders is used now.
Each of the pooled builders has an independent copy of the XML template
and can be run in parallel.
The number of builders is determined by the system property
'flys.datacage.pool.size'. It defaults to 4.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 21 Apr 2013 12:48:09 +0200 |
parents | f939e1e6cfa4 |
children |
line wrap: on
line source
package de.intevation.utils; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathVariableResolver; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.xml.sax.SAXException; public final class XML { /** Logger for this class. */ private static Logger log = Logger.getLogger(XML.class); public static class MapXPathVariableResolver implements XPathVariableResolver { protected Map<String, String> variables; public MapXPathVariableResolver() { this.variables = new HashMap<String, String>(); } public MapXPathVariableResolver(Map<String, String> variables) { this.variables = variables; } public void addVariable(String name, String value) { variables.put(name, value); } @Override public Object resolveVariable(QName variableName) { String key = variableName.getLocalPart(); return variables.get(key); } } // class MapXPathVariableResolver private XML() { } /** * Creates a new XML document * @return the new XML document ot null if something went wrong during * creation. */ public static final Document newDocument() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); try { return factory.newDocumentBuilder().newDocument(); } catch (ParserConfigurationException pce) { log.error(pce.getLocalizedMessage(), pce); } return null; } /** * Loads a XML document namespace aware from a file * @param file The file to load. * @return the XML document or null if something went wrong * during loading. */ public static final Document parseDocument(File file) { return parseDocument(file, Boolean.TRUE); } public static final Document parseDocument(File file, Boolean namespaceAware) { InputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(file)); return parseDocument(inputStream, namespaceAware); } catch (IOException ioe) { log.error(ioe.getLocalizedMessage(), ioe); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ioe) {} } } return null; } public static final Document parseDocument(InputStream inputStream) { return parseDocument(inputStream, Boolean.TRUE); } public static final Document parseDocument( InputStream inputStream, Boolean namespaceAware ) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); if (namespaceAware != null) { factory.setNamespaceAware(namespaceAware.booleanValue()); } try { return factory.newDocumentBuilder().parse(inputStream); } catch (ParserConfigurationException pce) { log.error(pce.getLocalizedMessage(), pce); } catch (SAXException se) { log.error(se.getLocalizedMessage(), se); } catch (IOException ioe) { log.error(ioe.getLocalizedMessage(), ioe); } return null; } /** * Creates a new XPath without a namespace context. * @return the new XPath. */ public static final XPath newXPath() { return newXPath(null, null); } /** * Creates a new XPath with a given namespace context. * @param namespaceContext The namespace context to be used or null * if none should be used. * @return The new XPath */ public static final XPath newXPath( NamespaceContext namespaceContext, XPathVariableResolver resolver) { XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); if (namespaceContext != null) { xpath.setNamespaceContext(namespaceContext); } if (resolver != null) { xpath.setXPathVariableResolver(resolver); } return xpath; } /** * Evaluates an XPath query on a given object and returns the result * as a given type. No namespace context is used. * @param root The object which is used as the root of the tree to * be searched in. * @param query The XPath query * @param returnTyp The type of the result. * @return The result of type 'returnTyp' or null if something * went wrong during XPath evaluation. */ public static final Object xpath( Object root, String query, QName returnTyp ) { return xpath(root, query, returnTyp, null); } /** * Evaluates an XPath query on a given object and returns the result * as a given type. Optionally a namespace context is used. * @param root The object which is used as the root of the tree to * be searched in. * @param query The XPath query * @param returnType The type of the result. * @param namespaceContext The namespace context to be used or null * if none should be used. * @return The result of type 'returnTyp' or null if something * went wrong during XPath evaluation. */ public static final Object xpath( Object root, String query, QName returnType, NamespaceContext namespaceContext ) { return xpath(root, query, returnType, namespaceContext, null); } public static final Object xpath( Object root, String query, QName returnType, NamespaceContext namespaceContext, Map<String, String> variables) { if (root == null) { return null; } XPathVariableResolver resolver = variables != null ? new MapXPathVariableResolver(variables) : null; try { XPath xpath = newXPath(namespaceContext, resolver); if (xpath != null) { return xpath.evaluate(query, root, returnType); } } catch (XPathExpressionException xpee) { log.error(xpee.getLocalizedMessage(), xpee); } return null; } public static Document transform( Document document, File xformFile ) { try { Transformer transformer = TransformerFactory .newInstance() .newTransformer( new StreamSource(xformFile)); DOMResult result = new DOMResult(); transformer.transform(new DOMSource(document), result); return (Document)result.getNode(); } catch (TransformerConfigurationException tce) { log.error(tce, tce); } catch (TransformerException te) { log.error(te, te); } return null; } /** * Streams out an XML document to a given output stream. * @param document The document to be streamed out. * @param out The output stream to be used. * @return true if operation succeeded else false. */ public static boolean toStream(Document document, OutputStream out) { try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMSource source = new DOMSource(document); StreamResult result = new StreamResult(out); transformer.transform(source, result); return true; } catch (TransformerConfigurationException tce) { log.error(tce.getLocalizedMessage(), tce); } catch (TransformerFactoryConfigurationError tfce) { log.error(tfce.getLocalizedMessage(), tfce); } catch (TransformerException te) { log.error(te.getLocalizedMessage(), te); } return false; } public static String toString(Document document) { try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMSource source = new DOMSource(document); StringWriter out = new StringWriter(); StreamResult result = new StreamResult(out); transformer.transform(source, result); out.flush(); return out.toString(); } catch (TransformerConfigurationException tce) { log.error(tce.getLocalizedMessage(), tce); } catch (TransformerFactoryConfigurationError tfce) { log.error(tfce.getLocalizedMessage(), tfce); } catch (TransformerException te) { log.error(te.getLocalizedMessage(), te); } return null; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :