View Javadoc

    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 java.io.IOException;
    7   import java.io.Writer;
    8   import java.util.Iterator;
    9   import java.util.List;
    10
    11  import net.sourceforge.pmd.PMD;
    12  import net.sourceforge.pmd.Report;
    13  import net.sourceforge.pmd.RuleViolation;
    14  import net.sourceforge.pmd.lang.rule.properties.StringProperty;
    15  import net.sourceforge.pmd.util.StringUtil;
    16
    17  /**
    18   * Renderer to basic HTML format.
    19   *
    20   * FIXME: this class should just work with the XMLRenderer and then apply
    21   * 		an XSLT transformation + stylesheet. No need to hard-code HTML
    22   * 		markup here.
    23   */
    24  public class HTMLRenderer extends AbstractIncrementingRenderer {
    25
    26      public static final String NAME = "html";
    27
    28      public static final StringProperty LINE_PREFIX = new StringProperty("linePrefix", "Prefix for line number anchor in the source file.", null, 1);
    29      public static final StringProperty LINK_PREFIX = new StringProperty("linkPrefix", "Path to HTML source.", null, 0);
    30
    31      private String linkPrefix;
    32      private String linePrefix;
    33
    34      private int violationCount = 1;
    35      boolean colorize = true;
    36
    37      public HTMLRenderer() {
    38  		super(NAME, "HTML format");
    39
    40  		definePropertyDescriptor(LINK_PREFIX);
    41  		definePropertyDescriptor(LINE_PREFIX);
    42      }
    43
    44      public String defaultFileExtension() { return "html"; }
    45
    46      /**
    47       * Write the body of the main body of the HTML content.
    48       *
    49       * @param writer
    50       * @param report
    51       * @throws IOException
    52       */
    53      public void renderBody(Writer writer, Report report) throws IOException {
    54  		linkPrefix = getProperty(LINK_PREFIX);
    55  		linePrefix = getProperty(LINE_PREFIX);
    56
    57  		writer.write("<center><h3>PMD report</h3></center>");
    58  		writer.write("<center><h3>Problems found</h3></center>");
    59  		writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL
    60  			+ "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
    61  		setWriter(writer);
    62  		renderFileReport(report);
    63  		writer.write("</table>");
    64  		glomProcessingErrors(writer, errors);
    65  		if (showSuppressedViolations) {
    66  		    glomSuppressions(writer, suppressed);
    67  		}
    68      }
    69
    70      /**
    71       * {@inheritDoc}
    72       */
    73      @Override
    74      public void start() throws IOException {
    75  		Writer writer = getWriter();
    76  		writer.write("<html><head><title>PMD</title></head><body>" + PMD.EOL);
    77  		writer.write("<center><h3>PMD report</h3></center>");
    78  		writer.write("<center><h3>Problems found</h3></center>");
    79  		writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL
    80  			+ "<th>#</th><th>File</th><th>Line</th><th>Problem</th></tr>" + PMD.EOL);
    81      }
    82
    83      /**
    84       * {@inheritDoc}
    85       */
    86      @Override
    87      public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException {
    88  		Writer writer = getWriter();
    89  		glomRuleViolations(writer, violations);
    90      }
    91
    92      /**
    93       * {@inheritDoc}
    94       */
    95      @Override
    96      public void end() throws IOException {
    97  		Writer writer = getWriter();
    98  		writer.write("</table>");
    99  		glomProcessingErrors(writer, errors);
    100 		if (showSuppressedViolations) {
    101 		    glomSuppressions(writer, suppressed);
    102 		}
    103 		writer.write("</body></html>" + PMD.EOL);
    104     }
    105
    106     private void glomRuleViolations(Writer writer, Iterator<RuleViolation> violations) throws IOException {
    107
    108     	StringBuilder buf = new StringBuilder(500);
    109
    110 		while (violations.hasNext()) {
    111 		    RuleViolation rv = violations.next();
    112 		    buf.setLength(0);
    113 		    buf.append("<tr");
    114 		    if (colorize) {
    115 		    	buf.append(" bgcolor=\"lightgrey\"");
    116 		    }
    117 		    colorize = !colorize;
    118 		    buf.append("> " + PMD.EOL);
    119 		    buf.append("<td align=\"center\">" + violationCount + "</td>" + PMD.EOL);
    120 		    buf.append("<td width=\"*%\">"
    121 			    + maybeWrap(rv.getFilename(), linePrefix == null ? "" : linePrefix
    122 				    + Integer.toString(rv.getBeginLine())) + "</td>" + PMD.EOL);
    123 		    buf.append("<td align=\"center\" width=\"5%\">" + Integer.toString(rv.getBeginLine()) + "</td>" + PMD.EOL);
    124
    125 		    String d = StringUtil.htmlEncode(rv.getDescription());
    126
    127 		    String infoUrl = rv.getRule().getExternalInfoUrl();
    128 		    if (StringUtil.isNotEmpty(infoUrl)) {
    129 				d = "<a href=\"" + infoUrl + "\">" + d + "</a>";
    130 			    }
    131 		    buf.append("<td width=\"*\">" + d + "</td>" + PMD.EOL);
    132 		    buf.append("</tr>" + PMD.EOL);
    133 		    writer.write(buf.toString());
    134 		    violationCount++;
    135 			}
    136     }
    137
    138     private void glomProcessingErrors(Writer writer, List<Report.ProcessingError> errors) throws IOException {
    139
    140     	if (errors.isEmpty()) return;
    141
    142 	    writer.write("<hr/>");
    143 	    writer.write("<center><h3>Processing errors</h3></center>");
    144 	    writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL
    145 		    + "<th>File</th><th>Problem</th></tr>" + PMD.EOL);
    146
    147 	    StringBuffer buf = new StringBuffer(500);
    148 	    boolean colorize = true;
    149 	    for (Report.ProcessingError pe : errors) {
    150 			buf.setLength(0);
    151 			buf.append("<tr");
    152 			if (colorize) {
    153 			    buf.append(" bgcolor=\"lightgrey\"");
    154 			}
    155 			colorize = !colorize;
    156 			buf.append("> " + PMD.EOL);
    157 			buf.append("<td>" + pe.getFile() + "</td>" + PMD.EOL);
    158 			buf.append("<td>" + pe.getMsg() + "</td>" + PMD.EOL);
    159 			buf.append("</tr>" + PMD.EOL);
    160 			writer.write(buf.toString());
    161 		    }
    162 	    writer.write("</table>");
    163     }
    164
    165     private void glomSuppressions(Writer writer, List<Report.SuppressedViolation> suppressed) throws IOException {
    166 		if (suppressed.isEmpty())  return;
    167
    168 		writer.write("<hr/>");
    169 		writer.write("<center><h3>Suppressed warnings</h3></center>");
    170 		writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL
    171 			    + "<th>File</th><th>Line</th><th>Rule</th><th>NOPMD or Annotation</th><th>Reason</th></tr>"
    172 			    + PMD.EOL);
    173
    174 		StringBuilder buf = new StringBuilder(500);
    175 		boolean colorize = true;
    176 		for (Report.SuppressedViolation sv : suppressed) {
    177 			buf.setLength(0);
    178 			buf.append("<tr");
    179 			if (colorize) {
    180 			    buf.append(" bgcolor=\"lightgrey\"");
    181 			}
    182 			colorize = !colorize;
    183 			buf.append("> " + PMD.EOL);
    184 			buf.append("<td align=\"left\">" + sv.getRuleViolation().getFilename() + "</td>" + PMD.EOL);
    185 			buf.append("<td align=\"center\">" + sv.getRuleViolation().getBeginLine() + "</td>" + PMD.EOL);
    186 			buf.append("<td align=\"center\">" + sv.getRuleViolation().getRule().getName() + "</td>" + PMD.EOL);
    187 			buf.append("<td align=\"center\">" + (sv.suppressedByNOPMD() ? "NOPMD" : "Annotation") + "</td>"
    188 					+ PMD.EOL);
    189 			buf.append("<td align=\"center\">" + (sv.getUserMessage() == null ? "" : sv.getUserMessage()) + "</td>"
    190 					+ PMD.EOL);
    191 			buf.append("</tr>" + PMD.EOL);
    192 			writer.write(buf.toString());
    193 			}
    194 		writer.write("</table>");
    195     }
    196
    197     private String maybeWrap(String filename, String line) {
    198 		if (StringUtil.isEmpty(linkPrefix)) {
    199 		    return filename;
    200 		}
    201 		String newFileName = filename;
    202 		int index = filename.lastIndexOf('.');
    203 		if (index >= 0) {
    204 		    newFileName = filename.substring(0, index).replace('\\', '/');
    205 		}
    206 		return "<a href=\"" + linkPrefix + newFileName + ".html#" + line + "\">" + newFileName + "</a>";
    207     }
    208 }