View Javadoc

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