pmd: refactor renderers to use PropertyDescriptors

This commit is contained in:
Andreas Dangel
2012-10-26 20:13:20 +02:00
parent 940d5e36a8
commit a72c4f293c
15 changed files with 102 additions and 131 deletions

View File

@ -3,10 +3,6 @@
TODO - Release blockers - Must implement before this release can be finally finished
CODE:
o PropertyDescriptor final tasks:
- Report renderers now inherit from PropertySource so we should migrate the
old-style property references to use the new style. Ensure we remain
compatible with the online arguments that get passed in.
o Need to refactor the test framework to more readily support for multiple
Languages (too Java-centric at the moment). Then, need start adding tests
for the new XML language and other new languages.

View File

@ -7,11 +7,11 @@ import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
import net.sourceforge.pmd.util.StringUtil;
/**
@ -25,20 +25,20 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
public static final String NAME = "html";
public static final String LINK_PREFIX = "linkPrefix";
public static final String LINE_PREFIX = "linePrefix";
public static final StringProperty LINE_PREFIX = new StringProperty("linePrefix", "Prefix for line number anchor in the source file.", null, 1);
public static final StringProperty LINK_PREFIX = new StringProperty("linkPrefix", "Path to HTML source.", null, 0);
private final String linkPrefix;
private final String linePrefix;
private String linkPrefix;
private String linePrefix;
private int violationCount = 1;
boolean colorize = true;
public HTMLRenderer(Properties properties) {
public HTMLRenderer() {
super(NAME, "HTML format");
linkPrefix = properties.getProperty(LINK_PREFIX);
linePrefix = properties.getProperty(LINE_PREFIX);
definePropertyDescriptor(LINK_PREFIX);
definePropertyDescriptor(LINE_PREFIX);
}
public String defaultFileExtension() { return "html"; }
@ -51,6 +51,9 @@ public class HTMLRenderer extends AbstractIncrementingRenderer {
* @throws IOException
*/
public void renderBody(Writer writer, Report report) throws IOException {
linkPrefix = getProperty(LINK_PREFIX);
linePrefix = getProperty(LINE_PREFIX);
writer.write("<center><h3>PMD report</h3></center>");
writer.write("<center><h3>Problems found</h3></center>");
writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL

View File

@ -7,40 +7,35 @@ import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
/**
* Renderer for IntelliJ IDEA integration.
*/
public class IDEAJRenderer extends AbstractIncrementingRenderer {
private final String sourcePath;
private final String classAndMethodName;
private final String fileName;
private String classAndMethodName;
private String fileName;
public static final String NAME = "ideaj";
public static final String FILE_NAME = "fileName";
public static final String SOURCE_PATH = "sourcePath";
public static final String CLASS_AND_METHOD_NAME = "classAndMethodName";
public static final StringProperty FILE_NAME = new StringProperty("fileName", "File name.", "", 0);
public static final StringProperty SOURCE_PATH = new StringProperty("sourcePath", "Source path.", "", 1);
public static final StringProperty CLASS_AND_METHOD_NAME = new StringProperty("classAndMethodName", "Class and Method name, pass '.method' when processing a directory.", "", 2);
private static final String FILE_SEPARATOR = System.getProperty("file.separator");
private static final String PATH_SEPARATOR = System.getProperty("path.separator");
public IDEAJRenderer(Properties properties) {
public IDEAJRenderer() {
super(NAME, "IntelliJ IDEA integration.");
super.defineProperty(SOURCE_PATH, "Source path.");
super.defineProperty(CLASS_AND_METHOD_NAME, "Class and Method name, pass '.method' when processing a directory.");
super.defineProperty(FILE_NAME, "File name.");
sourcePath = properties.getProperty(SOURCE_PATH);
classAndMethodName = properties.getProperty(CLASS_AND_METHOD_NAME);
fileName = properties.getProperty(FILE_NAME);
definePropertyDescriptor(FILE_NAME);
definePropertyDescriptor(SOURCE_PATH);
definePropertyDescriptor(CLASS_AND_METHOD_NAME);
}
public String defaultFileExtension() { return "txt"; }
@ -50,6 +45,9 @@ public class IDEAJRenderer extends AbstractIncrementingRenderer {
*/
@Override
public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException {
classAndMethodName = getProperty(CLASS_AND_METHOD_NAME);
fileName = getProperty(FILE_NAME);
Writer writer = getWriter();
if (".method".equals(classAndMethodName)) {
// working on a directory tree
@ -61,7 +59,7 @@ public class IDEAJRenderer extends AbstractIncrementingRenderer {
}
private void renderDirectoy(Writer writer, Iterator<RuleViolation> violations) throws IOException {
SourcePath sourcePath = new SourcePath(this.sourcePath);
SourcePath sourcePath = new SourcePath(getProperty(SOURCE_PATH));
StringBuilder buf = new StringBuilder();
while (violations.hasNext()) {
buf.setLength(0);

View File

@ -5,7 +5,6 @@ package net.sourceforge.pmd.renderers;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
@ -16,19 +15,13 @@ public class SummaryHTMLRenderer extends AbstractAccumulatingRenderer {
public static final String NAME = "summaryhtml";
public static final String LINK_PREFIX = HTMLRenderer.LINK_PREFIX;
public static final String LINE_PREFIX = HTMLRenderer.LINE_PREFIX;
private Properties properties;
public SummaryHTMLRenderer(Properties properties) {
public SummaryHTMLRenderer() {
super(NAME, "Summary HTML format.");
this.properties = properties;
// These properties are defined here, but used by the HTMLRenderer
super.defineProperty(HTMLRenderer.LINK_PREFIX, "Path to HTML source.");
super.defineProperty(HTMLRenderer.LINE_PREFIX, "Prefix for line number anchor in the source file.");
// Note: we define the same properties as HTML Renderer
// we have to copy the values later from this renderer to the HTML Renderer
definePropertyDescriptor(HTMLRenderer.LINK_PREFIX);
definePropertyDescriptor(HTMLRenderer.LINE_PREFIX);
}
public String defaultFileExtension() { return "html"; }
@ -42,7 +35,12 @@ public class SummaryHTMLRenderer extends AbstractAccumulatingRenderer {
renderSummary();
writer.write("<h2><center>Detail</h2></center>");
writer.write("<table align=\"center\" cellspacing=\"0\" cellpadding=\"3\"><tr>" + PMD.EOL);
new HTMLRenderer(properties).renderBody(writer, report);
HTMLRenderer htmlRenderer = new HTMLRenderer();
htmlRenderer.setProperty(HTMLRenderer.LINK_PREFIX, getProperty(HTMLRenderer.LINK_PREFIX));
htmlRenderer.setProperty(HTMLRenderer.LINE_PREFIX, getProperty(HTMLRenderer.LINE_PREFIX));
htmlRenderer.renderBody(writer, report);
writer.write("</table></body></html>" + PMD.EOL);
}

View File

@ -15,6 +15,7 @@ import java.util.Map;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
import net.sourceforge.pmd.util.IOUtil;
/**
@ -49,9 +50,11 @@ import net.sourceforge.pmd.util.IOUtil;
*/
public class TextColorRenderer extends AbstractAccumulatingRenderer {
public static final String NAME = "textcolor";
public static final String COLOR = "color";
public static final StringProperty COLOR = new StringProperty("color", "Enables colors with anything other than 'false' or '0'.", "yes", 0);
private static final String SYSTEM_PROPERTY_PMD_COLOR = "pmd.color";
/**
* Directory from where java was invoked.
@ -69,7 +72,7 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer {
public TextColorRenderer() {
// This Renderer was originally submitted by Adrian Papari and was called the "PapariTextRenderer" pre-PMD 5.0.
super(NAME, "Text format, with color support (requires ANSI console support, e.g. xterm, rxvt, etc.).");
defineProperty(COLOR, "Enables colors with anything other than 'false' or '0'.");
definePropertyDescriptor(COLOR);
}
public String defaultFileExtension() { return "txt"; }
@ -82,8 +85,7 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer {
* btw, is it possible to do this on windows (ie; console colors)?
*/
private void initializeColorsIfSupported() {
if (System.getProperty("pmd.color") != null
&& !(System.getProperty("pmd.color").equals("0") || System.getProperty("pmd.color").equals("false"))) {
if (isPropertyEnabled(getProperty(COLOR)) || isPropertyEnabled(System.getProperty(SYSTEM_PROPERTY_PMD_COLOR))) {
this.yellowBold = "\u001B[1;33m";
this.whiteBold = "\u001B[1;37m";
this.redBold = "\u001B[1;31m";
@ -94,6 +96,10 @@ public class TextColorRenderer extends AbstractAccumulatingRenderer {
}
}
private boolean isPropertyEnabled(String property) {
return property != null && !(property.equals("0") || property.equalsIgnoreCase("false"));
}
/**
* {@inheritDoc}
*/

View File

@ -8,11 +8,11 @@ import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
import net.sourceforge.pmd.util.StringUtil;
/**
@ -22,23 +22,16 @@ public class XMLRenderer extends AbstractIncrementingRenderer {
public static final String NAME = "xml";
public static final String ENCODING = "encoding";
public static final StringProperty ENCODING = new StringProperty("encoding", "XML encoding format, defaults to UTF-8.", "UTF-8", 0);
// FIXME - hardcoded character encoding, booooooo
protected String encoding = "UTF-8";
public XMLRenderer(Properties properties) {
public XMLRenderer() {
super(NAME, "XML format.");
defineProperty(ENCODING, "XML encoding format, defaults to UTF-8.");
if (properties.containsKey(ENCODING)) {
encoding = properties.getProperty(ENCODING);
}
definePropertyDescriptor(ENCODING);
}
public XMLRenderer(String encoding) {
this(new Properties());
this.encoding = encoding;
this();
setProperty(ENCODING, encoding);
}
public String defaultFileExtension() { return "xml"; }
@ -48,6 +41,8 @@ public class XMLRenderer extends AbstractIncrementingRenderer {
*/
@Override
public void start() throws IOException {
String encoding = getProperty(ENCODING);
Writer writer = getWriter();
StringBuilder buf = new StringBuilder(500);
buf.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>").append(PMD.EOL);

View File

@ -4,15 +4,14 @@
package net.sourceforge.pmd.renderers;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@ -25,7 +24,10 @@ import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
@ -37,25 +39,17 @@ public class XSLTRenderer extends XMLRenderer {
public static final String NAME = "xslt";
public static final String XSLT_FILENAME = "xsltFilename";
public static final StringProperty XSLT_FILENAME = new StringProperty("xsltFilename", "The XSLT file name.", null, 0);
private Transformer transformer;
private String xsltFilename = "/etc/pmd-nicerhtml.xsl";
private Writer outputWriter;
public XSLTRenderer(Properties properties) {
super(properties);
super.setName(NAME);
super.setDescription("XML with a XSL Transformation applied.");
super.defineProperty(XSLT_FILENAME, "The XSLT file name.");
String xsltFilename = properties.getProperty(XSLT_FILENAME);
if (xsltFilename != null) {
File file = new File(xsltFilename);
if (file.exists() && file.canRead()) {
this.xsltFilename = xsltFilename;
}
}
public XSLTRenderer() {
super();
setName(NAME);
setDescription("XML with a XSL Transformation applied.");
definePropertyDescriptor(XSLT_FILENAME);
}
public String defaultFileExtension() { return "xsl"; }
@ -65,6 +59,14 @@ public class XSLTRenderer extends XMLRenderer {
*/
@Override
public void start() throws IOException {
String xsltFilename = getProperty(XSLT_FILENAME);
if (xsltFilename != null) {
File file = new File(xsltFilename);
if (file.exists() && file.canRead()) {
this.xsltFilename = xsltFilename;
}
}
// We keep the inital writer to put the final html output
this.outputWriter = getWriter();
// We use a new one to store the XML...
@ -118,13 +120,11 @@ public class XSLTRenderer extends XMLRenderer {
if (writer instanceof StringWriter) {
StringWriter w = (StringWriter) writer;
StringBuffer buffer = w.getBuffer();
// FIXME: If we change the encoding in XMLRenderer, we should change this too !
InputStream xml = new ByteArrayInputStream(buffer.toString().getBytes(this.encoding));
Document doc = this.getDocument(xml);
Document doc = this.getDocument(buffer.toString());
this.transform(doc);
} else {
// Should not happen !
new RuntimeException("Wrong writer").printStackTrace();
throw new RuntimeException("Wrong writer");
}
}
@ -140,10 +140,10 @@ public class XSLTRenderer extends XMLRenderer {
}
}
private Document getDocument(InputStream xml) {
private Document getDocument(String xml) {
try {
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return parser.parse(xml);
return parser.parse(new InputSource(new StringReader(xml)));
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {

View File

@ -4,11 +4,11 @@
package net.sourceforge.pmd.renderers;
import java.io.IOException;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.lang.dfa.report.ReportHTMLPrintVisitor;
import net.sourceforge.pmd.lang.dfa.report.ReportTree;
import net.sourceforge.pmd.lang.rule.properties.StringProperty;
/**
* Renderer to another HTML format.
@ -17,16 +17,12 @@ public class YAHTMLRenderer extends AbstractAccumulatingRenderer {
public static final String NAME = "yahtml";
public static final String OUTPUT_DIR = "outputDir";
public static final StringProperty OUTPUT_DIR = new StringProperty("outputDir", "Output directory.", null, 0);
private String outputDir;
public YAHTMLRenderer(Properties properties) {
public YAHTMLRenderer() {
// YA = Yet Another?
super(NAME, "Yet Another HTML format.");
defineProperty(OUTPUT_DIR, "Output directory.");
this.outputDir = properties.getProperty(OUTPUT_DIR);
definePropertyDescriptor(OUTPUT_DIR);
}
public String defaultFileExtension() { return "html"; }
@ -36,6 +32,7 @@ public class YAHTMLRenderer extends AbstractAccumulatingRenderer {
*/
@Override
public void end() throws IOException {
String outputDir = getProperty(OUTPUT_DIR);
ReportTree tree = report.getViolationTree();
tree.getRootNode().accept(new ReportHTMLPrintVisitor(outputDir == null ? ".." : outputDir));
writer.write("<h3 align=\"center\">The HTML files are located "

View File

@ -11,15 +11,8 @@ import java.io.IOException;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import junit.framework.JUnit4TestAdapter;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.ReportListener;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.DummyJavaNode;
@ -93,7 +86,7 @@ public class ReportTest extends RuleTst implements ReportListener {
r.addMetric(new Metric("m1", 0, 0.0, 1.0, 2.0, 3.0, 4.0));
assertTrue("Expected metrics weren't there", r.hasMetrics());
Iterator ms = r.metrics();
Iterator<Metric> ms = r.metrics();
assertTrue("Should have some metrics in there now", ms.hasNext());
Object o = ms.next();
@ -166,7 +159,7 @@ public class ReportTest extends RuleTst implements ReportListener {
JavaNode s1 = getNode(10, 5, ctx.getSourceCodeFilename());
Rule rule2 = new MockRule("name", "desc", "msg", "rulesetname");
r.addRuleViolation(new JavaRuleViolation(rule2, ctx, s1, rule2.getMessage()));
Renderer rend = new XMLRenderer(new Properties());
Renderer rend = new XMLRenderer();
String result = render(rend, r);
assertTrue("sort order wrong", result.indexOf("bar") < result.indexOf("foo"));
}
@ -183,7 +176,7 @@ public class ReportTest extends RuleTst implements ReportListener {
JavaNode s1 = getNode(20, 5, ctx.getSourceCodeFilename());
Rule rule2 = new MockRule("rule1", "rule1", "msg", "rulesetname");
r.addRuleViolation(new JavaRuleViolation(rule2, ctx, s1, rule2.getMessage()));
Renderer rend = new XMLRenderer(new Properties());
Renderer rend = new XMLRenderer();
String result = render(rend, r);
assertTrue("sort order wrong", result.indexOf("rule2") < result.indexOf("rule1"));
}
@ -220,7 +213,7 @@ public class ReportTest extends RuleTst implements ReportListener {
JavaNode s2 = getNode(30, 5, ctx.getSourceCodeFilename());
r.addRuleViolation(new JavaRuleViolation(mr, ctx, s1, mr.getMessage()));
r.addRuleViolation(new JavaRuleViolation(mr, ctx, s2, mr.getMessage()));
Map summary = r.getSummary();
Map<String, Integer> summary = r.getSummary();
assertEquals(summary.keySet().size(), 2);
assertTrue(summary.values().contains(Integer.valueOf(1)));
assertTrue(summary.values().contains(Integer.valueOf(2)));

View File

@ -1,17 +1,13 @@
package net.sourceforge.pmd.renderers;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.renderers.HTMLRenderer;
import net.sourceforge.pmd.renderers.Renderer;
public class HTMLRendererTest extends AbstractRendererTst {
@Override
public Renderer getRenderer() {
return new HTMLRenderer(new Properties());
return new HTMLRenderer();
}
@Override

View File

@ -1,19 +1,15 @@
package net.sourceforge.pmd.renderers;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.renderers.IDEAJRenderer;
import net.sourceforge.pmd.renderers.Renderer;
public class IDEAJRendererTest extends AbstractRendererTst {
public Renderer getRenderer() {
Properties properties = new Properties();
properties.put(IDEAJRenderer.SOURCE_PATH, "");
properties.put(IDEAJRenderer.CLASS_AND_METHOD_NAME, "Foo <init>");
properties.put(IDEAJRenderer.FILE_NAME, "Foo.java");
return new IDEAJRenderer(properties);
Renderer result = new IDEAJRenderer();
result.setProperty(IDEAJRenderer.SOURCE_PATH, "");
result.setProperty(IDEAJRenderer.CLASS_AND_METHOD_NAME, "Foo <init>");
result.setProperty(IDEAJRenderer.FILE_NAME, "Foo.java");
return result;
}
public String getExpected() {

View File

@ -16,11 +16,13 @@ public class PapariTextRendererTest extends AbstractRendererTst {
}
public Renderer getRenderer() {
return new TextColorRenderer(){
TextColorRenderer result = new TextColorRenderer(){
protected Reader getReader(String sourceFile) throws FileNotFoundException {
return new StringReader("public class Foo {}");
}
};
result.setProperty(TextColorRenderer.COLOR, "false");
return result;
}
public String getExpected() {

View File

@ -1,20 +1,16 @@
package net.sourceforge.pmd.renderers;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.SummaryHTMLRenderer;
public class SummaryHTMLRendererTest extends AbstractRendererTst {
@Override
public Renderer getRenderer() {
Properties properties = new Properties();
properties.put(SummaryHTMLRenderer.LINK_PREFIX, "link_prefix");
properties.put(SummaryHTMLRenderer.LINE_PREFIX, "line_prefix");
return new SummaryHTMLRenderer(properties);
Renderer result = new SummaryHTMLRenderer();
result.setProperty(HTMLRenderer.LINK_PREFIX, "link_prefix");
result.setProperty(HTMLRenderer.LINE_PREFIX, "line_prefix");
return result;
}
@Override

View File

@ -8,7 +8,6 @@ import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@ -22,7 +21,6 @@ import net.sourceforge.pmd.RuleSets;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.renderers.XMLRenderer;
import net.sourceforge.pmd.testframework.RuleTst;
import org.junit.Test;
@ -120,7 +118,7 @@ public class XMLRendererTest extends RuleTst {
}
private Element parseRootElement(Report rpt) throws SAXException, IOException, ParserConfigurationException {
String result = ReportTest.render(new XMLRenderer(new Properties()), rpt);
String result = ReportTest.render(new XMLRenderer(), rpt);
return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(result))).getDocumentElement();
}

View File

@ -2,12 +2,9 @@ package net.sourceforge.pmd.renderers;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.YAHTMLRenderer;
import org.junit.After;
import org.junit.Before;
@ -51,9 +48,9 @@ public class YAHTMLRendererTest extends AbstractRendererTst {
@Override
public Renderer getRenderer() {
Properties properties = new Properties();
properties.put(YAHTMLRenderer.OUTPUT_DIR, outputDir);
return new YAHTMLRenderer(properties);
Renderer result = new YAHTMLRenderer();
result.setProperty(YAHTMLRenderer.OUTPUT_DIR, outputDir);
return result;
}
@Override