Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 469   Methods: 20
NCLOC: 314   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
RuleSetFactory.java 89.1% 82.2% 90% 85.1%
coverage coverage
 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;
 8    import org.w3c.dom.Element;
 9    import org.w3c.dom.Node;
 10    import org.w3c.dom.NodeList;
 11    import org.xml.sax.SAXException;
 12   
 13    import javax.xml.parsers.DocumentBuilder;
 14    import javax.xml.parsers.DocumentBuilderFactory;
 15    import javax.xml.parsers.ParserConfigurationException;
 16    import java.io.IOException;
 17    import java.io.InputStream;
 18    import java.util.HashSet;
 19    import java.util.Iterator;
 20    import java.util.Properties;
 21    import java.util.Set;
 22    import java.util.StringTokenizer;
 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 ruleElement;
 33   
 34  14 public OverrideParser(Element ruleElement) {
 35  14 this.ruleElement = ruleElement;
 36    }
 37   
 38  14 public void overrideAsNecessary(Rule rule) {
 39  14 if (ruleElement.hasAttribute("name")) {
 40  1 rule.setName(ruleElement.getAttribute("name"));
 41    }
 42  14 if (ruleElement.hasAttribute("message")) {
 43  4 rule.setMessage(ruleElement.getAttribute("message"));
 44    }
 45  14 if (ruleElement.hasAttribute("externalInfoUrl")) {
 46  0 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
 47    }
 48  14 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 49  16 Node node = ruleElement.getChildNodes().item(i);
 50  16 if (node.getNodeType() == Node.ELEMENT_NODE) {
 51  6 if (node.getNodeName().equals("description")) {
 52  1 rule.setDescription(parseTextNode(node));
 53  5 } else if (node.getNodeName().equals("example")) {
 54  1 rule.setExample(parseTextNode(node));
 55  4 } else if (node.getNodeName().equals("priority")) {
 56  2 rule.setPriority(Integer.parseInt(parseTextNode(node)));
 57  2 } else if (node.getNodeName().equals("properties")) {
 58  2 Properties p = new Properties();
 59  2 parsePropertiesNode(p, node);
 60  2 rule.addProperties(p);
 61    }
 62    }
 63    }
 64    }
 65    }
 66   
 67    private int minPriority = Rule.LOWEST_PRIORITY;
 68   
 69  2 public void setMinimumPriority(int minPriority) {
 70  2 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  0 public Iterator getRegisteredRuleSets() throws RuleSetNotFoundException {
 80  0 try {
 81  0 Properties props = new Properties();
 82  0 props.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties"));
 83  0 String rulesetFilenames = props.getProperty("rulesets.filenames");
 84  0 return createRuleSets(rulesetFilenames).getRuleSetsIterator();
 85    } catch (IOException ioe) {
 86  0 throw new RuntimeException("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  218 public RuleSets createRuleSets(String ruleSetFileNames, ClassLoader classLoader)
 99    throws RuleSetNotFoundException {
 100  218 RuleSets ruleSets = new RuleSets();
 101   
 102  218 for (StringTokenizer st = new StringTokenizer(ruleSetFileNames, ","); st
 103    .hasMoreTokens();) {
 104  218 RuleSet ruleSet = createSingleRuleSet(st.nextToken().trim(), classLoader);
 105  218 ruleSets.addRuleSet(ruleSet);
 106    }
 107   
 108  218 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  218 public RuleSets createRuleSets(String ruleSetFileNames)
 118    throws RuleSetNotFoundException {
 119  218 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  0 public RuleSet createRuleSet(String name, ClassLoader classLoader) throws RuleSetNotFoundException {
 134  0 RuleSets ruleSets = createRuleSets(name, classLoader);
 135  0 RuleSet result = new RuleSet();
 136  0 RuleSet[] allRuleSets = ruleSets.getAllRuleSets();
 137  0 for (int i = 0; i < allRuleSets.length; i++) {
 138  0 result.addRuleSet(allRuleSets[i]);
 139    }
 140  0 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  218 private RuleSet createSingleRuleSet(String ruleSetFileName, ClassLoader classLoader)
 152    throws RuleSetNotFoundException {
 153  218 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  2 public RuleSet createSingleRuleSet(String ruleSetFileName)
 164    throws RuleSetNotFoundException {
 165  2 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  33 public RuleSet createRuleSet(InputStream inputStream) {
 177  33 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  251 private RuleSet createRuleSet(InputStream inputStream, ClassLoader classLoader) {
 188  251 try {
 189  251 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 190  251 Document doc = builder.parse(inputStream);
 191  251 Element root = doc.getDocumentElement();
 192   
 193  251 RuleSet ruleSet = new RuleSet();
 194  251 ruleSet.setName(root.getAttribute("name"));
 195  251 ruleSet.setLanguage(Language.getByName(root.getAttribute("language")));
 196   
 197  251 NodeList nodeList = root.getChildNodes();
 198  251 for (int i = 0; i < nodeList.getLength(); i++) {
 199  9866 Node node = nodeList.item(i);
 200  9866 if (node.getNodeType() == Node.ELEMENT_NODE) {
 201  4796 if (node.getNodeName().equals("description")) {
 202  250 ruleSet.setDescription(parseTextNode(node));
 203  4546 } else if (node.getNodeName().equals("rule")) {
 204  4543 parseRuleNode(ruleSet, node, classLoader);
 205    }
 206    }
 207    }
 208   
 209  250 return ruleSet;
 210    } catch (ClassNotFoundException cnfe) {
 211  0 cnfe.printStackTrace();
 212  0 throw new RuntimeException("Couldn't find that class " + cnfe.getMessage());
 213    } catch (InstantiationException ie) {
 214  0 ie.printStackTrace();
 215  0 throw new RuntimeException("Couldn't find that class " + ie.getMessage());
 216    } catch (IllegalAccessException iae) {
 217  0 iae.printStackTrace();
 218  0 throw new RuntimeException("Couldn't find that class " + iae.getMessage());
 219    } catch (ParserConfigurationException pce) {
 220  0 pce.printStackTrace();
 221  0 throw new RuntimeException("Couldn't find that class " + pce.getMessage());
 222    } catch (RuleSetNotFoundException rsnfe) {
 223  0 rsnfe.printStackTrace();
 224  0 throw new RuntimeException("Couldn't find that class " + rsnfe.getMessage());
 225    } catch (IOException ioe) {
 226  0 ioe.printStackTrace();
 227  0 throw new RuntimeException("Couldn't find that class " + ioe.getMessage());
 228    } catch (SAXException se) {
 229  0 se.printStackTrace();
 230  0 throw new RuntimeException("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  220 private InputStream tryToGetStreamTo(String name, ClassLoader loader)
 243    throws RuleSetNotFoundException {
 244  220 InputStream in = ResourceLoader.loadResourceAsStream(name, loader);
 245  220 if (in == null) {
 246  1 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  219 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  4543 private void parseRuleNode(RuleSet ruleSet, Node ruleNode, ClassLoader classLoader)
 261    throws ClassNotFoundException, InstantiationException,
 262    IllegalAccessException, RuleSetNotFoundException {
 263  4543 Element ruleElement = (Element) ruleNode;
 264  4543 String ref = ruleElement.getAttribute("ref");
 265  4543 if (ref.trim().length() == 0) {
 266  4526 parseInternallyDefinedRuleNode(ruleSet, ruleNode, classLoader);
 267    } else {
 268  17 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  4526 private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode, ClassLoader classLoader)
 279    throws ClassNotFoundException, InstantiationException, IllegalAccessException {
 280  4526 Element ruleElement = (Element) ruleNode;
 281   
 282  4526 String attribute = ruleElement.getAttribute("class");
 283  4526 Class c;
 284  4526 if ((Language.JAVA.equals(ruleSet.getLanguage()) || ruleSet.getLanguage() == null) &&
 285    attribute.equals("net.sourceforge.pmd.rules.XPathRule")) {
 286  2451 String xpath = null;
 287  2451 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 288  22095 Node node = ruleElement.getChildNodes().item(i);
 289  22095 if (node.getNodeType() == Node.ELEMENT_NODE) {
 290  9822 if (node.getNodeName().equals("properties")) {
 291  2451 Properties p = new Properties();
 292  2451 parsePropertiesNode(p, node);
 293  2451 xpath = p.getProperty("xpath");
 294    }
 295    }
 296    }
 297  2451 c = XPathRule.loadClass(classLoader, xpath, ruleElement.getAttribute("name"));
 298    } else {
 299  2075 c = classLoader.loadClass(attribute);
 300    }
 301  4526 Rule rule = (Rule) c.newInstance();
 302   
 303  4526 rule.setName(ruleElement.getAttribute("name"));
 304  4526 rule.setMessage(ruleElement.getAttribute("message"));
 305  4526 rule.setRuleSetName(ruleSet.getName());
 306  4526 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
 307   
 308  4526 if (ruleElement.hasAttribute("dfa")
 309    && ruleElement.getAttribute("dfa").equals("true")) {
 310  18 rule.setUsesDFA();
 311    }
 312   
 313  4526 if (ruleElement.hasAttribute("typeResolution")
 314    && ruleElement.getAttribute("typeResolution").equals("true")) {
 315  4 rule.setUsesTypeResolution();
 316    }
 317   
 318  4526 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 319  37904 Node node = ruleElement.getChildNodes().item(i);
 320  37904 if (node.getNodeType() == Node.ELEMENT_NODE) {
 321  16698 if (node.getNodeName().equals("description")) {
 322  4480 rule.setDescription(parseTextNode(node));
 323  12218 } else if (node.getNodeName().equals("example")) {
 324  4568 rule.setExample(parseTextNode(node));
 325  7650 } else if (node.getNodeName().equals("priority")) {
 326  4468 rule.setPriority(new Integer(parseTextNode(node).trim()).intValue());
 327  3182 } else if (node.getNodeName().equals("properties")) {
 328  3182 Properties p = new Properties();
 329  3182 parsePropertiesNode(p, node);
 330  3182 for (Iterator j = p.keySet().iterator(); j.hasNext();) {
 331  3231 String key = (String) j.next();
 332  3231 rule.addProperty(key, p.getProperty(key));
 333    }
 334    }
 335    }
 336    }
 337  4526 if (rule.getPriority() <= minPriority) {
 338  4525 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  17 private void parseExternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode)
 349    throws RuleSetNotFoundException {
 350  17 Element ruleElement = (Element) ruleNode;
 351  17 String ref = ruleElement.getAttribute("ref");
 352  17 if (ref.endsWith("xml")) {
 353  2 parseRuleNodeWithExclude(ruleSet, ruleElement, ref);
 354    } else {
 355  15 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  15 private void parseRuleNodeWithSimpleReference(RuleSet ruleSet, Node ruleNode,
 366    String ref) throws RuleSetNotFoundException {
 367  15 RuleSetFactory rsf = new RuleSetFactory();
 368   
 369  15 ExternalRuleID externalRuleID = new ExternalRuleID(ref);
 370  15 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
 371    .loadResourceAsStream(externalRuleID.getFilename()));
 372  15 Rule externalRule = externalRuleSet.getRuleByName(externalRuleID.getRuleName());
 373  15 if (externalRule == null) {
 374  1 throw new IllegalArgumentException("Unable to find rule "
 375    + externalRuleID.getRuleName()
 376    + "; perhaps the rule name is mispelled?");
 377    }
 378   
 379  14 OverrideParser p = new OverrideParser((Element) ruleNode);
 380  14 p.overrideAsNecessary(externalRule);
 381   
 382  14 if (externalRule.getPriority() <= minPriority) {
 383  14 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  2 private void parseRuleNodeWithExclude(RuleSet ruleSet, Element ruleElement, String ref)
 395    throws RuleSetNotFoundException {
 396  2 NodeList excludeNodes = ruleElement.getChildNodes();
 397  2 Set excludes = new HashSet();
 398  2 for (int i = 0; i < excludeNodes.getLength(); i++) {
 399  0 if ((excludeNodes.item(i).getNodeType() == Node.ELEMENT_NODE)
 400    && (excludeNodes.item(i).getNodeName().equals("exclude"))) {
 401  0 Element excludeElement = (Element) excludeNodes.item(i);
 402  0 excludes.add(excludeElement.getAttribute("name"));
 403    }
 404    }
 405   
 406  2 RuleSetFactory rsf = new RuleSetFactory();
 407  2 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
 408    .loadResourceAsStream(ref));
 409  2 for (Iterator i = externalRuleSet.getRules().iterator(); i.hasNext();) {
 410  34 Rule rule = (Rule) i.next();
 411  34 if (!excludes.contains(rule.getName()) && rule.getPriority() <= minPriority) {
 412  34 ruleSet.addRule(rule);
 413    }
 414    }
 415    }
 416   
 417  18995 private static String parseTextNode(Node exampleNode) {
 418  18995 StringBuffer buffer = new StringBuffer();
 419  18995 for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) {
 420  37327 Node node = exampleNode.getChildNodes().item(i);
 421  37327 if (node.getNodeType() == Node.CDATA_SECTION_NODE
 422    || node.getNodeType() == Node.TEXT_NODE) {
 423  37315 buffer.append(node.getNodeValue());
 424    }
 425    }
 426  18995 return buffer.toString();
 427    }
 428   
 429    /**
 430    * Parse a properties node
 431    *
 432    * @param propertiesNode must be a properties element node
 433    */
 434  5635 private static void parsePropertiesNode(Properties p, Node propertiesNode) {
 435  5635 for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) {
 436  16843 Node node = propertiesNode.getChildNodes().item(i);
 437  16843 if (node.getNodeType() == Node.ELEMENT_NODE
 438    && node.getNodeName().equals("property")) {
 439  5695 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  5695 private static void parsePropertyNode(Properties p, Node propertyNode) {
 450  5695 Element propertyElement = (Element) propertyNode;
 451  5695 String name = propertyElement.getAttribute("name");
 452  5695 String value = propertyElement.getAttribute("value");
 453    // TODO String desc = propertyElement.getAttribute("description");
 454  5695 if (value.trim().length() == 0) {
 455  5303 for (int i = 0; i < propertyNode.getChildNodes().getLength(); i++) {
 456  15869 Node node = propertyNode.getChildNodes().item(i);
 457  15869 if ((node.getNodeType() == Node.ELEMENT_NODE)
 458    && node.getNodeName().equals("value")) {
 459  5225 value = parseTextNode(node);
 460    }
 461    }
 462    }
 463  5695 if (propertyElement.hasAttribute("pluginname")) {
 464  191 p.setProperty("pluginname", propertyElement.getAttributeNode("pluginname")
 465    .getNodeValue());
 466    }
 467  5695 p.setProperty(name, value);
 468    }
 469    }