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
109
110
111
112 private final ReportTree violationTree = new ReportTree();
113
114
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
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 }