1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd.renderers;
5
6 import net.sourceforge.pmd.IRuleViolation;
7 import net.sourceforge.pmd.PMD;
8 import net.sourceforge.pmd.Report;
9 import net.sourceforge.pmd.util.StringUtil;
10
11 import java.io.IOException;
12 import java.io.Writer;
13 import java.util.Iterator;
14 import java.util.List;
15
16 public class HTMLRenderer extends OnTheFlyRenderer {
17
18 private final String linkPrefix;
19 private final String linePrefix;
20
21 private int violationCount = 1;
22 boolean colorize = true;
23
24 public HTMLRenderer(String linkPrefix, String linePrefix) {
25 this.linkPrefix = linkPrefix;
26 this.linePrefix = linePrefix;
27
28 }
29
30 public HTMLRenderer() {
31 this(null, null);
32 }
33
34 public void renderBody(Writer writer, Report report) throws IOException {
35 writer.write("<center><h3>PMD report</h3></center>");
36 writer.write("<center><h3>Problems found</h3></center>");
37 writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
38 setWriter(writer);
39 renderFileReport(report);
40 writer.write("</table>");
41 glomProcessingErrors(writer, errors);
42 if (showSuppressedViolations) {
43 glomSuppressions(writer, suppressed);
44 }
45 }
46
47 public void start() throws IOException {
48 Writer writer = getWriter();
49 writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
50 writer.write("<center><h3>PMD report</h3></center>");
51 writer.write("<center><h3>Problems found</h3></center>");
52 writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
53 }
54
55 public void renderFileViolations(Iterator<IRuleViolation> violations) throws IOException {
56 Writer writer = getWriter();
57 glomIRuleViolations(writer, violations);
58 }
59
60 public void end() throws IOException {
61 Writer writer = getWriter();
62 writer.write("</table>");
63 glomProcessingErrors(writer, errors);
64 if (showSuppressedViolations) {
65 glomSuppressions(writer, suppressed);
66 }
67 writer.write("</body></html>");
68 }
69
70 private void glomIRuleViolations(Writer writer, Iterator<IRuleViolation> violations) throws IOException {
71 StringBuffer buf = new StringBuffer(500);
72 while (violations.hasNext()) {
73 IRuleViolation rv = violations.next();
74 buf.setLength(0);
75 buf.append("<tr");
76 if (colorize) {
77 buf.append(" bgcolor=\"lightgrey\"");
78 }
79 colorize = !colorize;
80 buf.append("> " + PMD.EOL);
81 buf.append("<td align=\"center\">" + violationCount + "</td>" + PMD.EOL);
82 buf.append("<td width=\"*%\">" + maybeWrap(rv.getFilename(),linePrefix==null?"":linePrefix + Integer.toString(rv.getBeginLine())) + "</td>" + PMD.EOL);
83 buf.append("<td align=\"center\" width=\"5%\">" + Integer.toString(rv.getBeginLine()) + "</td>" + PMD.EOL);
84
85 String d = StringUtil.htmlEncode(rv.getDescription());
86
87 if (rv.getRule().getExternalInfoUrl() != null && rv.getRule().getExternalInfoUrl().length() != 0) {
88 d = "<a href=\"" + rv.getRule().getExternalInfoUrl() + "\">" + d + "</a>";
89 }
90 buf.append("<td width=\"*\">" + d + "</td>" + PMD.EOL);
91 buf.append("</tr>" + PMD.EOL);
92 writer.write(buf.toString());
93 violationCount++;
94 }
95 }
96
97 private void glomProcessingErrors(Writer writer, List<Report.ProcessingError> errors) throws IOException {
98 if (!errors.isEmpty()) {
99 writer.write("<hr/>");
100 writer.write("<center><h3>Processing errors</h3></center>");
101 writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>File</th><th>Problem</th></tr>" + PMD.EOL);
102
103 StringBuffer buf = new StringBuffer(500);
104 boolean colorize = true;
105 for (Report.ProcessingError pe: errors) {
106 buf.setLength(0);
107 buf.append("<tr");
108 if (colorize) {
109 buf.append(" bgcolor=\"lightgrey\"");
110 }
111 colorize = !colorize;
112 buf.append("> " + PMD.EOL);
113 buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
114 buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
115 buf.append("</tr>" + PMD.EOL);
116 writer.write(buf.toString());
117
118 }
119 writer.write("</table>");
120 }
121 }
122
123 private void glomSuppressions(Writer writer, List<Report.SuppressedViolation> suppressed) throws IOException {
124 if (!suppressed.isEmpty()) {
125 writer.write("<hr/>");
126 writer.write("<center><h3>Suppressed warnings</h3></center>");
127 writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL + "<th>File</th><th>Line</th><th>Rule</th><th>NOPMD or Annotation</th><th>Reason</th></tr>" + PMD.EOL);
128
129 StringBuffer buf = new StringBuffer(500);
130 boolean colorize = true;
131 for (Report.SuppressedViolation sv: suppressed) {
132 buf.setLength(0);
133 buf.append("<tr");
134 if (colorize) {
135 buf.append(" bgcolor=\"lightgrey\"");
136 }
137 colorize = !colorize;
138 buf.append("> " + PMD.EOL);
139 buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
140 buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
141 buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
142 buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>" + PMD.EOL);
143 buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>" + PMD.EOL);
144 buf.append("</tr>" + PMD.EOL);
145 writer.write(buf.toString());
146 }
147 writer.write("</table>");
148 }
149 }
150
151 private String maybeWrap(String filename, String line) {
152 if (linkPrefix == null) {
153 return filename;
154 }
155 String newFileName = filename.substring(0, filename.lastIndexOf('.')).replace('\\', '/');
156 return "<a href=\"" + linkPrefix + newFileName + ".html#" + line + "\">" + newFileName + "</a>";
157 }
158 }