/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.dfa.report;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.util.StringUtil;
/**
* Uses the generated result tree instead of the result list. The
* visitor traverses the tree and creates several html files. The
* "package view" file (index.html) displays an overview of packages,
* classes and the number of * rule violations they contain. All the
* other html files represent a class * and show detailed information
* about the violations.
*
* @author raik
*/
public class ReportHTMLPrintVisitor extends ReportVisitor {
@SuppressWarnings("PMD.AvoidStringBufferField")
private StringBuilder packageBuf = new StringBuilder(30);
@SuppressWarnings("PMD.AvoidStringBufferField")
private StringBuilder classBuf = new StringBuilder(60);
private int length;
private String baseDir;
private static final String FILE_SEPARATOR = System.getProperty("file.separator");
public ReportHTMLPrintVisitor(String baseDir) {
this.baseDir = baseDir;
}
/**
* Writes the buffer to file.
*/
private void write(String filename, StringBuilder buf) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter(new File(baseDir + FILE_SEPARATOR + filename)));
bw.write(buf.toString(), 0, buf.length());
IOUtils.closeQuietly(bw);
}
/**
* Generates a html table with violation information.
*/
private String displayRuleViolation(RuleViolation vio) {
StringBuilder sb = new StringBuilder(200);
sb.append("<table border=\"0\">");
renderViolationRow(sb, "Rule:", vio.getRule().getName());
renderViolationRow(sb, "Description:", vio.getDescription());
if (StringUtil.isNotEmpty(vio.getVariableName())) {
renderViolationRow(sb, "Variable:", vio.getVariableName());
}
if (vio.getEndLine() > 0) {
renderViolationRow(sb, "Line:", vio.getEndLine() + " and " + vio.getBeginLine());
} else {
renderViolationRow(sb, "Line:", Integer.toString(vio.getBeginLine()));
}
sb.append("</table>");
return sb.toString();
}
// TODO - join the 21st century, include CSS attributes :)
private void renderViolationRow(StringBuilder sb, String fieldName, String fieldData) {
sb.append("<tr><td><b>").append(fieldName).append("</b></td><td>").append(fieldData).append("</td></tr>");
}
/**
* The visit method (Visitor Pattern). There are 3 types of ReportNodes:
* RuleViolation - contains a RuleViolation, Class - represents a class and
* contains the name of the class, Package - represents a package and
* contains the name(s) of the package.
*/
@Override
public void visit(AbstractReportNode node) {
/*
* The first node of result tree.
*/
if (node.getParent() == null) {
packageBuf.insert(0,
"<html>" + " <head>" + " <title>PMD</title>" + " </head>" + " <body>" + PMD.EOL
+ "<h2>Package View</h2>"
+ "<table border=\"1\" align=\"center\" cellspacing=\"0\" cellpadding=\"3\">" + " <tr>"
+ PMD.EOL + "<th>Package</th>" + "<th>Class</th>" + "<th>#</th>" + " </tr>" + PMD.EOL);
length = packageBuf.length();
}
super.visit(node);
if (node instanceof ViolationNode) {
renderViolation((ViolationNode) node);
}
if (node instanceof ClassNode) {
renderClass((ClassNode) node);
}
if (node instanceof PackageNode) {
renderPackage((PackageNode) node);
}
// The first node of result tree.
if (node.getParent() == null) {
packageBuf.append("</table> </body></html>");
try {
write("index.html", packageBuf);
} catch (Exception e) {
throw new RuntimeException("Error while writing HTML report: " + e.getMessage());
}
}
}
private void renderViolation(ViolationNode vnode) {
vnode.getParent().addNumberOfViolation(1);
RuleViolation vio = vnode.getRuleViolation();
classBuf.append("<tr>" + " <td>" + vio.getMethodName() + "</td>" + " <td>" + this.displayRuleViolation(vio)
+ "</td>" + "</tr>");
}
private void renderPackage(PackageNode pnode) {
String str;
// rootNode
if (pnode.getParent() == null) {
str = "Aggregate";
} else { // all the other nodes
str = pnode.getPackageName();
pnode.getParent().addNumberOfViolation(pnode.getNumberOfViolations());
}
packageBuf.insert(length, "<tr><td><b>" + str + "</b></td>" + " <td>-</td>" + " <td>"
+ pnode.getNumberOfViolations() + "</td>" + "</tr>" + PMD.EOL);
}
private void renderClass(ClassNode cnode) {
String str = cnode.getClassName();
classBuf.insert(0,
"<html><head><title>PMD - " + str + "</title></head><body>" + PMD.EOL + "<h2>Class View</h2>"
+ "<h3 align=\"center\">Class: " + str + "</h3>"
+ "<table border=\"\" align=\"center\" cellspacing=\"0\" cellpadding=\"3\">" + " <tr>" + PMD.EOL
+ "<th>Method</th>" + "<th>Violation</th>" + " </tr>" + PMD.EOL);
classBuf.append("</table>" + " </body>" + "</html>");
try {
write(str + ".html", classBuf);
} catch (Exception e) {
throw new RuntimeException("Error while writing HTML report: " + e.getMessage());
}
classBuf = new StringBuilder();
packageBuf.insert(this.length, "<tr>" + " <td>-</td>" + " <td><a href=\"" + str + ".html\">" + str + "</a></td>"
+ " <td>" + cnode.getNumberOfViolations() + "</td>" + "</tr>" + PMD.EOL);
cnode.getParent().addNumberOfViolation(cnode.getNumberOfViolations());
}
}