Skip to content

Commit b9696ac

Browse files
committed
https://issues.apache.org/jira/browse/AMQ-5333 - make xpath parser features configurable
1 parent 4fa1035 commit b9696ac

File tree

3 files changed

+94
-37
lines changed

3 files changed

+94
-37
lines changed

activemq-broker/src/main/java/org/apache/activemq/filter/JAXPXPathEvaluator.java

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,33 @@
1616
*/
1717
package org.apache.activemq.filter;
1818

19-
import java.io.StringReader;
19+
import org.apache.activemq.command.Message;
20+
import org.apache.activemq.util.ByteArrayInputStream;
21+
import org.w3c.dom.Document;
22+
import org.xml.sax.InputSource;
23+
2024
import javax.jms.BytesMessage;
2125
import javax.jms.JMSException;
2226
import javax.jms.TextMessage;
27+
import javax.xml.parsers.DocumentBuilder;
2328
import javax.xml.xpath.XPath;
2429
import javax.xml.xpath.XPathConstants;
25-
import javax.xml.xpath.XPathExpressionException;
2630
import javax.xml.xpath.XPathFactory;
27-
28-
import org.apache.activemq.command.Message;
29-
import org.apache.activemq.util.ByteArrayInputStream;
30-
import org.xml.sax.InputSource;
31+
import java.io.StringReader;
3132

3233
public class JAXPXPathEvaluator implements XPathExpression.XPathEvaluator {
3334

3435
private static final XPathFactory FACTORY = XPathFactory.newInstance();
35-
private final javax.xml.xpath.XPathExpression expression;
3636
private final String xpathExpression;
37+
private final DocumentBuilder builder;
38+
private final XPath xpath = FACTORY.newXPath();
3739

38-
public JAXPXPathEvaluator(String xpathExpression) {
40+
public JAXPXPathEvaluator(String xpathExpression, DocumentBuilder builder) throws Exception {
3941
this.xpathExpression = xpathExpression;
40-
try {
41-
XPath xpath = FACTORY.newXPath();
42-
expression = xpath.compile(xpathExpression);
43-
} catch (XPathExpressionException e) {
44-
throw new RuntimeException("Invalid XPath expression: " + xpathExpression);
42+
if (builder != null) {
43+
this.builder = builder;
44+
} else {
45+
throw new RuntimeException("No document builder available");
4546
}
4647
}
4748

@@ -61,17 +62,19 @@ public boolean evaluate(Message message) throws JMSException {
6162
private boolean evaluate(byte[] data) {
6263
try {
6364
InputSource inputSource = new InputSource(new ByteArrayInputStream(data));
64-
return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue();
65-
} catch (XPathExpressionException e) {
65+
Document inputDocument = builder.parse(inputSource);
66+
return ((Boolean)xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue();
67+
} catch (Exception e) {
6668
return false;
6769
}
6870
}
6971

7072
private boolean evaluate(String text) {
7173
try {
7274
InputSource inputSource = new InputSource(new StringReader(text));
73-
return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue();
74-
} catch (XPathExpressionException e) {
75+
Document inputDocument = builder.parse(inputSource);
76+
return ((Boolean)xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue();
77+
} catch (Exception e) {
7578
return false;
7679
}
7780
}

activemq-broker/src/main/java/org/apache/activemq/filter/XalanXPathEvaluator.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,33 @@
1616
*/
1717
package org.apache.activemq.filter;
1818

19-
import java.io.StringReader;
19+
import org.apache.activemq.command.Message;
20+
import org.apache.activemq.util.ByteArrayInputStream;
21+
import org.w3c.dom.Document;
22+
import org.xml.sax.InputSource;
2023

2124
import javax.jms.BytesMessage;
2225
import javax.jms.JMSException;
2326
import javax.jms.TextMessage;
27+
import javax.xml.parsers.DocumentBuilder;
2428
import javax.xml.xpath.XPath;
2529
import javax.xml.xpath.XPathConstants;
26-
import javax.xml.xpath.XPathExpressionException;
2730
import javax.xml.xpath.XPathFactory;
28-
29-
import org.apache.activemq.command.Message;
30-
import org.apache.activemq.util.ByteArrayInputStream;
31-
32-
import org.xml.sax.InputSource;
31+
import java.io.StringReader;
3332

3433
public class XalanXPathEvaluator implements XPathExpression.XPathEvaluator {
3534

3635
private static final XPathFactory FACTORY = XPathFactory.newInstance();
37-
private final javax.xml.xpath.XPathExpression expression;
3836
private final String xpathExpression;
37+
private final DocumentBuilder builder;
38+
private final XPath xpath = FACTORY.newXPath();
3939

40-
public XalanXPathEvaluator(String xpathExpression) {
40+
public XalanXPathEvaluator(String xpathExpression, DocumentBuilder builder) throws Exception {
4141
this.xpathExpression = xpathExpression;
42-
try {
43-
XPath xpath = FACTORY.newXPath();
44-
expression = xpath.compile(xpathExpression);
45-
} catch (XPathExpressionException e) {
46-
throw new RuntimeException("Invalid XPath expression: " + xpathExpression);
42+
if (builder != null) {
43+
this.builder = builder;
44+
} else {
45+
throw new RuntimeException("No document builder available");
4746
}
4847
}
4948

@@ -63,17 +62,19 @@ public boolean evaluate(Message message) throws JMSException {
6362
private boolean evaluate(byte[] data) {
6463
try {
6564
InputSource inputSource = new InputSource(new ByteArrayInputStream(data));
66-
return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue();
67-
} catch (XPathExpressionException e) {
65+
Document inputDocument = builder.parse(inputSource);
66+
return ((Boolean) xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue();
67+
} catch (Exception e) {
6868
return false;
6969
}
7070
}
7171

7272
private boolean evaluate(String text) {
7373
try {
7474
InputSource inputSource = new InputSource(new StringReader(text));
75-
return ((Boolean)expression.evaluate(inputSource, XPathConstants.BOOLEAN)).booleanValue();
76-
} catch (XPathExpressionException e) {
75+
Document inputDocument = builder.parse(inputSource);
76+
return ((Boolean) xpath.evaluate(xpathExpression, inputDocument, XPathConstants.BOOLEAN)).booleanValue();
77+
} catch (Exception e) {
7778
return false;
7879
}
7980
}

activemq-client/src/main/java/org/apache/activemq/filter/XPathExpression.java

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,15 @@
1919
import java.io.IOException;
2020
import java.lang.reflect.Constructor;
2121
import java.lang.reflect.InvocationTargetException;
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.Properties;
2226

2327
import javax.jms.JMSException;
28+
import javax.xml.parsers.DocumentBuilder;
29+
import javax.xml.parsers.DocumentBuilderFactory;
30+
import javax.xml.parsers.ParserConfigurationException;
2431

2532
import org.apache.activemq.command.Message;
2633
import org.apache.activemq.util.JMSExceptionSupport;
@@ -35,15 +42,32 @@ public final class XPathExpression implements BooleanExpression {
3542
private static final Logger LOG = LoggerFactory.getLogger(XPathExpression.class);
3643
private static final String EVALUATOR_SYSTEM_PROPERTY = "org.apache.activemq.XPathEvaluatorClassName";
3744
private static final String DEFAULT_EVALUATOR_CLASS_NAME = "org.apache.activemq.filter.XalanXPathEvaluator";
45+
public static final String DOCUMENT_BUILDER_FACTORY_FEATURE = "org.apache.activemq.documentBuilderFactory.feature";
3846

3947
private static final Constructor EVALUATOR_CONSTRUCTOR;
48+
private static DocumentBuilder builder = null;
4049

4150
static {
4251
String cn = System.getProperty(EVALUATOR_SYSTEM_PROPERTY, DEFAULT_EVALUATOR_CLASS_NAME);
4352
Constructor m = null;
4453
try {
4554
try {
4655
m = getXPathEvaluatorConstructor(cn);
56+
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
57+
builderFactory.setNamespaceAware(true);
58+
builderFactory.setIgnoringElementContentWhitespace(true);
59+
builderFactory.setIgnoringComments(true);
60+
try {
61+
// set some reasonable defaults
62+
builderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
63+
builderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
64+
builderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
65+
} catch (ParserConfigurationException e) {
66+
LOG.warn("Error setting document builder factory feature", e);
67+
}
68+
// setup the feature from the system property
69+
setupFeatures(builderFactory);
70+
builder = builderFactory.newDocumentBuilder();
4771
} catch (Throwable e) {
4872
LOG.warn("Invalid " + XPathEvaluator.class.getName() + " implementation: " + cn + ", reason: " + e, e);
4973
cn = DEFAULT_EVALUATOR_CLASS_NAME;
@@ -75,12 +99,41 @@ private static Constructor getXPathEvaluatorConstructor(String cn) throws ClassN
7599
if (!XPathEvaluator.class.isAssignableFrom(c)) {
76100
throw new ClassCastException("" + c + " is not an instance of " + XPathEvaluator.class);
77101
}
78-
return c.getConstructor(new Class[] {String.class});
102+
return c.getConstructor(new Class[] {String.class, DocumentBuilder.class});
103+
}
104+
105+
protected static void setupFeatures(DocumentBuilderFactory factory) {
106+
Properties properties = System.getProperties();
107+
List<String> features = new ArrayList<String>();
108+
for (Map.Entry<Object, Object> prop : properties.entrySet()) {
109+
String key = (String) prop.getKey();
110+
if (key.startsWith(DOCUMENT_BUILDER_FACTORY_FEATURE)) {
111+
String uri = key.split(DOCUMENT_BUILDER_FACTORY_FEATURE + ":")[1];
112+
Boolean value = Boolean.valueOf((String)prop.getValue());
113+
try {
114+
factory.setFeature(uri, value);
115+
features.add("feature " + uri + " value " + value);
116+
} catch (ParserConfigurationException e) {
117+
LOG.warn("DocumentBuilderFactory doesn't support the feature {} with value {}, due to {}.", new Object[]{uri, value, e});
118+
}
119+
}
120+
}
121+
if (features.size() > 0) {
122+
StringBuffer featureString = new StringBuffer();
123+
// just log the configured feature
124+
for (String feature : features) {
125+
if (featureString.length() != 0) {
126+
featureString.append(", ");
127+
}
128+
featureString.append(feature);
129+
}
130+
}
131+
79132
}
80133

81134
private XPathEvaluator createEvaluator(String xpath2) {
82135
try {
83-
return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath});
136+
return (XPathEvaluator)EVALUATOR_CONSTRUCTOR.newInstance(new Object[] {xpath, builder});
84137
} catch (InvocationTargetException e) {
85138
Throwable cause = e.getCause();
86139
if (cause instanceof RuntimeException) {

0 commit comments

Comments
 (0)