1 package net.sourceforge.pmd;
2
3 import net.sourceforge.pmd.util.ResourceLoader;
4 import org.w3c.dom.Document;
5 import org.w3c.dom.Element;
6 import org.w3c.dom.Node;
7 import org.w3c.dom.NodeList;
8
9 import javax.xml.parsers.DocumentBuilder;
10 import javax.xml.parsers.DocumentBuilderFactory;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.util.ArrayList;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Properties;
18 import java.util.Set;
19 import java.util.StringTokenizer;
20
21 public class RuleSetFactory {
22
23 /***
24 * Returns an Iterator of RuleSet objects
25 */
26 public Iterator getRegisteredRuleSets() throws RuleSetNotFoundException {
27 try {
28 Properties props = new Properties();
29 props.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties"));
30 String rulesetFilenames = props.getProperty("rulesets.filenames");
31 List ruleSets = new ArrayList();
32 for (StringTokenizer st = new StringTokenizer(rulesetFilenames, ","); st.hasMoreTokens();) {
33 ruleSets.add(createRuleSet(st.nextToken()));
34 }
35 return ruleSets.iterator();
36 } catch (IOException ioe) {
37 throw new RuntimeException("Couldn't find rulesets.properties; please ensure that the rulesets directory is on the classpath. Here's the current classpath: " + System.getProperty("java.class.path"));
38 }
39 }
40
41 public RuleSet createRuleSet(String name, ClassLoader classLoader) throws RuleSetNotFoundException {
42 if (name.indexOf(',') == -1) {
43 return createRuleSet(tryToGetStreamTo(name, classLoader));
44 }
45
46 RuleSet ruleSet = new RuleSet();
47 for (StringTokenizer st = new StringTokenizer(name, ","); st.hasMoreTokens();) {
48 String ruleSetName = st.nextToken().trim();
49 RuleSet tmpRuleSet = createRuleSet(ruleSetName, classLoader);
50 ruleSet.addRuleSet(tmpRuleSet);
51 }
52 return ruleSet;
53 }
54
55 /***
56 * Creates a ruleset. If passed a comma-delimited string (rulesets/basic.xml,rulesets/unusedcode.xml)
57 * it will parse that string and create a new ruleset for each item in the list.
58 */
59 public RuleSet createRuleSet(String name) throws RuleSetNotFoundException {
60 return createRuleSet(name, getClass().getClassLoader());
61 }
62
63 public RuleSet createRuleSet(InputStream inputStream) {
64 return createRuleSet(inputStream, getClass().getClassLoader());
65 }
66
67 public RuleSet createRuleSet(InputStream inputStream, ClassLoader classLoader) {
68 try {
69 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
70 Document doc = builder.parse(inputStream);
71 Element root = doc.getDocumentElement();
72
73 RuleSet ruleSet = new RuleSet();
74 ruleSet.setName(root.getAttribute("name"));
75 ruleSet.setDescription(root.getChildNodes().item(1).getFirstChild().getNodeValue());
76
77 NodeList rules = root.getElementsByTagName("rule");
78 for (int i = 0; i < rules.getLength(); i++) {
79 Node ruleNode = rules.item(i);
80 if (ruleNode.getAttributes().getNamedItem("ref") != null) {
81 parseExternallyDefinedRule(ruleSet, ruleNode);
82 } else {
83 parseInternallyDefinedRule(ruleSet, ruleNode, classLoader);
84 }
85 }
86 return ruleSet;
87 } catch (Exception e) {
88 e.printStackTrace();
89 throw new RuntimeException("Couldn't read from that source: " + e.getMessage());
90 }
91 }
92
93 private void parseInternallyDefinedRule(RuleSet ruleSet, Node ruleNode, ClassLoader classLoader) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
94 Rule rule = (Rule) Class.forName(ruleNode.getAttributes().getNamedItem("class").getNodeValue(), true, classLoader).newInstance();
95 rule.setName(ruleNode.getAttributes().getNamedItem("name").getNodeValue());
96 rule.setMessage(ruleNode.getAttributes().getNamedItem("message").getNodeValue());
97 // get the description, priority, example and properties (if any)
98 Node node = ruleNode.getFirstChild();
99 while (node != null) {
100 if (node.getNodeName() != null && node.getNodeName().equals("description")) {
101 rule.setDescription(node.getFirstChild().getNodeValue());
102 }
103
104 if (node.getNodeName() != null && node.getNodeName().equals("priority")) {
105 rule.setPriority(Integer.parseInt(node.getFirstChild().getNodeValue().trim()));
106 }
107
108 if (node.getNodeName() != null && node.getNodeName().equals("example")) {
109 rule.setExample(node.getFirstChild().getNextSibling().getNodeValue());
110 }
111
112 parseProperties(node, rule);
113
114 node = node.getNextSibling();
115 }
116 ruleSet.addRule(rule);
117 }
118
119 /***
120 * Here's how to exclude rules:
121 *
122 * <rule ref="rulesets/braces.xml">
123 * <exclude name="WhileLoopsMustUseBracesRule"/>
124 * <exclude name="IfElseStmtsMustUseBracesRule"/>
125 * </rule>
126 *
127 */
128 private void parseExternallyDefinedRule(RuleSet ruleSet, Node ruleNode) throws RuleSetNotFoundException {
129 String referenceValue = ruleNode.getAttributes().getNamedItem("ref").getNodeValue();
130 if (referenceValue.endsWith("xml")) {
131 parseWithExcludes(ruleNode, referenceValue, ruleSet);
132 } else {
133 parseSimpleReference(referenceValue, ruleSet);
134 }
135 }
136
137 private void parseSimpleReference(String referenceValue, RuleSet ruleSet) throws RuleSetNotFoundException {
138 RuleSetFactory rsf = new RuleSetFactory();
139 ExternalRuleID externalRuleID = new ExternalRuleID(referenceValue);
140 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader.loadResourceAsStream(externalRuleID.getFilename()));
141 ruleSet.addRule(externalRuleSet.getRuleByName(externalRuleID.getRuleName()));
142 }
143
144 private void parseWithExcludes(Node ruleNode, String referenceValue, RuleSet ruleSet) throws RuleSetNotFoundException {
145 NodeList excludeNodes = ruleNode.getChildNodes();
146 Set excludes = new HashSet();
147 for (int i=0; i<excludeNodes.getLength(); i++) {
148 Node node = excludeNodes.item(i);
149 if (node.getAttributes() != null) {
150 excludes.add(node.getAttributes().getNamedItem("name").getNodeValue());
151 }
152 }
153 RuleSetFactory rsf = new RuleSetFactory();
154 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader.loadResourceAsStream(referenceValue));
155 for (Iterator i = externalRuleSet.getRules().iterator(); i.hasNext();) {
156 Rule rule = (Rule)i.next();
157 if (!excludes.contains(rule.getName())) {
158 ruleSet.addRule(rule);
159 }
160 }
161 }
162
163 private void parseProperties(Node node, Rule rule) {
164 if (node.getNodeName().equals("properties")) {
165 Node propNode = node.getFirstChild().getNextSibling();
166 while (propNode != null && propNode.getAttributes() != null) {
167 propNode = parseProperty(propNode, rule);
168 }
169 }
170 }
171
172 private Node parseProperty(Node propNode, Rule rule) {
173 String propName = propNode.getAttributes().getNamedItem("name").getNodeValue();
174 String propValue;
175 if (propName.equals("xpath")) {
176 Node xpathExprNode = propNode.getFirstChild().getNextSibling();
177 propValue = xpathExprNode.getFirstChild().getNextSibling().getNodeValue();
178 } else {
179 propValue = propNode.getAttributes().getNamedItem("value").getNodeValue();
180 }
181 rule.addProperty(propName, propValue);
182 return propNode.getNextSibling().getNextSibling();
183 }
184
185 private InputStream tryToGetStreamTo(String name, ClassLoader loader) throws RuleSetNotFoundException {
186 InputStream in = ResourceLoader.loadResourceAsStream(name, loader);
187 if (in == null) {
188 throw new RuleSetNotFoundException("Can't find resource " + name + ". Make sure the resource is a valid file or URL or is on the CLASSPATH");
189 }
190 return in;
191 }
192 }
This page was automatically generated by Maven