package com.philemonworks.critter.condition; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import com.philemonworks.critter.rule.RuleContext; public class XPath implements Condition { private static final Logger LOG = LoggerFactory.getLogger(XPath.class); String expression, matches; XPathExpression cachedXPathExpression; boolean badExpression = false; @Override public String explain() { return "the xpath expression [" + expression + "] on the request XML body matches [" + matches + "]"; } public XPathExpression getXPathExpression() { if (cachedXPathExpression == null) { XPathFactory xPathfactory = XPathFactory.newInstance(); javax.xml.xpath.XPath xpath = xPathfactory.newXPath(); try { cachedXPathExpression = xpath.compile(this.expression); } catch (XPathExpressionException e) { this.badExpression = true; } } return cachedXPathExpression; } @Override public boolean test(RuleContext ctx) { String contentType = ctx.httpContext.getRequest().getHeaderValue("Content-Type"); if (!"application/xml".equals(contentType)) { return false; } XPathExpression xExp = this.getXPathExpression(); if (this.badExpression) { if (ctx.rule.tracing) { LOG.info("rule={} xpath expression is not valid", ctx.rule.id); } return false; } try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(ctx.httpContext.getRequest().getEntity(String.class)); String matchTarget = (String) xExp.evaluate(doc, XPathConstants.STRING); return matches.matches(matchTarget); } catch (Exception ex) { if (ctx.rule.tracing) { LOG.info("rule={} xml document parse failed, err={}", ctx.rule.id, ex.toString()); } LOG.error("xml document parse failed", ex); } return false; } }