Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT
file stats: LOC: 472   Methods: 21
NCLOC: 305   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
RuleSetFactory.java 88.1% 83.1% 95.2% 85.7%
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.ArrayList;
 19    import java.util.HashSet;
 20    import java.util.Iterator;
 21    import java.util.List;
 22    import java.util.Properties;
 23    import java.util.Set;
 24    import java.util.StringTokenizer;
 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 ClassLoader classLoader;
 68    private int minPriority = Rule.LOWEST_PRIORITY;
 69   
 70  2 public void setMinimumPriority(int minPriority) {
 71  2 this.minPriority = minPriority;
 72    }
 73   
 74    /**
 75    * Returns an Iterator of RuleSet objects loaded from descriptions from the
 76    * "rulesets.properties" resource.
 77    *
 78    * @return an iterator of RuleSet objects
 79    */
 80  0 public Iterator getRegisteredRuleSets() throws RuleSetNotFoundException {
 81  0 try {
 82  0 Properties props = new Properties();
 83  0 props.load(ResourceLoader
 84    .loadResourceAsStream("rulesets/rulesets.properties"));
 85  0 String rulesetFilenames = props.getProperty("rulesets.filenames");
 86  0 List ruleSets = new ArrayList();
 87  0 for (StringTokenizer st = new StringTokenizer(rulesetFilenames, ","); st
 88    .hasMoreTokens();) {
 89  0 ruleSets.add(createRuleSet(st.nextToken()));
 90    }
 91  0 return ruleSets.iterator();
 92    } catch (IOException ioe) {
 93  0 throw new RuntimeException("Couldn't find rulesets.properties; please ensure that the rulesets directory is on the classpath. Here's the current classpath: "
 94    + System.getProperty("java.class.path"));
 95    }
 96    }
 97   
 98    /**
 99    * Create a RuleSets from a list of names.
 100    *
 101    * @param ruleSetFileNames comma-separated list of rule set files.
 102    * @param class a RuleSets object
 103    * @throws RuleSetNotFoundException
 104    */
 105  215 public RuleSets createRuleSets(String ruleSetFileNames, ClassLoader classLoader)
 106    throws RuleSetNotFoundException {
 107  215 RuleSets ruleSets = new RuleSets();
 108   
 109  215 for (StringTokenizer st = new StringTokenizer(ruleSetFileNames, ","); st
 110    .hasMoreTokens();) {
 111  215 RuleSet ruleSet = createSingleRuleSet(st.nextToken().trim(), classLoader);
 112  214 ruleSets.addRuleSet(ruleSet);
 113    }
 114   
 115  214 return ruleSets;
 116    }
 117   
 118    /**
 119    * Create a RuleSets from a list of names, using the classloader of this class.
 120    *
 121    * @param ruleSetFileNames comma-separated list of rule set files.
 122    * @throws RuleSetNotFoundException
 123    */
 124  213 public RuleSets createRuleSets(String ruleSetFileNames)
 125    throws RuleSetNotFoundException {
 126  213 return createRuleSets(ruleSetFileNames, getClass().getClassLoader());
 127    }
 128   
 129    /**
 130    * Create a ruleset from a name or from a list of names
 131    *
 132    * @param name name of rule set file loaded as a resource
 133    * @param classLoader the classloader used to load the ruleset and subsequent rules
 134    * @return the new ruleset
 135    * @throws RuleSetNotFoundException
 136    * @deprecated Use createRuleSets instead, because this method puts all rules in one
 137    * single RuleSet object, and thus removes name and language of the
 138    * originating rule set files.
 139    */
 140  2 public RuleSet createRuleSet(String name, ClassLoader classLoader)
 141    throws RuleSetNotFoundException {
 142  2 RuleSets ruleSets = createRuleSets(name, classLoader);
 143   
 144  1 RuleSet result = new RuleSet();
 145  1 RuleSet[] allRuleSets = ruleSets.getAllRuleSets();
 146  1 for (int i = 0; i < allRuleSets.length; i++) {
 147  1 result.addRuleSet(allRuleSets[i]);
 148    }
 149   
 150  1 return result;
 151    }
 152   
 153    /**
 154    * Creates a ruleset. If passed a comma-delimited string
 155    * (rulesets/basic.xml,rulesets/unusedcode.xml) it will parse that string and create a
 156    * new ruleset for each item in the list. Same as createRuleSet(name,
 157    * ruleSetFactory.getClassLoader()).
 158    *
 159    * @param name name of rule set file loaded as a resource
 160    * @deprecated Use createRuleSets instead, because this method puts all rules in one
 161    * single RuleSet object, and thus removes name and language of the
 162    * originating rule set files.
 163    */
 164  2 public RuleSet createRuleSet(String name) throws RuleSetNotFoundException {
 165  2 return createRuleSet(name, getClass().getClassLoader());
 166    }
 167   
 168    /**
 169    * Create a ruleset from a name
 170    *
 171    * @param name name of rule set file loaded as a resource
 172    * @param classLoader the classloader used to load the ruleset and subsequent rules
 173    * @return the new ruleset
 174    * @throws RuleSetNotFoundException
 175    */
 176  215 public RuleSet createSingleRuleSet(String ruleSetFileName, ClassLoader classLoader)
 177    throws RuleSetNotFoundException {
 178  215 return createRuleSet(tryToGetStreamTo(ruleSetFileName, classLoader), classLoader);
 179    }
 180   
 181    /**
 182    * Create a ruleset from a name
 183    *
 184    * @param name name of rule set file loaded as a resource
 185    * @return the new ruleset
 186    * @throws RuleSetNotFoundException
 187    */
 188  5 public RuleSet createSingleRuleSet(String ruleSetFileName)
 189    throws RuleSetNotFoundException {
 190  5 return createRuleSet(tryToGetStreamTo(ruleSetFileName, getClass()
 191    .getClassLoader()));
 192    }
 193   
 194    /**
 195    * Create a ruleset from an inputsteam. Same as createRuleSet(inputStream,
 196    * ruleSetFactory.getClassLoader()).
 197    *
 198    * @param inputStream an input stream that contains a ruleset descripion
 199    * @return a new ruleset
 200    */
 201  37 public RuleSet createRuleSet(InputStream inputStream) {
 202  37 return createRuleSet(inputStream, getClass().getClassLoader());
 203    }
 204   
 205    /**
 206    * Create a ruleset from an input stream with a specified class loader
 207    *
 208    * @param inputStream an input stream that contains a ruleset descripion
 209    * @param classLoader a class loader used to load rule classes
 210    * @return a new ruleset
 211    */
 212  251 public RuleSet createRuleSet(InputStream inputStream, ClassLoader classLoader) {
 213  251 try {
 214  251 this.classLoader = classLoader;
 215  251 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 216  251 Document doc = builder.parse(inputStream);
 217  251 Element root = doc.getDocumentElement();
 218   
 219  251 RuleSet ruleSet = new RuleSet();
 220  251 ruleSet.setName(root.getAttribute("name"));
 221  251 ruleSet.setLanguage(Language.getByName(root.getAttribute("language")));
 222   
 223  251 NodeList nodeList = root.getChildNodes();
 224  251 for (int i = 0; i < nodeList.getLength(); i++) {
 225  9046 Node node = nodeList.item(i);
 226  9046 if (node.getNodeType() == Node.ELEMENT_NODE) {
 227  4387 if (node.getNodeName().equals("description")) {
 228  250 ruleSet.setDescription(parseTextNode(node));
 229  4137 } else if (node.getNodeName().equals("rule")) {
 230  4134 parseRuleNode(ruleSet, node);
 231    }
 232    }
 233    }
 234   
 235  250 return ruleSet;
 236    } catch (ClassNotFoundException cnfe) {
 237  0 cnfe.printStackTrace();
 238  0 throw new RuntimeException("Couldn't find that class " + cnfe.getMessage());
 239    } catch (InstantiationException ie) {
 240  0 ie.printStackTrace();
 241  0 throw new RuntimeException("Couldn't find that class " + ie.getMessage());
 242    } catch (IllegalAccessException iae) {
 243  0 iae.printStackTrace();
 244  0 throw new RuntimeException("Couldn't find that class " + iae.getMessage());
 245    } catch (ParserConfigurationException pce) {
 246  0 pce.printStackTrace();
 247  0 throw new RuntimeException("Couldn't find that class " + pce.getMessage());
 248    } catch (RuleSetNotFoundException rsnfe) {
 249  0 rsnfe.printStackTrace();
 250  0 throw new RuntimeException("Couldn't find that class " + rsnfe.getMessage());
 251    } catch (IOException ioe) {
 252  0 ioe.printStackTrace();
 253  0 throw new RuntimeException("Couldn't find that class " + ioe.getMessage());
 254    } catch (SAXException se) {
 255  0 se.printStackTrace();
 256  0 throw new RuntimeException("Couldn't find that class " + se.getMessage());
 257    }
 258    }
 259   
 260    /**
 261    * Try to load a resource with the specified class loader
 262    *
 263    * @param name a resource name (contains a ruleset description)
 264    * @param loader a class loader used to load that rule set description
 265    * @return an inputstream to that resource
 266    * @throws RuleSetNotFoundException
 267    */
 268  220 private InputStream tryToGetStreamTo(String name, ClassLoader loader)
 269    throws RuleSetNotFoundException {
 270  220 InputStream in = ResourceLoader.loadResourceAsStream(name, loader);
 271  220 if (in == null) {
 272  1 throw new RuleSetNotFoundException("Can't find resource "
 273    + name
 274    + ". Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
 275    + System.getProperty("java.class.path"));
 276    }
 277  219 return in;
 278    }
 279   
 280    /**
 281    * Parse a rule node
 282    *
 283    * @param ruleSet the ruleset being constructed
 284    * @param ruleNode must be a rule element node
 285    */
 286  4134 private void parseRuleNode(RuleSet ruleSet, Node ruleNode)
 287    throws ClassNotFoundException, InstantiationException,
 288    IllegalAccessException, RuleSetNotFoundException {
 289  4134 Element ruleElement = (Element) ruleNode;
 290  4134 String ref = ruleElement.getAttribute("ref");
 291  4134 if (ref.trim().length() == 0) {
 292  4117 parseInternallyDefinedRuleNode(ruleSet, ruleNode);
 293    } else {
 294  17 parseExternallyDefinedRuleNode(ruleSet, ruleNode);
 295    }
 296    }
 297   
 298    /**
 299    * Process a rule definition node
 300    *
 301    * @param ruleSet the ruleset being constructed
 302    * @param ruleNode must be a rule element node
 303    */
 304  4117 private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode)
 305    throws ClassNotFoundException, InstantiationException, IllegalAccessException {
 306  4117 Element ruleElement = (Element) ruleNode;
 307   
 308  4117 String attribute = ruleElement.getAttribute("class");
 309  4117 Rule rule = (Rule) classLoader.loadClass(attribute).newInstance();
 310   
 311  4117 rule.setName(ruleElement.getAttribute("name"));
 312  4117 rule.setMessage(ruleElement.getAttribute("message"));
 313  4117 rule.setRuleSetName(ruleSet.getName());
 314  4117 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
 315   
 316  4117 if (ruleElement.hasAttribute("dfa")
 317    && ruleElement.getAttribute("dfa").equals("true")) {
 318  1 rule.setUsesDFA();
 319    }
 320   
 321  4117 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 322  34816 Node node = ruleElement.getChildNodes().item(i);
 323  34816 if (node.getNodeType() == Node.ELEMENT_NODE) {
 324  15352 if (node.getNodeName().equals("description")) {
 325  4110 rule.setDescription(parseTextNode(node));
 326  11242 } else if (node.getNodeName().equals("example")) {
 327  4126 rule.setExample(parseTextNode(node));
 328  7116 } else if (node.getNodeName().equals("priority")) {
 329  4111 rule.setPriority(new Integer(parseTextNode(node).trim()).intValue());
 330  3005 } else if (node.getNodeName().equals("properties")) {
 331  3005 Properties p = new Properties();
 332  3005 parsePropertiesNode(p, node);
 333  3005 for (Iterator j = p.keySet().iterator(); j.hasNext();) {
 334  3263 String key = (String) j.next();
 335  3263 rule.addProperty(key, p.getProperty(key));
 336    }
 337    }
 338    }
 339    }
 340  4117 if (rule.getPriority() <= minPriority) {
 341  4116 ruleSet.addRule(rule);
 342    }
 343    }
 344   
 345    /**
 346    * Process a reference to a rule
 347    *
 348    * @param ruleSet the ruleset being constructucted
 349    * @param ruleNode must be a rule element node
 350    */
 351  17 private void parseExternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode)
 352    throws RuleSetNotFoundException {
 353  17 Element ruleElement = (Element) ruleNode;
 354  17 String ref = ruleElement.getAttribute("ref");
 355  17 if (ref.endsWith("xml")) {
 356  2 parseRuleNodeWithExclude(ruleSet, ruleElement, ref);
 357    } else {
 358  15 parseRuleNodeWithSimpleReference(ruleSet, ruleNode, ref);
 359    }
 360    }
 361   
 362    /**
 363    * Parse a rule node with a simple reference
 364    *
 365    * @param ruleSet the ruleset being constructed
 366    * @param ref a reference to a rule
 367    */
 368  15 private void parseRuleNodeWithSimpleReference(RuleSet ruleSet, Node ruleNode,
 369    String ref) throws RuleSetNotFoundException {
 370  15 RuleSetFactory rsf = new RuleSetFactory();
 371   
 372  15 ExternalRuleID externalRuleID = new ExternalRuleID(ref);
 373  15 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
 374    .loadResourceAsStream(externalRuleID.getFilename()));
 375  15 Rule externalRule = externalRuleSet.getRuleByName(externalRuleID.getRuleName());
 376  15 if (externalRule == null) {
 377  1 throw new IllegalArgumentException("Unable to find rule "
 378    + externalRuleID.getRuleName()
 379    + "; perhaps the rule name is mispelled?");
 380    }
 381   
 382  14 OverrideParser p = new OverrideParser((Element) ruleNode);
 383  14 p.overrideAsNecessary(externalRule);
 384   
 385  14 if (externalRule.getPriority() <= minPriority) {
 386  14 ruleSet.addRule(externalRule);
 387    }
 388    }
 389   
 390    /**
 391    * Parse a reference rule node with excludes
 392    *
 393    * @param ruleSet the ruleset being constructed
 394    * @param ruleElement must be a rule element
 395    * @param ref the ruleset reference
 396    */
 397  2 private void parseRuleNodeWithExclude(RuleSet ruleSet, Element ruleElement, String ref)
 398    throws RuleSetNotFoundException {
 399  2 NodeList excludeNodes = ruleElement.getChildNodes();
 400  2 Set excludes = new HashSet();
 401  2 for (int i = 0; i < excludeNodes.getLength(); i++) {
 402  0 if ((excludeNodes.item(i).getNodeType() == Node.ELEMENT_NODE)
 403    && (excludeNodes.item(i).getNodeName().equals("exclude"))) {
 404  0 Element excludeElement = (Element) excludeNodes.item(i);
 405  0 excludes.add(excludeElement.getAttribute("name"));
 406    }
 407    }
 408   
 409  2 RuleSetFactory rsf = new RuleSetFactory();
 410  2 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
 411    .loadResourceAsStream(ref));
 412  2 for (Iterator i = externalRuleSet.getRules().iterator(); i.hasNext();) {
 413  31 Rule rule = (Rule) i.next();
 414  31 if (!excludes.contains(rule.getName()) && rule.getPriority() <= minPriority) {
 415  31 ruleSet.addRule(rule);
 416    }
 417    }
 418    }
 419   
 420  15398 private static String parseTextNode(Node exampleNode) {
 421  15398 StringBuffer buffer = new StringBuffer();
 422  15398 for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) {
 423  28434 Node node = exampleNode.getChildNodes().item(i);
 424  28434 if (node.getNodeType() == Node.CDATA_SECTION_NODE
 425    || node.getNodeType() == Node.TEXT_NODE) {
 426  28428 buffer.append(node.getNodeValue());
 427    }
 428    }
 429  15398 return buffer.toString();
 430    }
 431   
 432    /**
 433    * Parse a properties node
 434    *
 435    * @param propertiesNode must be a properties element node
 436    */
 437  3007 private static void parsePropertiesNode(Properties p, Node propertiesNode) {
 438  3007 for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) {
 439  9241 Node node = propertiesNode.getChildNodes().item(i);
 440  9241 if (node.getNodeType() == Node.ELEMENT_NODE
 441    && node.getNodeName().equals("property")) {
 442  3161 parsePropertyNode(p, node);
 443    }
 444    }
 445    }
 446   
 447    /**
 448    * Parse a property node
 449    *
 450    * @param propertyNode must be a property element node
 451    */
 452  3161 private static void parsePropertyNode(Properties p, Node propertyNode) {
 453  3161 Element propertyElement = (Element) propertyNode;
 454  3161 String name = propertyElement.getAttribute("name");
 455  3161 String value = propertyElement.getAttribute("value");
 456    // TODO String desc = propertyElement.getAttribute("description");
 457  3161 if (value.trim().length() == 0) {
 458  2885 for (int i = 0; i < propertyNode.getChildNodes().getLength(); i++) {
 459  8565 Node node = propertyNode.getChildNodes().item(i);
 460  8565 if ((node.getNodeType() == Node.ELEMENT_NODE)
 461    && node.getNodeName().equals("value")) {
 462  2797 value = parseTextNode(node);
 463    }
 464    }
 465    }
 466  3161 if (propertyElement.hasAttribute("pluginname")) {
 467  106 p.setProperty("pluginname", propertyElement.getAttributeNode("pluginname")
 468    .getNodeValue());
 469    }
 470  3161 p.setProperty(name, value);
 471    }
 472    }