From b9696ac80bb496b52d05c3884f81b0746d9af9e2 Mon Sep 17 00:00:00 2001 From: Dejan Bosanac Date: Tue, 26 Aug 2014 14:46:45 +0200 Subject: [PATCH] https://issues.apache.org/jira/browse/AMQ-5333 - make xpath parser features configurable --- .../activemq/filter/JAXPXPathEvaluator.java | 37 ++++++------ .../activemq/filter/XalanXPathEvaluator.java | 37 ++++++------ .../activemq/filter/XPathExpression.java | 57 ++++++++++++++++++- 3 files changed, 94 insertions(+), 37 deletions(-) diff --git a/activemq-broker/src/main/java/org/apache/activemq/filter/JAXPXPathEvaluator.java b/activemq-broker/src/main/java/org/apache/activemq/filter/JAXPXPathEvaluator.java index 0ce505552f..e4581817ed 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/filter/JAXPXPathEvaluator.java +++ b/activemq-broker/src/main/java/org/apache/activemq/filter/JAXPXPathEvaluator.java @@ -16,32 +16,33 @@ */ package org.apache.activemq.filter; -import java.io.StringReader; +import org.apache.activemq.command.Message; +import org.apache.activemq.util.ByteArrayInputStream; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.TextMessage; +import javax.xml.parsers.DocumentBuilder; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; - -import org.apache.activemq.command.Message; -import org.apache.activemq.util.ByteArrayInputStream; -import org.xml.sax.InputSource; +import java.io.StringReader; public class JAXPXPathEvaluator implements XPathExpression.XPathEvaluator { private static final XPathFactory FACTORY = XPathFactory.newInstance(); - private final javax.xml.xpath.XPathExpression expression; private final String xpathExpression; + private final DocumentBuilder builder; + private final XPath xpath = FACTORY.newXPath(); - public JAXPXPathEvaluator(String xpathExpression) { + public JAXPXPathEvaluator(String xpathExpression, DocumentBuilder builder) throws Exception { this.xpathExpression = xpathExpression; - try { - XPath xpath = FACTORY.newXPath(); - expression = xpath.compile(xpathExpression); - } catch (XPathExpressionException e) { - throw new RuntimeException("Invalid XPath expression: " + xpathExpression); + if (builder != null) { + this.builder = builder; + } else { + throw new RuntimeException("No document builder available"); } } @@ -61,8 +62,9 @@ public class JAXPXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(byte[] data) { try { InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue(); - } catch (XPathExpressionException e) { + Document inputDocument = builder.parse(inputSource); + return ((Boolean)xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue(); + } catch (Exception e) { return false; } } @@ -70,8 +72,9 @@ public class JAXPXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(String text) { try { InputSource inputSource = new InputSource(new StringReader(text)); - return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue(); - } catch (XPathExpressionException e) { + Document inputDocument = builder.parse(inputSource); + return ((Boolean)xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue(); + } catch (Exception e) { return false; } } diff --git a/activemq-broker/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java b/activemq-broker/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java index 1ea092f377..7bfdaf0ac8 100755 --- a/activemq-broker/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java +++ b/activemq-broker/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java @@ -16,34 +16,33 @@ */ package org.apache.activemq.filter; -import java.io.StringReader; +import org.apache.activemq.command.Message; +import org.apache.activemq.util.ByteArrayInputStream; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.TextMessage; +import javax.xml.parsers.DocumentBuilder; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; - -import org.apache.activemq.command.Message; -import org.apache.activemq.util.ByteArrayInputStream; - -import org.xml.sax.InputSource; +import java.io.StringReader; public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private static final XPathFactory FACTORY = XPathFactory.newInstance(); - private final javax.xml.xpath.XPathExpression expression; private final String xpathExpression; + private final DocumentBuilder builder; + private final XPath xpath = FACTORY.newXPath(); - public XalanXPathEvaluator(String xpathExpression) { + public XalanXPathEvaluator(String xpathExpression, DocumentBuilder builder) throws Exception { this.xpathExpression = xpathExpression; - try { - XPath xpath = FACTORY.newXPath(); - expression = xpath.compile(xpathExpression); - } catch (XPathExpressionException e) { - throw new RuntimeException("Invalid XPath expression: " + xpathExpression); + if (builder != null) { + this.builder = builder; + } else { + throw new RuntimeException("No document builder available"); } } @@ -63,8 +62,9 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(byte[] data) { try { InputSource inputSource = new InputSource(new ByteArrayInputStream(data)); - return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue(); - } catch (XPathExpressionException e) { + Document inputDocument = builder.parse(inputSource); + return ((Boolean) xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue(); + } catch (Exception e) { return false; } } @@ -72,8 +72,9 @@ public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator { private boolean evaluate(String text) { try { InputSource inputSource = new InputSource(new StringReader(text)); - return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue(); - } catch (XPathExpressionException e) { + Document inputDocument = builder.parse(inputSource); + return ((Boolean) xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue(); + } catch (Exception e) { return false; } } diff --git a/activemq-client/src/main/java/org/apache/activemq/filter/XPathExpression.java b/activemq-client/src/main/java/org/apache/activemq/filter/XPathExpression.java index c29a31214c..75ab087e98 100755 --- a/activemq-client/src/main/java/org/apache/activemq/filter/XPathExpression.java +++ b/activemq-client/src/main/java/org/apache/activemq/filter/XPathExpression.java @@ -19,8 +19,15 @@ package org.apache.activemq.filter; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; import javax.jms.JMSException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.apache.activemq.command.Message; import org.apache.activemq.util.JMSExceptionSupport; @@ -35,8 +42,10 @@ public final class XPathExpression implements BooleanExpression { private static final Logger LOG = LoggerFactory.getLogger(XPathExpression.class); private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.activemq.XPathEvaluatorClassName"; private static final String DEFAULT_EVALUATOR_CLASS_NAME = "org.apache.activemq.filter.XalanXPathEvaluator"; + public static final String DOCUMENT_BUILDER_FACTORY_FEATURE = "org.apache.activemq.documentBuilderFactory.feature"; private static final Constructor EVALUATOR_CONSTRUCTOR; + private static DocumentBuilder builder = null; static { String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME); @@ -44,6 +53,21 @@ public final class XPathExpression implements BooleanExpression { try { try { m = getXPathEvaluatorConstructor(cn); + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + builderFactory.setNamespaceAware(true); + builderFactory.setIgnoringElementContentWhitespace(true); + builderFactory.setIgnoringComments(true); + try { + // set some reasonable defaults + builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false); + builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } catch (ParserConfigurationException e) { + LOG.warn("Error setting document builder factory feature", e); + } + // setup the feature from the system property + setupFeatures(builderFactory); + builder = builderFactory.newDocumentBuilder(); } catch (Throwable e) { LOG.warn("Invalid " + XPathEvaluator.class.getName() + " implementation: " + cn + ", reason: " + e, e); cn = DEFAULT_EVALUATOR_CLASS_NAME; @@ -75,12 +99,41 @@ public final class XPathExpression implements BooleanExpression { if (!XPathEvaluator.class.isAssignableFrom(c)) { throw new ClassCastException("" + c + " is not an instance of " + XPathEvaluator.class); } - return c.getConstructor(new Class[] {String.class}); + return c.getConstructor(new Class[] {String.class, DocumentBuilder.class}); + } + + protected static void setupFeatures(DocumentBuilderFactory factory) { + Properties properties = System.getProperties(); + List features = new ArrayList(); + for (Map.Entry prop : properties.entrySet()) { + String key = (String) prop.getKey(); + if (key.startsWith(DOCUMENT_BUILDER_FACTORY_FEATURE)) { + String uri = key.split(DOCUMENT_BUILDER_FACTORY_FEATURE + ":")[1]; + Boolean value = Boolean.valueOf((String)prop.getValue()); + try { + factory.setFeature(uri, value); + features.add("feature " + uri + " value " + value); + } catch (ParserConfigurationException e) { + LOG.warn("DocumentBuilderFactory doesn't support the feature {} with value {}, due to {}.", new Object[]{uri, value, e}); + } + } + } + if (features.size() > 0) { + StringBuffer featureString = new StringBuffer(); + // just log the configured feature + for (String feature : features) { + if (featureString.length() != 0) { + featureString.append(", "); + } + featureString.append(feature); + } + } + } private XPathEvaluator createEvaluator(String xpath2) { try { - return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath}); + return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath, builder}); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) {