1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.ant;
5
6 import net.sourceforge.pmd.PMD;
7 import net.sourceforge.pmd.Report;
8 import net.sourceforge.pmd.renderers.EmacsRenderer;
9 import net.sourceforge.pmd.renderers.HTMLRenderer;
10 import net.sourceforge.pmd.renderers.PapariTextRenderer;
11 import net.sourceforge.pmd.renderers.Renderer;
12 import net.sourceforge.pmd.renderers.SummaryHTMLRenderer;
13 import net.sourceforge.pmd.renderers.TextRenderer;
14 import net.sourceforge.pmd.renderers.VBHTMLRenderer;
15 import net.sourceforge.pmd.renderers.XMLRenderer;
16 import net.sourceforge.pmd.renderers.XSLTRenderer;
17 import net.sourceforge.pmd.renderers.YAHTMLRenderer;
18 import net.sourceforge.pmd.renderers.CSVRenderer;
19 import org.apache.tools.ant.BuildException;
20
21 import java.io.BufferedWriter;
22 import java.io.File;
23 import java.io.FileWriter;
24 import java.io.IOException;
25 import java.io.OutputStreamWriter;
26 import java.io.Writer;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 public class Formatter {
31
32 private interface RendererBuilder {
33 Renderer build(Object[] optionalArg);
34 }
35
36 private File toFile;
37 private String linkPrefix;
38 private String linePrefix;
39 private String type;
40 private boolean toConsole;
41 private boolean showSuppressed;
42
43 private static final Map<String, RendererBuilder> renderersByCode = new HashMap<String, RendererBuilder>(8);
44
45 static {
46 renderersByCode.put("xml", new RendererBuilder() {
47 public Renderer build(Object[] arg) { return new XMLRenderer(); }
48 });
49 renderersByCode.put("betterhtml", new RendererBuilder() {
50 public Renderer build(Object[] arg) { return new XSLTRenderer(); }
51 });
52 renderersByCode.put("html", new RendererBuilder() {
53 public Renderer build(Object[] arg) { return new HTMLRenderer((String) arg[0], (String) arg[1]); }
54 });
55 renderersByCode.put("summaryhtml", new RendererBuilder() {
56 public Renderer build(Object[] arg) { return new SummaryHTMLRenderer((String) arg[0], (String) arg[1]); }
57 });
58 renderersByCode.put("papari", new RendererBuilder() {
59 public Renderer build(Object[] arg) { return new PapariTextRenderer(); }
60 });
61 renderersByCode.put("csv", new RendererBuilder() {
62 public Renderer build(Object[] arg) { return new CSVRenderer(); }
63 });
64 renderersByCode.put("emacs", new RendererBuilder() {
65 public Renderer build(Object[] arg) { return new EmacsRenderer(); }
66 });
67 renderersByCode.put("vbhtml", new RendererBuilder() {
68 public Renderer build(Object[] arg) { return new VBHTMLRenderer(); }
69 });
70 renderersByCode.put("yahtml", new RendererBuilder() {
71 public Renderer build(Object[] arg) { return new YAHTMLRenderer(); }
72 });
73 renderersByCode.put("text", new RendererBuilder() {
74 public Renderer build(Object[] arg) { return new TextRenderer(); }
75 });
76
77 }
78
79 public void setShowSuppressed(boolean value) {
80 this.showSuppressed = value;
81 }
82
83 public void setType(String type) {
84 this.type = type;
85 }
86
87 public void setLinkPrefix(String linkPrefix) {
88 this.linkPrefix = linkPrefix;
89 }
90
91 public void setToFile(File toFile) {
92 this.toFile = toFile;
93 }
94
95 public void setToConsole(boolean toConsole) {
96 this.toConsole = toConsole;
97 }
98
99 public void setLinePrefix(String linePrefix) {
100 this.linePrefix = linePrefix;
101 }
102
103 private Writer writer;
104
105 private Renderer renderer;
106
107 public Renderer getRenderer() {
108 return renderer;
109 }
110
111 public void start(String baseDir) {
112 try {
113 if (toConsole) {
114 writer = new BufferedWriter(new OutputStreamWriter(System.out));
115 }
116 if (toFile != null) {
117 writer = getToFileWriter(baseDir);
118 }
119 renderer = getRenderer(toConsole);
120 renderer.setWriter(writer);
121 renderer.start();
122 } catch (IOException ioe) {
123 throw new BuildException(ioe.getMessage());
124 }
125 }
126
127 public void end(Report errorReport) {
128 try {
129 renderer.renderFileReport(errorReport);
130 renderer.end();
131 writer.write(PMD.EOL);
132 if (toConsole) {
133 writer.flush();
134 } else {
135 writer.close();
136 }
137 } catch (IOException ioe) {
138 throw new BuildException(ioe.getMessage());
139 }
140 }
141
142 public boolean isNoOutputSupplied() {
143 return toFile == null && !toConsole;
144 }
145
146 public String toString() {
147 return "file = " + toFile + "; renderer = " + type;
148 }
149
150 private static String[] validRendererCodes() {
151 return renderersByCode.keySet().toArray(new String[renderersByCode.size()]);
152 }
153
154 private static String unknownRendererMessage(String userSpecifiedType) {
155 StringBuffer sb = new StringBuffer(100);
156 sb.append("Formatter type must be one of: '");
157 String[] typeCodes = validRendererCodes();
158 sb.append(typeCodes[0]);
159 for (int i = 1; i < typeCodes.length; i++) {
160 sb.append("', '").append(typeCodes[i]);
161 }
162 sb.append("', or a class name; you specified: ");
163 sb.append(userSpecifiedType);
164 return sb.toString();
165 }
166
167 private Renderer fromClassname(String rendererClassname) {
168 try {
169 return (Renderer) Class.forName(rendererClassname).newInstance();
170 } catch (Exception e) {
171 throw new BuildException(unknownRendererMessage(rendererClassname));
172 }
173 }
174
175
176 private Renderer getRenderer(boolean consoleRenderer) {
177 if ("".equals(type)) {
178 throw new BuildException(unknownRendererMessage("<unspecified>"));
179 }
180 RendererBuilder builder = renderersByCode.get(type);
181 Renderer renderer = builder == null ? fromClassname(type) : builder.build(new String[]{linkPrefix, linePrefix});
182 renderer.showSuppressedViolations(showSuppressed);
183 return renderer;
184 }
185
186 private Writer getToFileWriter(String baseDir) throws IOException {
187 if (!toFile.isAbsolute()) {
188 return new BufferedWriter(new FileWriter(new File(baseDir + System.getProperty("file.separator") + toFile.getPath())));
189 }
190 return new BufferedWriter(new FileWriter(toFile));
191 }
192 }