001: package org.acm.seguin.pmd;
002:
003: import org.acm.seguin.util.FileSettings;
004: import org.acm.seguin.pmd.util.ResourceLoader;
005: import org.w3c.dom.Document;
006: import org.w3c.dom.Element;
007: import org.w3c.dom.Node;
008: import org.w3c.dom.NodeList;
009:
010: import javax.xml.parsers.DocumentBuilder;
011: import javax.xml.parsers.DocumentBuilderFactory;
012: import java.io.File;
013: import java.io.FilenameFilter;
014: import java.io.FileInputStream;
015: import java.io.IOException;
016: import java.io.InputStream;
017: import java.util.ArrayList;
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Properties;
022: import java.util.Set;
023: import java.util.StringTokenizer;
024:
025: public class RuleSetFactory {
026: /**
027: * Returns an Iterator of RuleSet objects
028: */
029: public Iterator getRegisteredRuleSets()
030: throws RuleSetNotFoundException {
031: try {
032: File root = FileSettings.getRefactorySettingsRoot();
033: if (root != null) {
034: File filesetRoot = new File(root, "rulesets");
035: if (filesetRoot.exists()) {
036: File[] files = filesetRoot
037: .listFiles(new FilenameFilter() {
038: public boolean accept(File dir,
039: String name) {
040: return (name != null && name
041: .endsWith(".xml"));
042: }
043: });
044: List ruleSets = new ArrayList();
045: for (int i = 0; i < files.length; i++) {
046: ruleSets.add(createRuleSet(new FileInputStream(
047: files[i])));
048: }
049: return ruleSets.iterator();
050: }
051: }
052: // get the default rulesets from the jar file/
053: Properties props = new Properties();
054: props
055: .load(ResourceLoader
056: .loadResourceAsStream("rulesets/rulesets.properties"));
057: String rulesetFilenames = props
058: .getProperty("rulesets.filenames");
059: List ruleSets = new ArrayList();
060: for (StringTokenizer st = new StringTokenizer(
061: rulesetFilenames, ","); st.hasMoreTokens();) {
062: ruleSets.add(createRuleSet(st.nextToken()));
063: }
064: return ruleSets.iterator();
065: } catch (IOException ioe) {
066: throw new RuntimeException(
067: "Couldn't find rulesets.properties; please ensure that the rulesets directory is on the classpath. Here's the current classpath: "
068: + System.getProperty("java.class.path"));
069: }
070: }
071:
072: public RuleSet createRuleSet(String name, ClassLoader classLoader)
073: throws RuleSetNotFoundException {
074: if (name.indexOf(',') == -1) {
075: return createRuleSet(tryToGetStreamTo(name, classLoader));
076: }
077:
078: RuleSet ruleSet = new RuleSet();
079: for (StringTokenizer st = new StringTokenizer(name, ","); st
080: .hasMoreTokens();) {
081: String ruleSetName = st.nextToken().trim();
082: RuleSet tmpRuleSet = createRuleSet(ruleSetName, classLoader);
083: ruleSet.addRuleSet(tmpRuleSet);
084: }
085: return ruleSet;
086: }
087:
088: /**
089: * Creates a ruleset. If passed a comma-delimited string (rulesets/basic.xml,rulesets/unusedcode.xml)
090: * it will parse that string and create a new ruleset for each item in the list.
091: */
092: public RuleSet createRuleSet(String name)
093: throws RuleSetNotFoundException {
094: return createRuleSet(name, getClass().getClassLoader());
095: }
096:
097: public RuleSet createRuleSet(InputStream inputStream) {
098: return createRuleSet(inputStream, getClass().getClassLoader());
099: }
100:
101: public RuleSet createRuleSet(InputStream inputStream,
102: ClassLoader classLoader) {
103: try {
104: DocumentBuilder builder = DocumentBuilderFactory
105: .newInstance().newDocumentBuilder();
106: Document doc = builder.parse(inputStream);
107: Element root = doc.getDocumentElement();
108:
109: RuleSet ruleSet = new RuleSet();
110: ruleSet.setName(root.getAttribute("name"));
111: ruleSet.setDescription(root.getChildNodes().item(1)
112: .getFirstChild().getNodeValue());
113:
114: NodeList rules = root.getElementsByTagName("rule");
115: for (int i = 0; i < rules.getLength(); i++) {
116: Node ruleNode = rules.item(i);
117: if (ruleNode.getAttributes().getNamedItem("ref") != null) {
118: parseExternallyDefinedRule(ruleSet, ruleNode);
119: } else {
120: parseInternallyDefinedRule(ruleSet, ruleNode,
121: classLoader);
122: }
123: }
124: return ruleSet;
125: } catch (Exception e) {
126: e.printStackTrace();
127: throw new RuntimeException(
128: "Couldn't read from that source: " + e.getMessage(),
129: e);
130: }
131: }
132:
133: private void parseInternallyDefinedRule(RuleSet ruleSet,
134: Node ruleNode, ClassLoader classLoader)
135: throws InstantiationException, IllegalAccessException,
136: ClassNotFoundException {
137: //System.out.println("ruleNode="+ruleNode);
138: //System.out.println("x="+ruleNode.getAttributes().getNamedItem("class"));
139: //System.out.println("y="+ruleNode.getAttributes().getNamedItem("class").getNodeValue());
140: String className = ruleNode.getAttributes().getNamedItem(
141: "class").getNodeValue();
142: if (className.startsWith("net.sourceforge")) {
143: className = "org.acm.seguin" + className.substring(15);
144: }
145: //System.out.println("className="+className);
146: Rule rule = (Rule) Class.forName(className, true, classLoader)
147: .newInstance();
148: rule.setName(ruleNode.getAttributes().getNamedItem("name")
149: .getNodeValue());
150: rule.setMessage(ruleNode.getAttributes()
151: .getNamedItem("message").getNodeValue());
152: // get the description, priority, example and properties (if any)
153: Node node = ruleNode.getFirstChild();
154: while (node != null) {
155: if (node.getNodeName() != null
156: && node.getNodeName().equals("description")) {
157: rule
158: .setDescription(node.getFirstChild()
159: .getNodeValue());
160: }
161:
162: if (node.getNodeName() != null
163: && node.getNodeName().equals("priority")) {
164: rule.setPriority(Integer.parseInt(node.getFirstChild()
165: .getNodeValue().trim()));
166: }
167:
168: if (node.getNodeName() != null
169: && node.getNodeName().equals("example")) {
170: rule.setExample(node.getFirstChild().getNextSibling()
171: .getNodeValue());
172: }
173:
174: parseProperties(node, rule);
175:
176: node = node.getNextSibling();
177: }
178: ruleSet.addRule(rule);
179: }
180:
181: private void parseExternallyDefinedRule(RuleSet ruleSet,
182: Node ruleNode) throws RuleSetNotFoundException {
183: String referenceValue = ruleNode.getAttributes().getNamedItem(
184: "ref").getNodeValue();
185: if (referenceValue.endsWith("xml")) {
186: parseWithExcludes(ruleNode, referenceValue, ruleSet);
187: } else {
188: parseSimpleReference(referenceValue, ruleSet);
189: }
190: }
191:
192: private void parseSimpleReference(String referenceValue,
193: RuleSet ruleSet) throws RuleSetNotFoundException {
194: RuleSetFactory rsf = new RuleSetFactory();
195: ExternalRuleID externalRuleID = new ExternalRuleID(
196: referenceValue);
197: RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
198: .loadResourceAsStream(externalRuleID.getFilename()));
199: ruleSet.addRule(externalRuleSet.getRuleByName(externalRuleID
200: .getRuleName()));
201: }
202:
203: private void parseWithExcludes(Node ruleNode,
204: String referenceValue, RuleSet ruleSet)
205: throws RuleSetNotFoundException {
206: NodeList excludeNodes = ruleNode.getChildNodes();
207: Set excludes = new HashSet();
208: for (int i = 0; i < excludeNodes.getLength(); i++) {
209: Node node = excludeNodes.item(i);
210: if (node.getAttributes() != null) {
211: excludes.add(node.getAttributes().getNamedItem("name")
212: .getNodeValue());
213: }
214: }
215: RuleSetFactory rsf = new RuleSetFactory();
216: RuleSet externalRuleSet = rsf.createRuleSet(ResourceLoader
217: .loadResourceAsStream(referenceValue));
218: for (Iterator i = externalRuleSet.getRules().iterator(); i
219: .hasNext();) {
220: Rule rule = (Rule) i.next();
221: if (!excludes.contains(rule.getName())) {
222: ruleSet.addRule(rule);
223: }
224: }
225: }
226:
227: private void parseProperties(Node node, Rule rule) {
228: if (node.getNodeName().equals("properties")) {
229: Node propNode = node.getFirstChild().getNextSibling();
230: while (propNode != null && propNode.getAttributes() != null) {
231: propNode = parseProperty(propNode, rule);
232: }
233: }
234: }
235:
236: private Node parseProperty(Node propNode, Rule rule) {
237: String propName = propNode.getAttributes().getNamedItem("name")
238: .getNodeValue();
239: String propValue;
240: if (propName.equals("xpath")) {
241: Node xpathExprNode = propNode.getFirstChild()
242: .getNextSibling();
243: propValue = xpathExprNode.getFirstChild().getNextSibling()
244: .getNodeValue();
245: if (propNode.getAttributes().getNamedItem("pluginname") != null) {
246: rule.addProperty("pluginname", propNode.getAttributes()
247: .getNamedItem("pluginname").getNodeValue());
248: }
249: } else {
250: propValue = propNode.getAttributes().getNamedItem("value")
251: .getNodeValue();
252: }
253: rule.addProperty(propName, propValue);
254: return propNode.getNextSibling().getNextSibling();
255: }
256:
257: private InputStream tryToGetStreamTo(String name, ClassLoader loader)
258: throws RuleSetNotFoundException {
259: InputStream in = ResourceLoader.loadResourceAsStream(name,
260: loader);
261: if (in == null) {
262: throw new RuleSetNotFoundException(
263: "Can't find resource "
264: + name
265: + ". Make sure the resource is a valid file or URL or is on the CLASSPATH");
266: }
267: return in;
268: }
269: }
|