001: package org.acm.seguin.pmd;
002:
003: import org.acm.seguin.pmd.swingui.Constants;
004: import org.xml.sax.Attributes;
005: import org.xml.sax.InputSource;
006: import org.xml.sax.SAXException;
007: import org.xml.sax.helpers.DefaultHandler;
008:
009: import javax.xml.parsers.SAXParser;
010: import javax.xml.parsers.SAXParserFactory;
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.text.MessageFormat;
014:
015: /**
016: * Reads an XML file containing information about a rule set and each rule within the rule set.
017: * <p>
018: * The SAXParser is used to parse the file.
019: *
020: * @author Donald A. Leckie
021: * @since August 30, 2002
022: * @version $Revision: 1.1 $, $Date: 2003/07/29 20:51:58 $
023: */
024: public class RuleSetReader implements Constants {
025:
026: private RuleSet m_ruleSet;
027: private boolean m_onlyIfIncluded;
028:
029: // Constants
030: private final String REJECT_NOT_INCLUDED = "Reject not included";
031:
032: /**
033: *****************************************************************************
034: *
035: */
036: public RuleSetReader() {
037: }
038:
039: /**
040: *****************************************************************************
041: *
042: * @param inputStream
043: * @param ruleSetFileName
044: *
045: * @return
046: */
047: public RuleSet read(InputStream inputStream, String ruleSetFileName)
048: throws PMDException {
049: return read(inputStream, ruleSetFileName, false);
050: }
051:
052: /**
053: *****************************************************************************
054: *
055: * @param inputStream
056: * @param ruleSetFileName
057: * @param onlyIfIncluded
058: *
059: * @return
060: */
061: public RuleSet read(InputStream inputStream,
062: String ruleSetFileName, boolean onlyIfIncluded)
063: throws PMDException {
064: if (inputStream == null) {
065: String message = "Missing input stream.";
066: PMDException pmdException = new PMDException(message);
067: pmdException.fillInStackTrace();
068: throw pmdException;
069: }
070:
071: if (ruleSetFileName == null) {
072: String message = "Missing rule set file name.";
073: PMDException pmdException = new PMDException(message);
074: pmdException.fillInStackTrace();
075: throw pmdException;
076: }
077:
078: m_onlyIfIncluded = onlyIfIncluded;
079:
080: try {
081: InputSource inputSource;
082: MainContentHandler mainContentHandler;
083: SAXParser parser;
084:
085: inputSource = new InputSource(inputStream);
086: mainContentHandler = new MainContentHandler();
087:
088: SAXParserFactory factory = SAXParserFactory.newInstance();
089: factory.setFeature(
090: "http://xml.org/sax/features/namespace-prefixes",
091: true);
092: factory.setFeature(
093: "http://xml.org/sax/features/namespaces", false);
094:
095: parser = factory.newSAXParser();
096:
097: parser.parse(inputSource, mainContentHandler);
098: m_ruleSet.setFileName(ruleSetFileName);
099:
100: return m_ruleSet;
101: } catch (IOException exception) {
102: PMDException pmdException = new PMDException(
103: "IOException was thrown.", exception);
104: pmdException.fillInStackTrace();
105: throw pmdException;
106: } catch (SAXException exception) {
107: if (exception.getMessage() == REJECT_NOT_INCLUDED) {
108: // Return a null rule set to indicate that it should not be included.
109: return null;
110: }
111:
112: Throwable originalException = exception.getException();
113:
114: if (originalException instanceof PMDException) {
115: throw (PMDException) originalException;
116: }
117:
118: String message = "SAXException was thrown.";
119: PMDException pmdException = new PMDException(message,
120: exception);
121: pmdException.fillInStackTrace();
122: throw pmdException;
123: } catch (Exception exception) {
124: PMDException pmdException = new PMDException(
125: "Uncaught exception was thrown.", exception);
126: pmdException.fillInStackTrace();
127: throw pmdException;
128: }
129: }
130:
131: /**
132: *****************************************************************************
133: *****************************************************************************
134: *****************************************************************************
135: */
136: private class MainContentHandler extends DefaultHandler {
137:
138: private StringBuffer m_buffer = new StringBuffer(500);
139: private Rule m_rule;
140:
141: /**
142: *************************************************************************
143: */
144: private MainContentHandler() {
145: super ();
146: }
147:
148: /**
149: *************************************************************************
150: *
151: * @param namespace
152: * @param localName
153: * @param qualifiedName
154: * @param attributes
155: *
156: * @throws SAXException
157: */
158: public void startElement(String namespace, String localName,
159: String qualifiedName, Attributes attributes)
160: throws SAXException {
161: m_buffer.setLength(0);
162:
163: if (qualifiedName.equalsIgnoreCase("ruleset")) {
164: String name;
165: String include;
166:
167: m_ruleSet = new RuleSet();
168: name = attributes.getValue("name");
169: name = (name == null) ? "Unknown" : name.trim();
170: include = attributes.getValue("include");
171: include = (include == null) ? "true" : include.trim();
172:
173: m_ruleSet.setName(name);
174: m_ruleSet.setInclude(include.equalsIgnoreCase("true"));
175: } else if (qualifiedName.equalsIgnoreCase("rule")) {
176: String ruleName;
177: String message;
178: String className;
179: String includeText;
180: boolean include;
181:
182: ruleName = attributes.getValue("name");
183: message = attributes.getValue("message");
184: className = attributes.getValue("class");
185: includeText = attributes.getValue("include");
186: ruleName = (ruleName == null) ? "Unknown" : ruleName
187: .trim();
188: message = (message == null) ? EMPTY_STRING : message
189: .trim();
190: className = (className == null) ? EMPTY_STRING
191: : className.trim();
192: includeText = (includeText == null) ? "true"
193: : includeText.trim();
194: include = includeText.equalsIgnoreCase("true");
195:
196: if (m_onlyIfIncluded && (include == false)) {
197: SAXException exception = new SAXException(
198: REJECT_NOT_INCLUDED);
199: throw exception;
200: }
201:
202: if (className.length() == 0) {
203: String template = "Missing class name for rule \"{0}\" in rule set \"{1}\".";
204: Object[] args = { ruleName, m_ruleSet.getName() };
205: String msg = MessageFormat.format(template, args);
206: PMDException pmdException = new PMDException(msg);
207: SAXException saxException = new SAXException(
208: EMPTY_STRING, pmdException.getReason());
209: pmdException.fillInStackTrace();
210: throw saxException;
211: }
212:
213: try {
214: Class ruleClass;
215:
216: ruleClass = Class.forName(className);
217: m_rule = (Rule) ruleClass.newInstance();
218: } catch (ClassNotFoundException classNotFoundException) {
219: try {
220: Class ruleClass;
221: className = "org.acm.seguin.pmd.UndefinedRule";
222: ruleClass = Class.forName(className);
223: m_rule = (Rule) ruleClass.newInstance();
224: } catch (Exception exception) {
225: String template = "Cannot find class \"{0}\" on the classpath.";
226: Object[] args = { className };
227: String msg = MessageFormat.format(template,
228: args);
229: PMDException pmdException = new PMDException(
230: msg, exception);
231: SAXException saxException = new SAXException(
232: EMPTY_STRING, pmdException);
233: pmdException.fillInStackTrace();
234: throw saxException;
235: }
236: } catch (IllegalAccessException exception) {
237: String template = "Illegal access to class \"{0}\" for rule \"{1}\" in rule set \"{2}\".";
238: Object[] args = { className, ruleName,
239: m_ruleSet.getName() };
240: String msg = MessageFormat.format(template, args);
241: PMDException pmdException = new PMDException(msg,
242: exception);
243: SAXException saxException = new SAXException(
244: EMPTY_STRING, pmdException);
245: pmdException.fillInStackTrace();
246: throw saxException;
247: } catch (InstantiationException exception) {
248: String template = "Cannot instantiate class \"{0}\" for rule \"{1}\" in rule set \"{2}\".";
249: Object[] args = { className, ruleName,
250: m_ruleSet.getName() };
251: String msg = MessageFormat.format(template, args);
252: PMDException pmdException = new PMDException(msg,
253: exception);
254: SAXException saxException = new SAXException(
255: EMPTY_STRING, pmdException);
256: pmdException.fillInStackTrace();
257: throw saxException;
258: }
259:
260: m_rule.setName(ruleName);
261: m_rule.setMessage(message);
262: m_rule.setInclude(include);
263: m_ruleSet.addRule(m_rule);
264: } else if (qualifiedName.equalsIgnoreCase("property")) {
265: String name = attributes.getValue("name");
266: String value = attributes.getValue("value");
267: String type = attributes.getValue("type");
268:
269: name = (name == null) ? EMPTY_STRING : name.trim();
270: value = (value == null) ? EMPTY_STRING : value;
271: type = (type == null) ? EMPTY_STRING : type;
272:
273: if (name.length() > 0) {
274: m_rule.getProperties().setValue(name, value);
275: m_rule.getProperties().setValueType(name, type);
276: }
277: }
278: }
279:
280: /**
281: *************************************************************************
282: *
283: * @param chars
284: * @param beginIndex
285: * @param length
286: *
287: * @throws PMDException
288: */
289: public void characters(char[] chars, int beginIndex, int length) {
290: m_buffer.append(chars, beginIndex, length);
291: }
292:
293: /**
294: *************************************************************************
295: *
296: * @param namespace
297: * @param localName
298: * @param qualifiedName
299: *
300: * @throws SAXException
301: */
302: public void endElement(String namespace, String localName,
303: String qualifiedName) throws SAXException {
304: if (qualifiedName.equalsIgnoreCase("description")) {
305: if (m_rule == null) {
306: m_ruleSet.setDescription(trim(m_buffer));
307: } else {
308: m_rule.setDescription(trim(m_buffer));
309: }
310: } else if (qualifiedName.equalsIgnoreCase("message")) {
311: m_rule.setMessage(trim(m_buffer));
312: } else if (qualifiedName.equalsIgnoreCase("example")) {
313: m_rule.setExample(trimExample(m_buffer));
314: } else if (qualifiedName.equals("priority")) {
315: int priority;
316:
317: try {
318: priority = Integer.parseInt(trim(m_buffer));
319: } catch (NumberFormatException exception) {
320: priority = Rule.LOWEST_PRIORITY;
321: }
322:
323: m_rule.setPriority(priority);
324: } else if (qualifiedName.equalsIgnoreCase("rule")) {
325: m_rule = null;
326: }
327: }
328:
329: /**
330: ***************************************************************************
331: */
332: private String trim(StringBuffer buffer) {
333: if (buffer.length() > 0) {
334: for (int n = buffer.length() - 1; n >= 0; n--) {
335: if (buffer.charAt(n) == '\n') {
336: buffer.setCharAt(n, ' ');
337: }
338:
339: char theChar = buffer.charAt(n);
340:
341: if (theChar == ' ') {
342: if (n == buffer.length() - 1) {
343: buffer.deleteCharAt(n);
344: } else if (buffer.charAt(n + 1) == ' ') {
345: buffer.deleteCharAt(n);
346: } else if (n == 0) {
347: buffer.deleteCharAt(n);
348: }
349: }
350: }
351: }
352:
353: return buffer.toString();
354: }
355:
356: /**
357: ***************************************************************************
358: */
359: private String trimExample(StringBuffer buffer) {
360: while ((buffer.length() > 0)
361: && ((buffer.charAt(0) == '\n') || (buffer.charAt(0) == ' '))) {
362: buffer.deleteCharAt(0);
363: }
364:
365: for (int n = buffer.length() - 1; n >= 0; n--) {
366: if ((buffer.charAt(n) != '\n')
367: && (buffer.charAt(n) != ' ')) {
368: buffer.setLength(n + 1);
369: break;
370: }
371: }
372:
373: return buffer.toString();
374: }
375: }
376: }
|