001: package net.innig.macker.event;
002:
003: import net.innig.macker.rule.RuleSet;
004: import net.innig.macker.structure.ClassInfo;
005:
006: import java.io.File;
007: import java.io.FileOutputStream;
008: import java.io.OutputStreamWriter;
009: import java.io.BufferedWriter;
010: import java.io.Writer;
011: import java.io.IOException;
012: import java.util.LinkedList;
013: import java.util.Iterator;
014:
015: import org.jdom.Document;
016: import org.jdom.Element;
017: import org.jdom.output.XMLOutputter;
018:
019: import org.apache.commons.lang.StringUtils;
020:
021: public class XmlReportingListener implements MackerEventListener {
022: private Writer out;
023: private String encoding;
024:
025: private Document document;
026: private Element curElem;
027: private LinkedList elemStack;
028:
029: public XmlReportingListener(File outFile) throws ListenerException {
030: try {
031: if (outFile.exists())
032: outFile.delete();
033: OutputStreamWriter out = new OutputStreamWriter(
034: new FileOutputStream(outFile), "UTF-8");
035: BufferedWriter bufferedOut = new BufferedWriter(out);
036: init(bufferedOut, "UTF-8");
037: } catch (IOException ioe) {
038: throw new ListenerException(this ,
039: "Unable to remove and re-create report file \""
040: + outFile + "\"", ioe);
041: }
042: }
043:
044: public XmlReportingListener(Writer out, String encoding)
045: throws ListenerException {
046: init(out, encoding);
047: }
048:
049: private void init(Writer out, String encoding)
050: throws ListenerException {
051: this .out = out;
052: this .encoding = encoding;
053:
054: elemStack = new LinkedList();
055: Element topElem = new Element("macker-report");
056: Element timestampElem = new Element("timestamp");
057: timestampElem.setText(new java.util.Date().toString()); // to heck with sophisticated localization!
058: topElem.addContent(timestampElem);
059:
060: pushElem(topElem);
061: document = new Document(topElem);
062: }
063:
064: public void flush() throws ListenerException {
065: try {
066: XMLOutputter xmlOut = new XMLOutputter(" ", true,
067: encoding);
068: xmlOut.output(document, out);
069: out.flush();
070: } catch (IOException ioe) {
071: throw new ListenerException(this ,
072: "Unable to write XML report", ioe);
073: }
074: }
075:
076: public void close() throws ListenerException {
077: try {
078: out.close();
079: } catch (IOException ioe) {
080: throw new ListenerException(this ,
081: "Unable to close XML report", ioe);
082: }
083: }
084:
085: public void mackerStarted(RuleSet ruleSet) {
086: if (ruleSet.hasName()) {
087: Element ruleSetElem = new Element("ruleset");
088: ruleSetElem.setAttribute("name", ruleSet.getName());
089: curElem.addContent(ruleSetElem);
090: pushElem(ruleSetElem);
091: } else
092: pushElem(curElem); // push again so finish can pop
093: }
094:
095: public void mackerFinished(RuleSet ruleSet)
096: throws MackerIsMadException, ListenerException {
097: popElem();
098: }
099:
100: public void mackerAborted(RuleSet ruleSet) {
101: curElem = null;
102: }
103:
104: public void handleMackerEvent(RuleSet ruleSet, MackerEvent event)
105: throws MackerIsMadException {
106: if (event instanceof MessageEvent) {
107: Element messageRuleElem = new Element("message-rule");
108: handleEventBasics(messageRuleElem, event);
109: curElem.addContent(messageRuleElem);
110: }
111:
112: if (event instanceof AccessRuleViolation) {
113: AccessRuleViolation violation = (AccessRuleViolation) event;
114: Element violationElem = new Element("access-rule-violation");
115:
116: handleEventBasics(violationElem, violation);
117:
118: Element fromElem = new Element("from");
119: Element toElem = new Element("to");
120: describeClass(fromElem, violation.getFrom());
121: describeClass(toElem, violation.getTo());
122: violationElem.addContent(fromElem);
123: violationElem.addContent(toElem);
124:
125: curElem.addContent(violationElem);
126: }
127:
128: if (event instanceof ForEachStarted) {
129: ForEachStarted forEachStarted = (ForEachStarted) event;
130: Element forEachElem = new Element("foreach");
131: forEachElem.setAttribute("var", forEachStarted.getForEach()
132: .getVariableName());
133: curElem.addContent(forEachElem);
134: pushElem(forEachElem);
135: }
136:
137: if (event instanceof ForEachIterationStarted) {
138: ForEachIterationStarted forEachIter = (ForEachIterationStarted) event;
139: Element iterElem = new Element("iteration");
140: iterElem.setAttribute("value", forEachIter
141: .getVariableValue());
142: curElem.addContent(iterElem);
143: pushElem(iterElem);
144: }
145:
146: if (event instanceof ForEachIterationFinished
147: || event instanceof ForEachFinished)
148: popElem();
149: }
150:
151: private void handleEventBasics(Element elem, MackerEvent event) {
152: elem.setAttribute("severity", event.getRule().getSeverity()
153: .getName());
154: for (Iterator msgIter = event.getMessages().iterator(); msgIter
155: .hasNext();) {
156: String message = (String) msgIter.next();
157: Element messageElem = new Element("message");
158: messageElem.setText(message);
159: elem.addContent(messageElem);
160: }
161: }
162:
163: private void describeClass(Element classInfoElem,
164: ClassInfo classInfo) {
165: Element fullElem = new Element("full-name");
166: Element classElem = new Element("class");
167: Element packElem = new Element("package");
168: fullElem.setText(classInfo.getFullName());
169: classElem.setText(classInfo.getClassName());
170: packElem.setText(classInfo.getPackageName());
171: classInfoElem.addContent(fullElem);
172: classInfoElem.addContent(classElem);
173: if (!StringUtils.isEmpty(classInfo.getPackageName()))
174: classInfoElem.addContent(packElem);
175: }
176:
177: private void pushElem(Element elem) {
178: elemStack.addLast(curElem);
179: curElem = elem;
180: }
181:
182: private void popElem() {
183: curElem = (Element) elemStack.removeLast();
184: }
185:
186: public String toString() {
187: return "XmlReportingListener";
188: }
189: }
|