KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > pmd > RuleSetFactory


1 /**
2  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3  */

4 package net.sourceforge.pmd;
5
6 import net.sourceforge.pmd.util.ResourceLoader;
7 import org.w3c.dom.Document JavaDoc;
8 import org.w3c.dom.Element JavaDoc;
9 import org.w3c.dom.Node JavaDoc;
10 import org.w3c.dom.NodeList JavaDoc;
11 import org.xml.sax.SAXException JavaDoc;
12
13 import javax.xml.parsers.DocumentBuilder JavaDoc;
14 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
15 import javax.xml.parsers.ParserConfigurationException JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.InputStream JavaDoc;
18 import java.util.HashSet JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.Properties JavaDoc;
21 import java.util.Set JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23
24 import net.sourceforge.pmd.rules.XPathRule;
25
26 // Note that ruleset parsing may fail on JDK 1.6 beta
27
// due to this bug - http://www.netbeans.org/issues/show_bug.cgi?id=63257
28

29 public class RuleSetFactory {
30
31     private static class OverrideParser {
32         private Element JavaDoc ruleElement;
33
34         public OverrideParser(Element JavaDoc ruleElement) {
35             this.ruleElement = ruleElement;
36         }
37
38         public void overrideAsNecessary(Rule rule) {
39             if (ruleElement.hasAttribute("name")) {
40                 rule.setName(ruleElement.getAttribute("name"));
41             }
42             if (ruleElement.hasAttribute("message")) {
43                 rule.setMessage(ruleElement.getAttribute("message"));
44             }
45             if (ruleElement.hasAttribute("externalInfoUrl")) {
46                 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
47             }
48             for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
49                 Node JavaDoc node = ruleElement.getChildNodes().item(i);
50                 if (node.getNodeType() == Node.ELEMENT_NODE) {
51                     if (node.getNodeName().equals("description")) {
52                         rule.setDescription(parseTextNode(node));
53                     } else if (node.getNodeName().equals("example")) {
54                         rule.setExample(parseTextNode(node));
55                     } else if (node.getNodeName().equals("priority")) {
56                         rule.setPriority(Integer.parseInt(parseTextNode(node)));
57                     } else if (node.getNodeName().equals("properties")) {
58                         Properties JavaDoc p = new Properties JavaDoc();
59                         parsePropertiesNode(p, node);
60                         rule.addProperties(p);
61                     }
62                 }
63             }
64         }
65     }
66
67     private int minPriority = Rule.LOWEST_PRIORITY;
68
69     public void setMinimumPriority(int minPriority) {
70         this.minPriority = minPriority;
71     }
72
73     /**
74      * Returns an Iterator of RuleSet objects loaded from descriptions from the
75      * "rulesets.properties" resource.
76      *
77      * @return an iterator of RuleSet objects
78      */

79     public Iterator JavaDoc getRegisteredRuleSets() throws RuleSetNotFoundException {
80         try {
81             Properties JavaDoc props = new Properties JavaDoc();
82             props.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties"));
83             String JavaDoc rulesetFilenames = props.getProperty("rulesets.filenames");
84             return createRuleSets(rulesetFilenames).getRuleSetsIterator();
85         } catch (IOException JavaDoc ioe) {
86             throw new RuntimeException JavaDoc("Couldn't find rulesets.properties; please ensure that the rulesets directory is on the classpath. Here's the current classpath: "
87                     + System.getProperty("java.class.path"));
88         }
89     }
90
91     /**
92      * Create a RuleSets from a list of names.
93      *
94      * @param ruleSetFileNames comma-separated list of rule set files.
95      * @param classLoader the classloader to load the rulesets
96      * @throws RuleSetNotFoundException
97      */

98     public RuleSets createRuleSets(String JavaDoc ruleSetFileNames, ClassLoader JavaDoc classLoader)
99             throws RuleSetNotFoundException {
100         RuleSets ruleSets = new RuleSets();
101
102         for (StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(ruleSetFileNames, ","); st
103                 .hasMoreTokens();) {
104             RuleSet ruleSet = createSingleRuleSet(st.nextToken().trim(), classLoader);
105             ruleSets.addRuleSet(ruleSet);
106         }
107
108         return ruleSets;
109     }
110
111     /**
112      * Create a RuleSets from a list of names, using the classloader of this class.
113      *
114      * @param ruleSetFileNames comma-separated list of rule set files.
115      * @throws RuleSetNotFoundException
116      */

117     public RuleSets createRuleSets(String JavaDoc ruleSetFileNames)
118             throws RuleSetNotFoundException {
119         return createRuleSets(ruleSetFileNames, getClass().getClassLoader());
120     }
121
122     /**
123      * Create a ruleset from a name or from a list of names
124      *
125      * @param name name of rule set file loaded as a resource
126      * @param classLoader the classloader used to load the ruleset and subsequent rules
127      * @return the new ruleset
128      * @throws RuleSetNotFoundException
129      * @deprecated Use createRuleSets instead, because this method puts all rules in one
130      * single RuleSet object, and thus removes name and language of the
131      * originating rule set files.
132      */

133     public RuleSet createRuleSet(String JavaDoc name, ClassLoader JavaDoc classLoader) throws RuleSetNotFoundException {
134         RuleSets ruleSets = createRuleSets(name, classLoader);
135         RuleSet result = new RuleSet();
136         RuleSet[] allRuleSets = ruleSets.getAllRuleSets();
137         for (int i = 0; i < allRuleSets.length; i++) {
138             result.addRuleSet(allRuleSets[i]);
139         }
140         return result;
141     }
142
143     /**
144      * Create a ruleset from a name
145      *
146      * @param ruleSetFileName name of rule set file loaded as a resource
147      * @param classLoader the classloader used to load the ruleset and subsequent rules
148      * @return the new ruleset
149      * @throws RuleSetNotFoundException
150      */

151     private RuleSet createSingleRuleSet(String JavaDoc ruleSetFileName, ClassLoader JavaDoc classLoader)
152             throws RuleSetNotFoundException {
153         return createRuleSet(tryToGetStreamTo(ruleSetFileName, classLoader), classLoader);
154     }
155
156     /**
157      * Create a ruleset from a name
158      *
159      * @param ruleSetFileName name of rule set file loaded as a resource
160      * @return the new ruleset
161      * @throws RuleSetNotFoundException
162      */

163     public RuleSet createSingleRuleSet(String JavaDoc ruleSetFileName)
164             throws RuleSetNotFoundException {
165         return createRuleSet(tryToGetStreamTo(ruleSetFileName, getClass()
166                 .getClassLoader()));
167     }
168
169     /**
170      * Create a ruleset from an inputsteam. Same as createRuleSet(inputStream,
171      * ruleSetFactory.getClassLoader()).
172      *
173      * @param inputStream an input stream that contains a ruleset descripion
174      * @return a new ruleset
175      */

176     public RuleSet createRuleSet(InputStream JavaDoc inputStream) {
177         return createRuleSet(inputStream, getClass().getClassLoader());
178     }
179
180     /**
181      * Create a ruleset from an input stream with a specified class loader
182      *
183      * @param inputStream an input stream that contains a ruleset descripion
184      * @param classLoader a class loader used to load rule classes
185      * @return a new ruleset
186      */

187     private RuleSet createRuleSet(InputStream JavaDoc inputStream, ClassLoader JavaDoc classLoader) {
188         try {
189             DocumentBuilder JavaDoc builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
190             Document JavaDoc doc = builder.parse(inputStream);
191             Element JavaDoc root = doc.getDocumentElement();
192
193             RuleSet ruleSet = new RuleSet();
194             ruleSet.setName(root.getAttribute("name"));
195             ruleSet.setLanguage(Language.getByName(root.getAttribute("language")));
196
197             NodeList JavaDoc nodeList = root.getChildNodes();
198             for (int i = 0; i < nodeList.getLength(); i++) {
199                 Node JavaDoc node = nodeList.item(i);
200                 if (node.getNodeType() == Node.ELEMENT_NODE) {
201                     if (node.getNodeName().equals("description")) {
202                         ruleSet.setDescription(parseTextNode(node));
203                     } else if (node.getNodeName().equals("rule")) {
204                         parseRuleNode(ruleSet, node, classLoader);
205                     }
206                 }
207             }
208
209             return ruleSet;
210         } catch (ClassNotFoundException JavaDoc cnfe) {
211             cnfe.printStackTrace();
212             throw new RuntimeException JavaDoc("Couldn't find that class " + cnfe.getMessage());
213         } catch (InstantiationException JavaDoc ie) {
214             ie.printStackTrace();
215             throw new RuntimeException JavaDoc("Couldn't find that class " + ie.getMessage());
216         } catch (IllegalAccessException JavaDoc iae) {
217             iae.printStackTrace();
218             throw new RuntimeException JavaDoc("Couldn't find that class " + iae.getMessage());
219         } catch (ParserConfigurationException JavaDoc pce) {
220             pce.printStackTrace();
221             throw new RuntimeException JavaDoc("Couldn't find that class " + pce.getMessage());
222         } catch (RuleSetNotFoundException rsnfe) {
223             rsnfe.printStackTrace();
224             throw new RuntimeException JavaDoc("Couldn't find that class " + rsnfe.getMessage());
225         } catch (IOException JavaDoc ioe) {
226             ioe.printStackTrace();
227             throw new RuntimeException JavaDoc("Couldn't find that class " + ioe.getMessage());
228         } catch (SAXException JavaDoc se) {
229             se.printStackTrace();
230             throw new RuntimeException JavaDoc("Couldn't find that class " + se.getMessage());
231         }
232     }
233
234     /**
235      * Try to load a resource with the specified class loader
236      *
237      * @param name a resource name (contains a ruleset description)
238      * @param loader a class loader used to load that rule set description
239      * @return an inputstream to that resource
240      * @throws RuleSetNotFoundException
241      */

242     private InputStream JavaDoc tryToGetStreamTo(String JavaDoc name, ClassLoader JavaDoc loader)
243             throws RuleSetNotFoundException {
244         InputStream JavaDoc in = ResourceLoader.loadResourceAsStream(name, loader);
245         if (in == null) {
246             throw new RuleSetNotFoundException("Can't find resource "
247                     + name
248                     + ". Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
249                     + System.getProperty("java.class.path"));
250         }
251         return in;
252     }
253
254     /**
255      * Parse a rule node
256      *
257      * @param ruleSet the ruleset being constructed
258      * @param ruleNode must be a rule element node
259      */

260     private void parseRuleNode(RuleSet ruleSet, Node JavaDoc ruleNode, ClassLoader JavaDoc classLoader)
261             throws ClassNotFoundException JavaDoc, InstantiationException JavaDoc,
262             IllegalAccessException JavaDoc, RuleSetNotFoundException {
263         Element JavaDoc ruleElement = (Element JavaDoc) ruleNode;
264         String JavaDoc ref = ruleElement.getAttribute("ref");
265         if (ref.trim().length() == 0) {
266             parseInternallyDefinedRuleNode(ruleSet, ruleNode, classLoader);
267         } else {
268             parseExternallyDefinedRuleNode(ruleSet, ruleNode);
269         }
270     }
271
272     /**
273      * Process a rule definition node
274      *
275      * @param ruleSet the ruleset being constructed
276      * @param ruleNode must be a rule element node
277      */

278     private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node JavaDoc ruleNode, ClassLoader JavaDoc classLoader)
279             throws ClassNotFoundException JavaDoc, InstantiationException JavaDoc, IllegalAccessException JavaDoc {
280         Element JavaDoc ruleElement = (Element JavaDoc) ruleNode;
281
282         String JavaDoc attribute = ruleElement.getAttribute("class");
283         Class JavaDoc c;
284         if ((Language.JAVA.equals(ruleSet.getLanguage()) || ruleSet.getLanguage() == null) &&
285                 attribute.equals("net.sourceforge.pmd.rules.XPathRule")) {
286             String JavaDoc xpath = null;
287             for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
288                 Node JavaDoc node = ruleElement.getChildNodes().item(i);
289                 if (node.getNodeType() == Node.ELEMENT_NODE) {
290                     if (node.getNodeName().equals("properties")) {
291                         Properties JavaDoc p = new Properties JavaDoc();
292                         parsePropertiesNode(p, node);
293                         xpath = p.getProperty("xpath");
294                     }
295                 }
296             }
297             c = XPathRule.loadClass(classLoader, xpath, ruleElement.getAttribute("name"));
298         } else {
299             c = classLoader.loadClass(attribute);
300         }
301         Rule rule = (Rule) c.newInstance();
302
303         rule.setName(ruleElement.getAttribute("name"));
304         rule.setMessage(ruleElement.getAttribute("message"));
305         rule.setRuleSetName(ruleSet.getName());
306         rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
307
308         if (ruleElement.hasAttribute("dfa")
309                 && ruleElement.getAttribute("dfa").equals("true")) {
310             rule.setUsesDFA();
311         }
312
313         if (ruleElement.hasAttribute("typeResolution")
314                 && ruleElement.getAttribute("typeResolution").equals("true")) {
315             rule.setUsesTypeResolution();
316         }
317
318         for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
319             Node JavaDoc node = ruleElement.getChildNodes().item(i);
320             if (node.getNodeType() == Node.ELEMENT_NODE) {
321                 if (node.getNodeName().equals("description")) {
322                     rule.setDescription(parseTextNode(node));
323                 } else if (node.getNodeName().equals("example")) {
324                     rule.setExample(parseTextNode(node));
325                 } else if (node.getNodeName().equals("priority")) {
326                     rule.setPriority(new Integer JavaDoc(parseTextNode(node).trim()).intValue());
327                 } else if (node.getNodeName().equals("properties")) {
328                     Properties JavaDoc p = new Properties JavaDoc();
329                     parsePropertiesNode(p, node);
330                     for (Iterator JavaDoc j = p.keySet().iterator(); j.hasNext();) {
331                         String JavaDoc key = (String JavaDoc) j.next();
332                         rule.addProperty(key, p.getProperty(key));
333                     }
334                 }
335             }
336         }
337         if (rule.getPriority() <= minPriority) {
338             ruleSet.addRule(rule);
339         }
340     }
341
342     /**
343      * Process a reference to a rule
344      *
345      * @param ruleSet the ruleset being constructucted
346      * @param ruleNode must be a rule element node
347      */

348     private void parseExternallyDefinedRuleNode(RuleSet ruleSet, Node JavaDoc ruleNode)
349             throws RuleSetNotFoundException {
350         Element JavaDoc ruleElement = (Element JavaDoc) ruleNode;
351         String JavaDoc ref = ruleElement.getAttribute("ref");
352         if (ref.endsWith("xml")) {
353             parseRuleNodeWithExclude(ruleSet, ruleElement, ref);
354         } else {
355             parseRuleNodeWithSimpleReference(ruleSet, ruleNode, ref);
356         }
357     }
358
359     /**
360      * Parse a rule node with a simple reference
361      *
362      * @param ruleSet the ruleset being constructed
363      * @param ref a reference to a rule
364      */

365     private void parseRuleNodeWithSimpleReference(RuleSet ruleSet, Node JavaDoc ruleNode,
366                                                   String JavaDoc ref) throws RuleSetNotFoundException {
367         RuleSetFactory rsf = new RuleSetFactory();
368
369         ExternalRuleID externalRuleID = new ExternalRuleID(ref);
370         RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
371                 .loadResourceAsStream(externalRuleID.getFilename()));
372         Rule externalRule = externalRuleSet.getRuleByName(externalRuleID.getRuleName());
373         if (externalRule == null) {
374             throw new IllegalArgumentException JavaDoc("Unable to find rule "
375                     + externalRuleID.getRuleName()
376                     + "; perhaps the rule name is mispelled?");
377         }
378
379         OverrideParser p = new OverrideParser((Element JavaDoc) ruleNode);
380         p.overrideAsNecessary(externalRule);
381
382         if (externalRule.getPriority() <= minPriority) {
383             ruleSet.addRule(externalRule);
384         }
385     }
386
387     /**
388      * Parse a reference rule node with excludes
389      *
390      * @param ruleSet the ruleset being constructed
391      * @param ruleElement must be a rule element
392      * @param ref the ruleset reference
393      */

394     private void parseRuleNodeWithExclude(RuleSet ruleSet, Element JavaDoc ruleElement, String JavaDoc ref)
395             throws RuleSetNotFoundException {
396         NodeList JavaDoc excludeNodes = ruleElement.getChildNodes();
397         Set JavaDoc excludes = new HashSet JavaDoc();
398         for (int i = 0; i < excludeNodes.getLength(); i++) {
399             if ((excludeNodes.item(i).getNodeType() == Node.ELEMENT_NODE)
400                     && (excludeNodes.item(i).getNodeName().equals("exclude"))) {
401                 Element JavaDoc excludeElement = (Element JavaDoc) excludeNodes.item(i);
402                 excludes.add(excludeElement.getAttribute("name"));
403             }
404         }
405
406         RuleSetFactory rsf = new RuleSetFactory();
407         RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
408                 .loadResourceAsStream(ref));
409         for (Iterator JavaDoc i = externalRuleSet.getRules().iterator(); i.hasNext();) {
410             Rule rule = (Rule) i.next();
411             if (!excludes.contains(rule.getName()) && rule.getPriority() <= minPriority) {
412                 ruleSet.addRule(rule);
413             }
414         }
415     }
416
417     private static String JavaDoc parseTextNode(Node JavaDoc exampleNode) {
418         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
419         for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) {
420             Node JavaDoc node = exampleNode.getChildNodes().item(i);
421             if (node.getNodeType() == Node.CDATA_SECTION_NODE
422                     || node.getNodeType() == Node.TEXT_NODE) {
423                 buffer.append(node.getNodeValue());
424             }
425         }
426         return buffer.toString();
427     }
428
429     /**
430      * Parse a properties node
431      *
432      * @param propertiesNode must be a properties element node
433      */

434     private static void parsePropertiesNode(Properties JavaDoc p, Node JavaDoc propertiesNode) {
435         for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) {
436             Node JavaDoc node = propertiesNode.getChildNodes().item(i);
437             if (node.getNodeType() == Node.ELEMENT_NODE
438                     && node.getNodeName().equals("property")) {
439                 parsePropertyNode(p, node);
440             }
441         }
442     }
443
444     /**
445      * Parse a property node
446      *
447      * @param propertyNode must be a property element node
448      */

449     private static void parsePropertyNode(Properties JavaDoc p, Node JavaDoc propertyNode) {
450         Element JavaDoc propertyElement = (Element JavaDoc) propertyNode;
451         String JavaDoc name = propertyElement.getAttribute("name");
452         String JavaDoc value = propertyElement.getAttribute("value");
453         // TODO String desc = propertyElement.getAttribute("description");
454
if (value.trim().length() == 0) {
455             for (int i = 0; i < propertyNode.getChildNodes().getLength(); i++) {
456                 Node JavaDoc node = propertyNode.getChildNodes().item(i);
457                 if ((node.getNodeType() == Node.ELEMENT_NODE)
458                         && node.getNodeName().equals("value")) {
459                     value = parseTextNode(node);
460                 }
461             }
462         }
463         if (propertyElement.hasAttribute("pluginname")) {
464             p.setProperty("pluginname", propertyElement.getAttributeNode("pluginname")
465                     .getNodeValue());
466         }
467         p.setProperty(name, value);
468     }
469 }
470
Popular Tags