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.util.ArrayList;
8   import java.util.HashMap;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Map;
12  
13  import net.sourceforge.pmd.PMD;
14  import net.sourceforge.pmd.PropertySource;
15  import net.sourceforge.pmd.RuleViolation;
16  import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
17  import net.sourceforge.pmd.renderers.ColumnDescriptor.Accessor;
18  import net.sourceforge.pmd.util.StringUtil;
19  
20  /**
21   * Renderer the results to a comma-delimited text format. All available columns
22   * are present by default. IDEs can enable/disable columns individually (cmd-line
23   * control to follow eventually)
24   */
25  public class CSVRenderer extends AbstractIncrementingRenderer {
26  
27      private String separator;
28      private String cr;
29  
30      private CSVWriter<RuleViolation> csvWriter;
31  
32      private static final String DefaultSeparator = ",";
33  
34      private static final Map<String, BooleanProperty> propertyDescriptorsById = new HashMap<String, BooleanProperty>();
35  
36      public static final String NAME = "csv";
37  
38      @SuppressWarnings("unchecked")
39  	private static final ColumnDescriptor<RuleViolation>[] AllColumns = new ColumnDescriptor[] {
40      	new ColumnDescriptor<RuleViolation>("problem", 	"Problem", 		new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return Integer.toString(idx); }} ),
41      	new ColumnDescriptor<RuleViolation>("package",	"Package", 		new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return rv.getPackageName(); }} ),
42      	new ColumnDescriptor<RuleViolation>("file",		"File", 		new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return rv.getFilename(); }} ),
43      	new ColumnDescriptor<RuleViolation>("priority",	"Priority", 	new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return Integer.toString(rv.getRule().getPriority().getPriority()); }} ),
44      	new ColumnDescriptor<RuleViolation>("line",		"Line", 		new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return Integer.toString(rv.getBeginLine()); }} ),
45      	new ColumnDescriptor<RuleViolation>("desc",		"Description", 	new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return StringUtil.replaceString(rv.getDescription(), '\"', "'"); }} ),
46      	new ColumnDescriptor<RuleViolation>("ruleSet",	"Rule set", 	new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return rv.getRule().getRuleSetName(); }} ),
47      	new ColumnDescriptor<RuleViolation>("rule",		"Rule", 		new Accessor<RuleViolation>() { public String get(int idx, RuleViolation rv, String cr) { return rv.getRule().getName(); }} )
48      	};
49  
50  
51      private static BooleanProperty booleanPropertyFor(String id, String label) {
52  
53      	BooleanProperty prop = propertyDescriptorsById.get(id);
54      	if (prop != null) return prop;
55  
56      	prop = new BooleanProperty(id, "Include " + label + " column", true, 1.0f);
57      	propertyDescriptorsById.put(id, prop);
58      	return prop;
59      }
60  
61      public CSVRenderer(ColumnDescriptor<RuleViolation>[] columns, String theSeparator, String theCR) {
62      	super(NAME, "Comma-separated values tabular format.");
63  
64      	separator = theSeparator;
65      	cr = theCR;
66  
67      	for (ColumnDescriptor<RuleViolation> desc : columns) {
68      		definePropertyDescriptor(booleanPropertyFor(desc.id, desc.title));
69      		}
70      }
71  
72      private List<ColumnDescriptor<RuleViolation>> activeColumns() {
73  
74      	List<ColumnDescriptor<RuleViolation>> actives = new ArrayList<ColumnDescriptor<RuleViolation>>();
75  
76       	for (ColumnDescriptor<RuleViolation> desc : AllColumns) {
77      		BooleanProperty prop = booleanPropertyFor(desc.id, null);
78      		if (getProperty(prop)) {
79      			actives.add(desc);
80      			} else {
81  //    				System.out.println("disabled: " + prop);
82      			}
83      		}
84       	return actives;
85      }
86  
87      private CSVWriter<RuleViolation> csvWriter() {
88      	if (csvWriter != null) return csvWriter;
89  
90      	csvWriter = new CSVWriter<RuleViolation>(activeColumns(), separator, cr);
91      	return csvWriter;
92      }
93  
94      public CSVRenderer() {
95      	this( AllColumns, DefaultSeparator, PMD.EOL);
96      }
97  
98      /**
99       * {@inheritDoc}
100      */
101     @Override
102     public void start() throws IOException {
103     	csvWriter().writeTitles(getWriter());
104     }
105 
106     public String defaultFileExtension() { return "csv"; }
107 
108     /**
109      * {@inheritDoc}
110      */
111     @Override
112     public void renderFileViolations(Iterator<RuleViolation> violations) throws IOException {
113     	csvWriter().writeData(getWriter(), violations);
114     }
115 
116 	 /**
117 	  * We can't show any violations if we don't have any visible columns.
118 	  *
119 	  * @see PropertySource#dysfunctionReason()
120 	  */
121     @Override
122 	 public String dysfunctionReason() {
123 		 return activeColumns().isEmpty() ? "No columns selected" : null;
124 	 }
125 }