Clover coverage report - PMD - 3.3
Coverage timestamp: Thu Sep 15 2005 17:59:57 EDT
file stats: LOC: 370   Methods: 16
NCLOC: 246   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
RuleSetFactory.java 85% 81.5% 93.8% 83.5%
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   
 12    import javax.xml.parsers.DocumentBuilder;
 13    import javax.xml.parsers.DocumentBuilderFactory;
 14    import javax.xml.parsers.ParserConfigurationException;
 15    import java.io.IOException;
 16    import java.io.InputStream;
 17    import java.util.ArrayList;
 18    import java.util.HashSet;
 19    import java.util.Iterator;
 20    import java.util.List;
 21    import java.util.Properties;
 22    import java.util.Set;
 23    import java.util.StringTokenizer;
 24   
 25    // Note that ruleset parsing may fail on JDK 1.6 beta
 26    // due to this bug - http://www.netbeans.org/issues/show_bug.cgi?id=63257
 27    public class RuleSetFactory {
 28   
 29    private static class OverrideParser {
 30    private Element ruleElement;
 31  14 public OverrideParser(Element ruleElement) {
 32  14 this.ruleElement = ruleElement;
 33    }
 34  14 public void overrideAsNecessary(Rule rule) {
 35  14 if (ruleElement.hasAttribute("name")) {
 36  1 rule.setName(ruleElement.getAttribute("name"));
 37    }
 38  14 if (ruleElement.hasAttribute("message")) {
 39  4 rule.setMessage(ruleElement.getAttribute("message"));
 40    }
 41  14 if (ruleElement.hasAttribute("externalInfoUrl")) {
 42  0 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
 43    }
 44  14 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 45  16 Node node = ruleElement.getChildNodes().item(i);
 46  16 if (node.getNodeType() == Node.ELEMENT_NODE) {
 47  6 if (node.getNodeName().equals("description")) {
 48  1 rule.setDescription(parseTextNode(node));
 49  5 } else if (node.getNodeName().equals("example")) {
 50  1 rule.setExample(parseTextNode(node));
 51  4 } else if (node.getNodeName().equals("priority")) {
 52  2 rule.setPriority(Integer.parseInt(parseTextNode(node)));
 53  2 } else if (node.getNodeName().equals("properties")) {
 54  2 Properties p = new Properties();
 55  2 parsePropertiesNode(p, node);
 56  2 rule.addProperties(p);
 57    }
 58    }
 59    }
 60    }
 61    }
 62   
 63   
 64    private ClassLoader classLoader;
 65   
 66    /**
 67    * Returns an Iterator of RuleSet objects loaded from descriptions from
 68    * the "rulesets.properties" resource.
 69    *
 70    * @return an iterator of RuleSet objects
 71    */
 72  0 public Iterator getRegisteredRuleSets() throws RuleSetNotFoundException {
 73  0 try {
 74  0 Properties props = new Properties();
 75  0 props.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties"));
 76  0 String rulesetFilenames = props.getProperty("rulesets.filenames");
 77  0 List ruleSets = new ArrayList();
 78  0 for (StringTokenizer st = new StringTokenizer(rulesetFilenames, ","); st.hasMoreTokens();) {
 79  0 ruleSets.add(createRuleSet(st.nextToken()));
 80    }
 81  0 return ruleSets.iterator();
 82    } catch (IOException ioe) {
 83  0 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"));
 84    }
 85    }
 86   
 87    /**
 88    * Create a ruleset from a name or from a list of names
 89    *
 90    * @param name name of rule set file loaded as a resource
 91    * @param classLoader the classloader used to load the ruleset and subsequent rules
 92    * @return the new ruleset
 93    * @throws RuleSetNotFoundException
 94    */
 95  164 public RuleSet createRuleSet(String name, ClassLoader classLoader) throws RuleSetNotFoundException {
 96  164 this.classLoader = classLoader;
 97  164 if (name.indexOf(',') == -1) {
 98  164 return createRuleSet(tryToGetStreamTo(name, classLoader));
 99    }
 100  0 RuleSet ruleSet = new RuleSet();
 101  0 for (StringTokenizer st = new StringTokenizer(name, ","); st.hasMoreTokens();) {
 102  0 ruleSet.addRuleSet(createRuleSet(st.nextToken().trim(), classLoader));
 103    }
 104  0 return ruleSet;
 105    }
 106   
 107    /**
 108    * Creates a ruleset. If passed a comma-delimited string (rulesets/basic.xml,rulesets/unusedcode.xml)
 109    * it will parse that string and create a new ruleset for each item in the list.
 110    * Same as createRuleSet(name, ruleSetFactory.getClassLoader()).
 111    */
 112  164 public RuleSet createRuleSet(String name) throws RuleSetNotFoundException {
 113  164 return createRuleSet(name, getClass().getClassLoader());
 114    }
 115   
 116    /**
 117    * Create a ruleset from an inputsteam.
 118    * Same as createRuleSet(inputStream, ruleSetFactory.getClassLoader()).
 119    *
 120    * @param inputStream an input stream that contains a ruleset descripion
 121    * @return a new ruleset
 122    */
 123  193 public RuleSet createRuleSet(InputStream inputStream) {
 124  193 return createRuleSet(inputStream, getClass().getClassLoader());
 125    }
 126   
 127    /**
 128    * Create a ruleset from an input stream with a specified class loader
 129    *
 130    * @param inputStream an input stream that contains a ruleset descripion
 131    * @param classLoader a class loader used to load rule classes
 132    * @return a new ruleset
 133    */
 134  193 public RuleSet createRuleSet(InputStream inputStream, ClassLoader classLoader) {
 135  193 try {
 136  193 this.classLoader = classLoader;
 137  193 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 138  193 Document doc = builder.parse(inputStream);
 139  193 Element root = doc.getDocumentElement();
 140   
 141  193 RuleSet ruleSet = new RuleSet();
 142  193 ruleSet.setName(root.getAttribute("name"));
 143   
 144  193 NodeList nodeList = root.getChildNodes();
 145  193 for (int i = 0; i < nodeList.getLength(); i++) {
 146  5852 Node node = nodeList.item(i);
 147  5852 if (node.getNodeType() == Node.ELEMENT_NODE) {
 148  2820 if (node.getNodeName().equals("description")) {
 149  193 ruleSet.setDescription(parseTextNode(node));
 150  2627 } else if (node.getNodeName().equals("rule")) {
 151  2624 parseRuleNode(ruleSet, node);
 152    }
 153    }
 154    }
 155   
 156  192 return ruleSet;
 157    } catch (IllegalArgumentException illae) {
 158  1 throw illae; // this is hideous, but see not in catch Exception block...
 159    } catch (ClassNotFoundException cnfe) {
 160  0 cnfe.printStackTrace();
 161  0 throw new RuntimeException("Couldn't find that class " + cnfe.getMessage());
 162    } catch (InstantiationException ie) {
 163  0 ie.printStackTrace();
 164  0 throw new RuntimeException("Couldn't find that class " + ie.getMessage());
 165    } catch (IllegalAccessException iae) {
 166  0 iae.printStackTrace();
 167  0 throw new RuntimeException("Couldn't find that class " + iae.getMessage());
 168    } catch (ParserConfigurationException pce) {
 169  0 pce.printStackTrace();
 170  0 throw new RuntimeException("Couldn't find that class " + pce.getMessage());
 171    } catch (Exception e) {
 172    /*
 173    I hate to catch Exception, but I need to catch SaxException, and
 174    I can't figure out where it's declared. It's not in our pmd/lib jar files;
 175    it must be buried in the JDK somewhere. If anyone knows how to fix this, pls
 176    let me know.... thanks!
 177    */
 178  0 e.printStackTrace();
 179  0 throw new RuntimeException("Couldn't find that class " + e.getMessage());
 180    }
 181    }
 182   
 183    /**
 184    * Try to load a resource with the specified class loader
 185    *
 186    * @param name a resource name (contains a ruleset description)
 187    * @param loader a class loader used to load that rule set description
 188    * @return an inputstream to that resource
 189    * @throws RuleSetNotFoundException
 190    */
 191  164 private InputStream tryToGetStreamTo(String name, ClassLoader loader) throws RuleSetNotFoundException {
 192  164 InputStream in = ResourceLoader.loadResourceAsStream(name, loader);
 193  164 if (in == null) {
 194  1 throw new RuleSetNotFoundException("Can't find resource " + name + ". Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: " + System.getProperty("java.class.path"));
 195    }
 196  163 return in;
 197    }
 198   
 199    /**
 200    * Parse a rule node
 201    *
 202    * @param ruleSet the ruleset being constructed
 203    * @param ruleNode must be a rule element node
 204    */
 205  2624 private void parseRuleNode(RuleSet ruleSet, Node ruleNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException, RuleSetNotFoundException {
 206  2624 Element ruleElement = (Element) ruleNode;
 207  2624 String ref = ruleElement.getAttribute("ref");
 208  2624 if (ref.trim().length() == 0) {
 209  2607 parseInternallyDefinedRuleNode(ruleSet, ruleNode);
 210    } else {
 211  17 parseExternallyDefinedRuleNode(ruleSet, ruleNode);
 212    }
 213    }
 214   
 215    /**
 216    * Process a rule definition node
 217    *
 218    * @param ruleSet the ruleset being constructed
 219    * @param ruleNode must be a rule element node
 220    */
 221  2607 private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
 222  2607 Element ruleElement = (Element) ruleNode;
 223   
 224  2607 String attribute = ruleElement.getAttribute("class");
 225  2607 Rule rule = (Rule)classLoader.loadClass(attribute).newInstance();
 226   
 227  2607 rule.setName(ruleElement.getAttribute("name"));
 228  2607 rule.setMessage(ruleElement.getAttribute("message"));
 229  2607 rule.setRuleSetName(ruleSet.getName());
 230  2607 rule.setExternalInfoUrl(ruleElement.getAttribute("externalInfoUrl"));
 231   
 232  2607 if (ruleElement.hasAttribute("dfa") && ruleElement.getAttribute("dfa").equals("true")) {
 233  1 rule.setUsesDFA();
 234    }
 235   
 236  2607 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) {
 237  21686 Node node = ruleElement.getChildNodes().item(i);
 238  21686 if (node.getNodeType() == Node.ELEMENT_NODE) {
 239  9541 if (node.getNodeName().equals("description")) {
 240  2602 rule.setDescription(parseTextNode(node));
 241  6939 } else if (node.getNodeName().equals("example")) {
 242  2623 rule.setExample(parseTextNode(node));
 243  4316 } else if (node.getNodeName().equals("priority")) {
 244  2598 rule.setPriority(new Integer(parseTextNode(node).trim()).intValue());
 245  1718 } else if (node.getNodeName().equals("properties")) {
 246  1718 Properties p = new Properties();
 247  1718 parsePropertiesNode(p, node);
 248  1718 for (Iterator j = p.keySet().iterator(); j.hasNext();) {
 249  1792 String key = (String)j.next();
 250  1792 rule.addProperty(key, p.getProperty(key));
 251    }
 252    }
 253    }
 254    }
 255  2607 ruleSet.addRule(rule);
 256    }
 257   
 258    /**
 259    * Process a reference to a rule
 260    *
 261    * @param ruleSet the ruleset being constructucted
 262    * @param ruleNode must be a rule element node
 263    */
 264  17 private void parseExternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode) throws RuleSetNotFoundException, ClassNotFoundException, InstantiationException, IllegalAccessException {
 265  17 Element ruleElement = (Element) ruleNode;
 266  17 String ref = ruleElement.getAttribute("ref");
 267  17 if (ref.endsWith("xml")) {
 268  2 parseRuleNodeWithExclude(ruleSet, ruleElement, ref);
 269    } else {
 270  15 parseRuleNodeWithSimpleReference(ruleSet, ruleNode, ref);
 271    }
 272    }
 273   
 274    /**
 275    * Parse a rule node with a simple reference
 276    *
 277    * @param ruleSet the ruleset being constructed
 278    * @param ref a reference to a rule
 279    */
 280  15 private void parseRuleNodeWithSimpleReference(RuleSet ruleSet, Node ruleNode, String ref) throws RuleSetNotFoundException {
 281  15 RuleSetFactory rsf = new RuleSetFactory();
 282   
 283  15 ExternalRuleID externalRuleID = new ExternalRuleID(ref);
 284  15 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader.loadResourceAsStream(externalRuleID.getFilename()));
 285  15 Rule externalRule = externalRuleSet.getRuleByName(externalRuleID.getRuleName());
 286  15 if (externalRule == null) {
 287  1 throw new IllegalArgumentException("Unable to find rule " + externalRuleID.getRuleName() + "; perhaps the rule name is mispelled?");
 288    }
 289   
 290  14 OverrideParser p = new OverrideParser((Element)ruleNode);
 291  14 p.overrideAsNecessary(externalRule);
 292   
 293  14 ruleSet.addRule(externalRule);
 294    }
 295   
 296    /**
 297    * Parse a reference rule node with excludes
 298    *
 299    * @param ruleSet the ruleset being constructed
 300    * @param ruleElement must be a rule element
 301    * @param ref the ruleset reference
 302    */
 303  2 private void parseRuleNodeWithExclude(RuleSet ruleSet, Element ruleElement, String ref) throws RuleSetNotFoundException {
 304  2 NodeList excludeNodes = ruleElement.getChildNodes();
 305  2 Set excludes = new HashSet();
 306  2 for (int i = 0; i < excludeNodes.getLength(); i++) {
 307  0 if ((excludeNodes.item(i).getNodeType() == Node.ELEMENT_NODE) && (excludeNodes.item(i).getNodeName().equals("exclude"))) {
 308  0 Element excludeElement = (Element) excludeNodes.item(i);
 309  0 excludes.add(excludeElement.getAttribute("name"));
 310    }
 311    }
 312   
 313  2 RuleSetFactory rsf = new RuleSetFactory();
 314  2 RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader.loadResourceAsStream(ref));
 315  2 for (Iterator i = externalRuleSet.getRules().iterator(); i.hasNext();) {
 316  25 Rule rule = (Rule) i.next();
 317  25 if (!excludes.contains(rule.getName())) {
 318  25 ruleSet.addRule(rule);
 319    }
 320    }
 321    }
 322   
 323  9581 private static String parseTextNode(Node exampleNode) {
 324  9581 StringBuffer buffer = new StringBuffer();
 325  9581 for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) {
 326  17813 Node node = exampleNode.getChildNodes().item(i);
 327  17813 if (node.getNodeType() == Node.CDATA_SECTION_NODE || node.getNodeType() == Node.TEXT_NODE) {
 328  17807 buffer.append(node.getNodeValue());
 329    }
 330    }
 331  9581 return buffer.toString();
 332    }
 333    /**
 334    * Parse a properties node
 335    *
 336    * @param propertiesNode must be a properties element node
 337    */
 338  1720 private static void parsePropertiesNode(Properties p, Node propertiesNode) {
 339  1720 for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) {
 340  5174 Node node = propertiesNode.getChildNodes().item(i);
 341  5174 if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("property")) {
 342  1727 parsePropertyNode(p, node);
 343    }
 344    }
 345    }
 346   
 347    /**
 348    * Parse a property node
 349    *
 350    * @param propertyNode must be a property element node
 351    */
 352  1727 private static void parsePropertyNode(Properties p, Node propertyNode) {
 353  1727 Element propertyElement = (Element) propertyNode;
 354  1727 String name = propertyElement.getAttribute("name");
 355  1727 String value = propertyElement.getAttribute("value");
 356    // TODO String desc = propertyElement.getAttribute("description");
 357  1727 if (value.trim().length() == 0) {
 358  1561 for (int i = 0; i < propertyNode.getChildNodes().getLength(); i++) {
 359  4681 Node node = propertyNode.getChildNodes().item(i);
 360  4681 if ((node.getNodeType() == Node.ELEMENT_NODE) && node.getNodeName().equals("value")) {
 361  1561 value = parseTextNode(node);
 362    }
 363    }
 364    }
 365  1727 if (propertyElement.hasAttribute("pluginname")) {
 366  69 p.setProperty("pluginname", propertyElement.getAttributeNode("pluginname").getNodeValue());
 367    }
 368  1727 p.setProperty(name, value);
 369    }
 370    }