1 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 29 public class RuleSetFactory { 30 31 private static class OverrideParser { 32 private Element ruleElement; 33 34 public OverrideParser(Element 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 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 p = new Properties (); 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 79 public Iterator getRegisteredRuleSets() throws RuleSetNotFoundException { 80 try { 81 Properties props = new Properties (); 82 props.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties")); 83 String rulesetFilenames = props.getProperty("rulesets.filenames"); 84 return createRuleSets(rulesetFilenames).getRuleSetsIterator(); 85 } catch (IOException ioe) { 86 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 98 public RuleSets createRuleSets(String ruleSetFileNames, ClassLoader classLoader) 99 throws RuleSetNotFoundException { 100 RuleSets ruleSets = new RuleSets(); 101 102 for (StringTokenizer st = new StringTokenizer (ruleSetFileNames, ","); st 103 .hasMoreTokens();) { 104 RuleSet ruleSet = createSingleRuleSet(st.nextToken().trim(), classLoader); 105 ruleSets.addRuleSet(ruleSet); 106 } 107 108 return ruleSets; 109 } 110 111 117 public RuleSets createRuleSets(String ruleSetFileNames) 118 throws RuleSetNotFoundException { 119 return createRuleSets(ruleSetFileNames, getClass().getClassLoader()); 120 } 121 122 133 public RuleSet createRuleSet(String name, ClassLoader 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 151 private RuleSet createSingleRuleSet(String ruleSetFileName, ClassLoader classLoader) 152 throws RuleSetNotFoundException { 153 return createRuleSet(tryToGetStreamTo(ruleSetFileName, classLoader), classLoader); 154 } 155 156 163 public RuleSet createSingleRuleSet(String ruleSetFileName) 164 throws RuleSetNotFoundException { 165 return createRuleSet(tryToGetStreamTo(ruleSetFileName, getClass() 166 .getClassLoader())); 167 } 168 169 176 public RuleSet createRuleSet(InputStream inputStream) { 177 return createRuleSet(inputStream, getClass().getClassLoader()); 178 } 179 180 187 private RuleSet createRuleSet(InputStream inputStream, ClassLoader classLoader) { 188 try { 189 DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 190 Document doc = builder.parse(inputStream); 191 Element 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 nodeList = root.getChildNodes(); 198 for (int i = 0; i < nodeList.getLength(); i++) { 199 Node 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 cnfe) { 211 cnfe.printStackTrace(); 212 throw new RuntimeException ("Couldn't find that class " + cnfe.getMessage()); 213 } catch (InstantiationException ie) { 214 ie.printStackTrace(); 215 throw new RuntimeException ("Couldn't find that class " + ie.getMessage()); 216 } catch (IllegalAccessException iae) { 217 iae.printStackTrace(); 218 throw new RuntimeException ("Couldn't find that class " + iae.getMessage()); 219 } catch (ParserConfigurationException pce) { 220 pce.printStackTrace(); 221 throw new RuntimeException ("Couldn't find that class " + pce.getMessage()); 222 } catch (RuleSetNotFoundException rsnfe) { 223 rsnfe.printStackTrace(); 224 throw new RuntimeException ("Couldn't find that class " + rsnfe.getMessage()); 225 } catch (IOException ioe) { 226 ioe.printStackTrace(); 227 throw new RuntimeException ("Couldn't find that class " + ioe.getMessage()); 228 } catch (SAXException se) { 229 se.printStackTrace(); 230 throw new RuntimeException ("Couldn't find that class " + se.getMessage()); 231 } 232 } 233 234 242 private InputStream tryToGetStreamTo(String name, ClassLoader loader) 243 throws RuleSetNotFoundException { 244 InputStream 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 260 private void parseRuleNode(RuleSet ruleSet, Node ruleNode, ClassLoader classLoader) 261 throws ClassNotFoundException , InstantiationException , 262 IllegalAccessException , RuleSetNotFoundException { 263 Element ruleElement = (Element ) ruleNode; 264 String 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 278 private void parseInternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode, ClassLoader classLoader) 279 throws ClassNotFoundException , InstantiationException , IllegalAccessException { 280 Element ruleElement = (Element ) ruleNode; 281 282 String attribute = ruleElement.getAttribute("class"); 283 Class c; 284 if ((Language.JAVA.equals(ruleSet.getLanguage()) || ruleSet.getLanguage() == null) && 285 attribute.equals("net.sourceforge.pmd.rules.XPathRule")) { 286 String xpath = null; 287 for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) { 288 Node node = ruleElement.getChildNodes().item(i); 289 if (node.getNodeType() == Node.ELEMENT_NODE) { 290 if (node.getNodeName().equals("properties")) { 291 Properties p = new Properties (); 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 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 (parseTextNode(node).trim()).intValue()); 327 } else if (node.getNodeName().equals("properties")) { 328 Properties p = new Properties (); 329 parsePropertiesNode(p, node); 330 for (Iterator j = p.keySet().iterator(); j.hasNext();) { 331 String key = (String ) 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 348 private void parseExternallyDefinedRuleNode(RuleSet ruleSet, Node ruleNode) 349 throws RuleSetNotFoundException { 350 Element ruleElement = (Element ) ruleNode; 351 String 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 365 private void parseRuleNodeWithSimpleReference(RuleSet ruleSet, Node ruleNode, 366 String 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 ("Unable to find rule " 375 + externalRuleID.getRuleName() 376 + "; perhaps the rule name is mispelled?"); 377 } 378 379 OverrideParser p = new OverrideParser((Element ) ruleNode); 380 p.overrideAsNecessary(externalRule); 381 382 if (externalRule.getPriority() <= minPriority) { 383 ruleSet.addRule(externalRule); 384 } 385 } 386 387 394 private void parseRuleNodeWithExclude(RuleSet ruleSet, Element ruleElement, String ref) 395 throws RuleSetNotFoundException { 396 NodeList excludeNodes = ruleElement.getChildNodes(); 397 Set excludes = new HashSet (); 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 excludeElement = (Element ) 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 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 parseTextNode(Node exampleNode) { 418 StringBuffer buffer = new StringBuffer (); 419 for (int i = 0; i < exampleNode.getChildNodes().getLength(); i++) { 420 Node 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 434 private static void parsePropertiesNode(Properties p, Node propertiesNode) { 435 for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) { 436 Node 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 449 private static void parsePropertyNode(Properties p, Node propertyNode) { 450 Element propertyElement = (Element ) propertyNode; 451 String name = propertyElement.getAttribute("name"); 452 String value = propertyElement.getAttribute("value"); 453 if (value.trim().length() == 0) { 455 for (int i = 0; i < propertyNode.getChildNodes().getLength(); i++) { 456 Node 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 |