View Javadoc

1   package net.sourceforge.pmd;
2   
3   import java.util.HashMap;
4   import java.util.List;
5   import java.util.Map;
6   
7   import net.sourceforge.pmd.lang.Language;
8   import net.sourceforge.pmd.lang.ast.Node;
9   import net.sourceforge.pmd.lang.rule.RuleChainVisitor;
10  
11  /**
12   * The RuleChain is a means by which Rules can participate in a uniform
13   * visitation of the AST, and not need perform their own independent visitation.
14   * The RuleChain exists as a means to improve the speed of PMD when there are
15   * many Rules.
16   */
17  public class RuleChain {
18      // Mapping from Language to RuleChainVisitor
19      private final Map<Language, RuleChainVisitor> languageToRuleChainVisitor = new HashMap<Language, RuleChainVisitor>();
20  
21      /**
22       * Add all Rules from the given RuleSet which want to participate in the
23       * RuleChain.
24       * 
25       * @param ruleSet
26       *            The RuleSet to add Rules from.
27       */
28      public void add(RuleSet ruleSet) {
29  	for (Rule r : ruleSet.getRules()) {
30              add(ruleSet, r);
31  	}
32      }
33  
34      /**
35       * Add the given Rule if it wants to participate in the RuleChain.
36       * 
37       * @param ruleSet
38       *            The RuleSet to which the rule belongs.
39       * @param rule
40       *            The Rule to add.
41       */
42      private void add(RuleSet ruleSet, Rule rule) {
43  	RuleChainVisitor visitor = getRuleChainVisitor(rule.getLanguage());
44  	if (visitor != null) {
45              visitor.add(ruleSet, rule);
46  	}
47      }
48  
49      /**
50       * Apply the RuleChain to the given Nodes using the given
51       * RuleContext, for those rules using the given Language.
52       * 
53       * @param nodes
54       *            The Nodes.
55       * @param ctx
56       *            The RuleContext.
57       * @param language
58       *            The Language.
59       */
60      public void apply(List<Node> nodes, RuleContext ctx, Language language) {
61  	RuleChainVisitor visitor = getRuleChainVisitor(language);
62  	if (visitor != null) {
63  	    visitor.visitAll(nodes, ctx);
64  	}
65      }
66  
67      // Get the RuleChainVisitor for the appropriate Language.
68      private RuleChainVisitor getRuleChainVisitor(Language language) {
69  	RuleChainVisitor visitor = languageToRuleChainVisitor.get(language);
70  	if (visitor == null) {
71  	    if (language.getRuleChainVisitorClass() != null) {
72  		try {
73  		    visitor = (RuleChainVisitor) language.getRuleChainVisitorClass().newInstance();
74  		} catch (InstantiationException e) {
75  		    throw new IllegalStateException("Failure to created RuleChainVisitor: "
76  			    + language.getRuleChainVisitorClass(), e);
77  		} catch (IllegalAccessException e) {
78  		    throw new IllegalStateException("Failure to created RuleChainVisitor: "
79  			    + language.getRuleChainVisitorClass(), e);
80  		}
81  		languageToRuleChainVisitor.put(language, visitor);
82  	    } else {
83  		throw new IllegalArgumentException("Language does not have a RuleChainVisitor: " + language);
84  	    }
85  	}
86  	return visitor;
87      }
88  }