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 }