View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd;
5   
6   import net.sourceforge.pmd.dfa.report.ReportTree;
7   import net.sourceforge.pmd.stat.Metric;
8   import net.sourceforge.pmd.util.NumericConstants;
9   
10  import java.util.ArrayList;
11  import java.util.HashMap;
12  import java.util.HashSet;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  import java.util.TreeSet;
18  
19  public class Report {
20  
21      public static class ReadableDuration {
22          private final long duration;
23  
24          public ReadableDuration(long duration) {
25              this.duration = duration;
26          }
27  
28          public String getTime() {
29              long seconds = 0;
30              long minutes = 0;
31              long hours = 0;
32  
33              if (duration > 1000) {
34                  seconds = duration / 1000;
35              }
36  
37              if (seconds > 60) {
38                  minutes = seconds / 60;
39                  seconds = seconds % 60;
40              }
41  
42              if (minutes > 60) {
43                  hours = minutes / 60;
44                  minutes = minutes % 60;
45              }
46  
47              StringBuffer res = new StringBuffer();
48              if (hours > 0) {
49                  res.append(hours).append("h ");
50              }
51              if (hours > 0 || minutes > 0) {
52                  res.append(minutes).append("m ");
53              }
54              res.append(seconds).append('s');
55              return res.toString();
56          }
57      }
58  
59      public static class ProcessingError {
60          private final String msg;
61          private final String file;
62  
63          public ProcessingError(String msg, String file) {
64              this.msg = msg;
65              this.file = file;
66          }
67  
68          public String getMsg() {
69              return msg;
70          }
71  
72          public String getFile() {
73              return file;
74          }
75      }
76  
77      public static class SuppressedViolation {
78          private final IRuleViolation rv;
79          private final boolean isNOPMD;
80          private final String userMessage;
81  
82          public SuppressedViolation(IRuleViolation rv, boolean isNOPMD, String userMessage) {
83              this.isNOPMD = isNOPMD;
84              this.rv = rv;
85              this.userMessage = userMessage;
86          }
87  
88          public boolean suppressedByNOPMD() {
89              return this.isNOPMD;
90          }
91  
92          public boolean suppressedByAnnotation() {
93              return !this.isNOPMD;
94          }
95  
96          public IRuleViolation getRuleViolation() {
97              return this.rv;
98          }
99  
100         public String getUserMessage() {
101             return userMessage;
102         }
103     }
104 
105     private static final RuleViolation.RuleViolationComparator COMPARATOR = new RuleViolation.RuleViolationComparator();
106 
107     /*
108      * The idea is to store the violations in a tree instead of a list, to do
109      * better and faster sort and filter mechanism and to visualize the result
110      * als tree. (ide plugins).
111      * */
112     private final ReportTree violationTree = new ReportTree();
113 
114     // Note that this and the above data structure are both being maintained for a bit
115     private final Set<IRuleViolation> violations = new TreeSet<IRuleViolation>(COMPARATOR);
116     private final Set<Metric> metrics = new HashSet<Metric>();
117     private final List<ReportListener> listeners = new ArrayList<ReportListener>();
118     private final List<ProcessingError> errors = new ArrayList<ProcessingError>();
119     private Map<Integer, String> linesToExclude = new HashMap<Integer, String>();
120     private long start;
121     private long end;
122 
123     private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<SuppressedViolation>();
124 
125     public void exclude(Map<Integer, String> lines) {
126         linesToExclude = lines;
127     }
128 
129     public Map<String, Integer> getCountSummary() {
130         Map<String, Integer> summary = new HashMap<String, Integer>();
131         for (Iterator<IRuleViolation> iter = violationTree.iterator(); iter.hasNext();) {
132             IRuleViolation rv = iter.next();
133             String key = "";
134             if (rv.getPackageName() != null && rv.getPackageName().length() != 0) {
135                 key = rv.getPackageName() + '.' + rv.getClassName();
136             }
137             Integer o = summary.get(key);
138             if (o == null) {
139                 summary.put(key, NumericConstants.ONE);
140             } else {
141                 summary.put(key, o+1);
142             }
143         }
144         return summary;
145     }
146 
147     public ReportTree getViolationTree() {
148         return this.violationTree;
149     }
150 
151 
152     /**
153      * @return a Map summarizing the Report: String (rule name) ->Integer (count of violations)
154      */
155     public Map<String, Integer> getSummary() {
156         Map<String, Integer> summary = new HashMap<String, Integer>();
157         for (IRuleViolation rv: violations) {
158             String name = rv.getRule().getName();
159             if (!summary.containsKey(name)) {
160                 summary.put(name, NumericConstants.ZERO);
161             }
162             Integer count = summary.get(name);
163             summary.put(name, count + 1);
164         }
165         return summary;
166     }
167 
168     public void addListener(ReportListener listener) {
169         listeners.add(listener);
170     }
171 
172     public List<SuppressedViolation> getSuppressedRuleViolations() {
173         return suppressedRuleViolations;
174     }
175 
176     public void addRuleViolation(IRuleViolation violation) {
177 
178         // NOPMD excluder
179         int line = violation.getBeginLine();
180         if (linesToExclude.containsKey(line)) {
181             suppressedRuleViolations.add(new SuppressedViolation(violation, true, linesToExclude.get(line)));
182             return;
183         }
184 
185         if (violation.isSuppressed()) {
186             suppressedRuleViolations.add(new SuppressedViolation(violation, false, null));
187             return;
188         }
189 
190 
191         violations.add(violation);
192         violationTree.addRuleViolation(violation);
193         for (ReportListener listener: listeners) {
194             listener.ruleViolationAdded(violation);
195         }
196     }
197 
198     public void addMetric(Metric metric) {
199         metrics.add(metric);
200         for (ReportListener listener: listeners) {
201             listener.metricAdded(metric);
202         }
203     }
204 
205     public void addError(ProcessingError error) {
206         errors.add(error);
207     }
208 
209     public void merge(Report r) {
210         Iterator<ProcessingError> i = r.errors();
211         while (i.hasNext()) {
212             addError(i.next());
213         }
214         Iterator<Metric> m = r.metrics();
215         while (m.hasNext()) {
216             addMetric(m.next());
217         }
218         Iterator<IRuleViolation> v = r.iterator();
219         while (v.hasNext()) {
220             IRuleViolation violation = v.next();
221             violations.add(violation);
222             violationTree.addRuleViolation(violation);
223         }
224         Iterator<SuppressedViolation> s = r.getSuppressedRuleViolations().iterator();
225         while (s.hasNext()) {
226             suppressedRuleViolations.add(s.next());
227         }
228     }
229 
230     public boolean hasMetrics() {
231         return !metrics.isEmpty();
232     }
233 
234     public Iterator<Metric> metrics() {
235         return metrics.iterator();
236     }
237 
238     public boolean isEmpty() {
239         return !violations.iterator().hasNext() && errors.isEmpty();
240     }
241 
242     public boolean treeIsEmpty() {
243         return !violationTree.iterator().hasNext();
244     }
245 
246     public Iterator<IRuleViolation> treeIterator() {
247         return violationTree.iterator();
248     }
249 
250     public Iterator<IRuleViolation> iterator() {
251         return violations.iterator();
252     }
253 
254     public Iterator<ProcessingError> errors() {
255         return errors.iterator();
256     }
257 
258     public int treeSize() {
259         return violationTree.size();
260     }
261 
262     public int size() {
263         return violations.size();
264     }
265 
266     public void start() {
267         start = System.currentTimeMillis();
268     }
269 
270     public void end() {
271         end = System.currentTimeMillis();
272     }
273 
274     public long getElapsedTimeInMillis() {
275         return end - start;
276     }
277 }