From 91ee02ef2143f06eca11cc78ddad342ef576ff48 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Mon, 5 Mar 2018 14:26:49 +0100 Subject: [PATCH] cache xml parsing/transformation by threadlocal --- .../com/evolveum/midpoint/util/DOMUtil.java | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/DOMUtil.java b/infra/util/src/main/java/com/evolveum/midpoint/util/DOMUtil.java index 191bae75985..5870108985c 100644 --- a/infra/util/src/main/java/com/evolveum/midpoint/util/DOMUtil.java +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/DOMUtil.java @@ -163,16 +163,45 @@ public class DOMUtil { // To generate random namespace prefixes private static Random rnd = new Random(); - private static final DocumentBuilder loader; + private static final DocumentBuilderFactory documentBuilderFactory; + private static final ThreadLocal documentBuilderThreadLocal; + + private static final TransformerFactory transformerFactory; + private static final ThreadLocal transformerThreadLocal; static { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - loader = factory.newDocumentBuilder(); + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilderFactory.setFeature("http://xml.org/sax/features/namespaces", true); + // voodoo to turn off reading of DTDs during parsing. This is needed e.g. to pre-parse schemas + documentBuilderFactory.setValidating(false); + documentBuilderFactory.setFeature("http://xml.org/sax/features/validation", false); + documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); + documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + + documentBuilderThreadLocal = ThreadLocal.withInitial(() -> { + try { + return documentBuilderFactory.newDocumentBuilder(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); } catch (ParserConfigurationException ex) { throw new IllegalStateException("Error creating XML document " + ex.getMessage()); } + + transformerFactory = TransformerFactory.newInstance(); + transformerThreadLocal = ThreadLocal.withInitial(() -> { + try { + Transformer trans = transformerFactory.newTransformer(); + trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); // XALAN-specific + trans.setParameter(OutputKeys.ENCODING, "utf-8"); + return trans; + } catch (Exception e) { + throw new RuntimeException(e); + } + }); } public static String serializeDOMToString(org.w3c.dom.Node node) { @@ -180,11 +209,9 @@ public static String serializeDOMToString(org.w3c.dom.Node node) { } public static void serializeDOMToFile(org.w3c.dom.Node node, File file) throws TransformerFactoryConfigurationError, TransformerException { - - Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Transformer transformer = transformerThreadLocal.get(); Result output = new StreamResult(file); Source input = new DOMSource(node); - transformer.transform(input, output); } @@ -196,23 +223,17 @@ public static Document getDocument(Node node) { } public static Document getDocument() { - return loader.newDocument(); + return documentBuilderThreadLocal.get().newDocument(); } public static Document getDocument(QName rootElementName) { - Document document = loader.newDocument(); + Document document = documentBuilderThreadLocal.get().newDocument(); document.appendChild(createElement(document, rootElementName)); return document; } public static DocumentBuilder createDocumentBuilder() { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - try { - return factory.newDocumentBuilder(); - } catch (ParserConfigurationException e) { - throw new IllegalStateException("Error creating document builder " + e.getMessage(), e); - } + return documentBuilderThreadLocal.get(); } public static Document parseDocument(String doc) { @@ -230,28 +251,16 @@ public static Document parseFile(String filePath) { public static Document parseFile(File file) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder loader = factory.newDocumentBuilder(); - return loader.parse(file); - } catch (SAXException | IOException | ParserConfigurationException ex) { + return documentBuilderThreadLocal.get().parse(file); + } catch (SAXException | IOException ex) { throw new IllegalStateException("Error parsing XML document " + ex.getMessage(),ex); } } public static Document parse(InputStream inputStream) throws IOException { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setFeature("http://xml.org/sax/features/namespaces", true); - // voodoo to turn off reading of DTDs during parsing. This is needed e.g. to pre-parse schemas - factory.setValidating(false); - factory.setFeature("http://xml.org/sax/features/validation", false); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - DocumentBuilder loader = factory.newDocumentBuilder(); - return loader.parse(inputStream); - } catch (SAXException | ParserConfigurationException ex) { + return documentBuilderThreadLocal.get().parse(inputStream); + } catch (SAXException ex) { throw new IllegalStateException("Error parsing XML document " + ex.getMessage(),ex); } } @@ -271,21 +280,12 @@ public static StringBuffer printDom(Node node) { public static StringBuffer printDom(Node node, boolean indent, boolean omitXmlDeclaration) { StringWriter writer = new StringWriter(); - TransformerFactory transfac = TransformerFactory.newInstance(); - Transformer trans; - try { - trans = transfac.newTransformer(); - } catch (TransformerConfigurationException e) { - throw new SystemException("Error in XML configuration: "+e.getMessage(),e); - } - trans.setOutputProperty(OutputKeys.INDENT, (indent ? "yes" : "no")); - trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); // XALAN-specific - trans.setParameter(OutputKeys.ENCODING, "utf-8"); - // Note: serialized XML does not contain xml declaration - trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, (omitXmlDeclaration ? "yes" : "no")); - DOMSource source = new DOMSource(node); try { + Transformer trans = transformerThreadLocal.get(); + trans.setOutputProperty(OutputKeys.INDENT, (indent ? "yes" : "no")); + // Note: serialized XML does not contain xml declaration + trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, (omitXmlDeclaration ? "yes" : "no")); trans.transform(source, new StreamResult(writer)); } catch (TransformerException e) { throw new SystemException("Error in XML transformation: "+e.getMessage(),e);