View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.lang.rule;
    5
    6   import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0;
    7   import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_1_0_COMPATIBILITY;
    8   import static net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery.XPATH_2_0;
    9
    10  import java.util.List;
    11
    12  import net.sourceforge.pmd.PropertySource;
    13  import net.sourceforge.pmd.RuleContext;
    14  import net.sourceforge.pmd.lang.ast.Node;
    15  import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty;
    16  import net.sourceforge.pmd.lang.rule.properties.StringProperty;
    17  import net.sourceforge.pmd.lang.rule.xpath.JaxenXPathRuleQuery;
    18  import net.sourceforge.pmd.lang.rule.xpath.SaxonXPathRuleQuery;
    19  import net.sourceforge.pmd.lang.rule.xpath.XPathRuleQuery;
    20  import net.sourceforge.pmd.util.StringUtil;
    21
    22  /**
    23   * Rule that tries to match an XPath expression against a DOM view of an AST.
    24   * <p/>
    25   * This rule needs a "xpath" property value in order to function.
    26   */
    27  public class XPathRule extends AbstractRule {
    28
    29  	public static final StringProperty XPATH_DESCRIPTOR = new StringProperty("xpath", "XPath expression", "", 1.0f);
    30  	public static final EnumeratedProperty<String> VERSION_DESCRIPTOR = new EnumeratedProperty<String>("version",
    31  			"XPath specification version",
    32  			new String[] { XPATH_1_0, XPATH_1_0_COMPATIBILITY, XPATH_2_0 },
    33  			new String[] { XPATH_1_0, XPATH_1_0_COMPATIBILITY, XPATH_2_0 },
    34  			0, 2.0f);
    35
    36  	private XPathRuleQuery xpathRuleQuery;
    37
    38  	public XPathRule() {
    39  		definePropertyDescriptor(XPATH_DESCRIPTOR);
    40  		definePropertyDescriptor(VERSION_DESCRIPTOR);
    41  	}
    42
    43  	public XPathRule(String xPath) {
    44  		this();
    45  		setXPath(xPath);
    46  	}
    47
    48  	public void setXPath(String xPath) {
    49  		setProperty(XPathRule.XPATH_DESCRIPTOR, xPath);
    50  	}
    51
    52  	public void setVersion(String version) {
    53  		setProperty(XPathRule.VERSION_DESCRIPTOR, version);
    54  	}
    55
    56  	/**
    57  	 * Apply the rule to all nodes.
    58  	 */
    59  	public void apply(List<? extends Node> nodes, RuleContext ctx) {
    60  		for (Node node : nodes) {
    61  			evaluate(node, ctx);
    62  		}
    63  	}
    64
    65  	/**
    66  	 * Evaluate the XPath query with the AST node.
    67  	 * All matches are reported as violations.
    68  	 *
    69  	 * @param node The Node that to be checked.
    70  	 * @param data The RuleContext.
    71  	 */
    72  	public void evaluate(Node node, RuleContext data) {
    73  		init();
    74  		List<Node> nodes = xpathRuleQuery.evaluate(node, data);
    75  		if (nodes != null) {
    76  			for (Node n : nodes) {
    77  				addViolation(data, n, n.getImage());
    78  			}
    79  		}
    80
    81  	}
    82
    83  	@Override
    84  	public List<String> getRuleChainVisits() {
    85  		if (init()) {
    86  			for (String nodeName : xpathRuleQuery.getRuleChainVisits()) {
    87  				super.addRuleChainVisit(nodeName);
    88  			}
    89  		}
    90  		return super.getRuleChainVisits();
    91  	}
    92
    93  	private boolean init() {
    94  		if (xpathRuleQuery == null) {
    95  			String xpath = getProperty(XPATH_DESCRIPTOR);
    96  			String version = (String) getProperty(VERSION_DESCRIPTOR);
    97  			if (XPATH_1_0.equals(version)) {
    98  				xpathRuleQuery = new JaxenXPathRuleQuery();
    99  			} else {
    100 				xpathRuleQuery = new SaxonXPathRuleQuery();
    101 			}
    102 			xpathRuleQuery.setXPath(xpath);
    103 			xpathRuleQuery.setVersion(version);
    104 			xpathRuleQuery.setProperties(this.getPropertiesByPropertyDescriptor());
    105 			return true;
    106 		}
    107 		return false;
    108 	}
    109
    110
    111 	public boolean hasXPathExpression() {
    112 		String xPath = getProperty(XPATH_DESCRIPTOR);
    113 		return StringUtil.isNotEmpty(xPath);
    114 	}
    115
    116 	/**
    117 	 * @see PropertySource#dysfunctionReason()
    118 	 */
    119 	public String dysfunctionReason() {
    120 		return hasXPathExpression() ? null : "Missing xPath expression";
    121 	}
    122 }