View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.lang.dfa.report;
5   
6   import java.io.BufferedWriter;
7   import java.io.File;
8   import java.io.FileWriter;
9   import java.io.IOException;
10  
11  import net.sourceforge.pmd.PMD;
12  import net.sourceforge.pmd.RuleViolation;
13  import net.sourceforge.pmd.util.StringUtil;
14  
15  import org.apache.commons.io.IOUtils;
16  
17  /**
18   * @author raik
19   *         <p/>
20   *         * Uses the generated result tree instead of the result list. The visitor
21   *         * traverses the tree and creates several html files. The "package view" file
22   *         * (index.html) displays an overview of packages, classes and the number of
23   *         * rule violations they contain. All the other html files represent a class
24   *         * and show detailed information about the violations.
25   */
26  public class ReportHTMLPrintVisitor extends ReportVisitor {
27  
28      @SuppressWarnings("PMD.AvoidStringBufferField")
29      private StringBuilder packageBuf = new StringBuilder();
30      @SuppressWarnings("PMD.AvoidStringBufferField")
31      private StringBuilder classBuf = new StringBuilder();
32      private int length;
33      private String baseDir;
34  
35      private static final String FILE_SEPARATOR = System.getProperty("file.separator");
36  
37      public ReportHTMLPrintVisitor(String baseDir) {
38          this.baseDir = baseDir;
39      }
40  
41      /**
42       * Writes the buffer to file.
43       */
44      private void write(String filename, StringBuilder buf) throws IOException {
45          BufferedWriter bw = new BufferedWriter(new FileWriter(new File(baseDir + FILE_SEPARATOR + filename)));
46          bw.write(buf.toString(), 0, buf.length());
47          IOUtils.closeQuietly(bw);
48      }
49      
50      /**
51       * Generates a html table with violation information.
52       */
53      private String displayRuleViolation(RuleViolation vio) {
54   
55      	StringBuilder sb = new StringBuilder(200);
56          sb.append("<table border=\"0\">");
57          renderViolationRow(sb, "Rule:", vio.getRule().getName());
58          renderViolationRow(sb, "Description:", vio.getDescription());
59  
60          if (StringUtil.isNotEmpty(vio.getVariableName())) {
61          	renderViolationRow(sb, "Variable:", vio.getVariableName());
62          }
63  
64          if (vio.getEndLine() > 0) {
65          	renderViolationRow(sb, "Line:", vio.getEndLine() + " and " + vio.getBeginLine());
66          } else {
67          	renderViolationRow(sb, "Line:", Integer.toString(vio.getBeginLine()));
68          }
69  
70          sb.append("</table>");
71          return sb.toString();
72      }
73  
74      // TODO - join the 21st century, include CSS attributes :)
75      private void renderViolationRow(StringBuilder sb, String fieldName, String fieldData) {
76      	sb.append("<tr><td><b>").append(fieldName).append("</b></td><td>").append(fieldData).append("</td></tr>");
77      }
78      
79      /**
80       * The visit method (Visitor Pattern). There are 3 types of ReportNodes:
81       * RuleViolation - contains a RuleViolation, Class - represents a class and
82       * contains the name of the class, Package - represents a package and
83       * contains the name(s) of the package.
84       */
85      public void visit(AbstractReportNode node) {
86  
87          /*
88           * The first node of result tree.
89           */
90          if (node.getParent() == null) {
91              packageBuf.insert(0,
92                      "<html>" +
93                      " <head>" +
94                      "   <title>PMD</title>" +
95                      " </head>" +
96                      " <body>" + PMD.EOL + 
97                      "<h2>Package View</h2>" +
98                      "<table border=\"1\" align=\"center\" cellspacing=\"0\" cellpadding=\"3\">" +
99                      " <tr>" + PMD.EOL + 
100                     "<th>Package</th>" +
101                     "<th>Class</th>" +
102                     "<th>#</th>" +
103                     " </tr>" + PMD.EOL);
104 
105             length = packageBuf.length();
106         }
107 
108         super.visit(node);
109 
110         if (node instanceof ViolationNode) {
111             renderViolation((ViolationNode)node);
112         }
113         if (node instanceof ClassNode) {
114             renderClass((ClassNode)node);
115         }
116         if (node instanceof PackageNode) {
117             renderPackage((PackageNode)node);
118         }
119         
120         // The first node of result tree.
121         if (node.getParent() == null) {
122             packageBuf.append("</table> </body></html>");
123             try {
124                 write("index.html", packageBuf);
125             } catch (Exception e) {
126                 throw new RuntimeException("Error while writing HTML report: " + e.getMessage());
127             }
128         }
129     }
130 
131 	private void renderViolation(ViolationNode vnode) {
132 
133 		vnode.getParent().addNumberOfViolation(1);
134 		RuleViolation vio = vnode.getRuleViolation();
135 		classBuf.append("<tr>" +
136 		        " <td>" + vio.getMethodName() + "</td>" +
137 		        " <td>" + this.displayRuleViolation(vio) + "</td>" +
138 		        "</tr>");
139 	}
140 
141 	private void renderPackage(PackageNode pnode) {
142 
143 		String str;
144 
145 		// rootNode
146 		if (pnode.getParent() == null) {
147 		    str = "Aggregate";
148 		} else {           // all the other nodes
149 		    str = pnode.getPackageName();
150 		    pnode.getParent().addNumberOfViolation(pnode.getNumberOfViolations());
151 		}
152 
153 		packageBuf.insert(length,
154 		        "<tr><td><b>" + str + "</b></td>" +
155 		        " <td>-</td>" +
156 		        " <td>" + pnode.getNumberOfViolations() + "</td>" +
157 		        "</tr>" + PMD.EOL);
158 	}
159 
160 	private void renderClass(ClassNode cnode) {
161 
162 		String str = cnode.getClassName();
163 
164 		classBuf.insert(0,
165 		        "<html><head><title>PMD - " + str + "</title></head><body>" + PMD.EOL + 
166 		        "<h2>Class View</h2>" +
167 		        "<h3 align=\"center\">Class: " + str + "</h3>" +
168 		        "<table border=\"\" align=\"center\" cellspacing=\"0\" cellpadding=\"3\">" +
169 		        " <tr>" + PMD.EOL + 
170 		        "<th>Method</th>" +
171 		        "<th>Violation</th>" +
172 		        " </tr>" + PMD.EOL);
173 
174 		classBuf.append("</table>" +
175 		        " </body>" +
176 		        "</html>");
177 
178 
179 		try {
180 		    write(str + ".html", classBuf);
181 		} catch (Exception e) {
182 		    throw new RuntimeException("Error while writing HTML report: " + e.getMessage());
183 		}
184 		classBuf = new StringBuilder();
185 
186 		packageBuf.insert(this.length,
187 		        "<tr>" +
188 		        " <td>-</td>" +
189 		        " <td><a href=\"" + str + ".html\">" + str + "</a></td>" +
190 		        " <td>" + cnode.getNumberOfViolations() + "</td>" +
191 		        "</tr>" + PMD.EOL);
192 		cnode.getParent().addNumberOfViolation(cnode.getNumberOfViolations());
193 	}
194 }