001: /**
002: * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003: */package net.sourceforge.pmd;
004:
005: import net.sourceforge.pmd.dfa.report.ReportTree;
006: import net.sourceforge.pmd.stat.Metric;
007: import net.sourceforge.pmd.util.NumericConstants;
008:
009: import java.util.ArrayList;
010: import java.util.HashMap;
011: import java.util.HashSet;
012: import java.util.Iterator;
013: import java.util.List;
014: import java.util.Map;
015: import java.util.Set;
016: import java.util.TreeSet;
017:
018: public class Report {
019:
020: public static class ReadableDuration {
021: private final long duration;
022:
023: public ReadableDuration(long duration) {
024: this .duration = duration;
025: }
026:
027: public String getTime() {
028: long seconds = 0;
029: long minutes = 0;
030: long hours = 0;
031:
032: if (duration > 1000) {
033: seconds = duration / 1000;
034: }
035:
036: if (seconds > 60) {
037: minutes = seconds / 60;
038: seconds = seconds % 60;
039: }
040:
041: if (minutes > 60) {
042: hours = minutes / 60;
043: minutes = minutes % 60;
044: }
045:
046: StringBuffer res = new StringBuffer();
047: if (hours > 0) {
048: res.append(hours).append("h ");
049: }
050: if (hours > 0 || minutes > 0) {
051: res.append(minutes).append("m ");
052: }
053: res.append(seconds).append('s');
054: return res.toString();
055: }
056: }
057:
058: public static class ProcessingError {
059: private final String msg;
060: private final String file;
061:
062: public ProcessingError(String msg, String file) {
063: this .msg = msg;
064: this .file = file;
065: }
066:
067: public String getMsg() {
068: return msg;
069: }
070:
071: public String getFile() {
072: return file;
073: }
074: }
075:
076: public static class SuppressedViolation {
077: private final IRuleViolation rv;
078: private final boolean isNOPMD;
079: private final String userMessage;
080:
081: public SuppressedViolation(IRuleViolation rv, boolean isNOPMD,
082: String userMessage) {
083: this .isNOPMD = isNOPMD;
084: this .rv = rv;
085: this .userMessage = userMessage;
086: }
087:
088: public boolean suppressedByNOPMD() {
089: return this .isNOPMD;
090: }
091:
092: public boolean suppressedByAnnotation() {
093: return !this .isNOPMD;
094: }
095:
096: public IRuleViolation getRuleViolation() {
097: return this .rv;
098: }
099:
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>(
116: COMPARATOR);
117: private final Set<Metric> metrics = new HashSet<Metric>();
118: private final List<ReportListener> listeners = new ArrayList<ReportListener>();
119: private final List<ProcessingError> errors = new ArrayList<ProcessingError>();
120: private Map<Integer, String> linesToExclude = new HashMap<Integer, String>();
121: private long start;
122: private long end;
123:
124: private List<SuppressedViolation> suppressedRuleViolations = new ArrayList<SuppressedViolation>();
125:
126: public void exclude(Map<Integer, String> lines) {
127: linesToExclude = lines;
128: }
129:
130: public Map<String, Integer> getCountSummary() {
131: Map<String, Integer> summary = new HashMap<String, Integer>();
132: for (Iterator<IRuleViolation> iter = violationTree.iterator(); iter
133: .hasNext();) {
134: IRuleViolation rv = iter.next();
135: String key = "";
136: if (rv.getPackageName() != null
137: && rv.getPackageName().length() != 0) {
138: key = rv.getPackageName() + '.' + rv.getClassName();
139: }
140: Integer o = summary.get(key);
141: if (o == null) {
142: summary.put(key, NumericConstants.ONE);
143: } else {
144: summary.put(key, o + 1);
145: }
146: }
147: return summary;
148: }
149:
150: public ReportTree getViolationTree() {
151: return this .violationTree;
152: }
153:
154: /**
155: * @return a Map summarizing the Report: String (rule name) ->Integer (count of violations)
156: */
157: public Map<String, Integer> getSummary() {
158: Map<String, Integer> summary = new HashMap<String, Integer>();
159: for (IRuleViolation rv : violations) {
160: String name = rv.getRule().getName();
161: if (!summary.containsKey(name)) {
162: summary.put(name, NumericConstants.ZERO);
163: }
164: Integer count = summary.get(name);
165: summary.put(name, count + 1);
166: }
167: return summary;
168: }
169:
170: public void addListener(ReportListener listener) {
171: listeners.add(listener);
172: }
173:
174: public List<SuppressedViolation> getSuppressedRuleViolations() {
175: return suppressedRuleViolations;
176: }
177:
178: public void addRuleViolation(IRuleViolation violation) {
179:
180: // NOPMD excluder
181: int line = violation.getBeginLine();
182: if (linesToExclude.containsKey(line)) {
183: suppressedRuleViolations.add(new SuppressedViolation(
184: violation, true, linesToExclude.get(line)));
185: return;
186: }
187:
188: if (violation.isSuppressed()) {
189: suppressedRuleViolations.add(new SuppressedViolation(
190: violation, false, null));
191: return;
192: }
193:
194: violations.add(violation);
195: violationTree.addRuleViolation(violation);
196: for (ReportListener listener : listeners) {
197: listener.ruleViolationAdded(violation);
198: }
199: }
200:
201: public void addMetric(Metric metric) {
202: metrics.add(metric);
203: for (ReportListener listener : listeners) {
204: listener.metricAdded(metric);
205: }
206: }
207:
208: public void addError(ProcessingError error) {
209: errors.add(error);
210: }
211:
212: public void merge(Report r) {
213: Iterator<ProcessingError> i = r.errors();
214: while (i.hasNext()) {
215: addError(i.next());
216: }
217: Iterator<Metric> m = r.metrics();
218: while (m.hasNext()) {
219: addMetric(m.next());
220: }
221: Iterator<IRuleViolation> v = r.iterator();
222: while (v.hasNext()) {
223: IRuleViolation violation = v.next();
224: violations.add(violation);
225: violationTree.addRuleViolation(violation);
226: }
227: Iterator<SuppressedViolation> s = r
228: .getSuppressedRuleViolations().iterator();
229: while (s.hasNext()) {
230: suppressedRuleViolations.add(s.next());
231: }
232: }
233:
234: public boolean hasMetrics() {
235: return !metrics.isEmpty();
236: }
237:
238: public Iterator<Metric> metrics() {
239: return metrics.iterator();
240: }
241:
242: public boolean isEmpty() {
243: return !violations.iterator().hasNext() && errors.isEmpty();
244: }
245:
246: public boolean treeIsEmpty() {
247: return !violationTree.iterator().hasNext();
248: }
249:
250: public Iterator<IRuleViolation> treeIterator() {
251: return violationTree.iterator();
252: }
253:
254: public Iterator<IRuleViolation> iterator() {
255: return violations.iterator();
256: }
257:
258: public Iterator<ProcessingError> errors() {
259: return errors.iterator();
260: }
261:
262: public int treeSize() {
263: return violationTree.size();
264: }
265:
266: public int size() {
267: return violations.size();
268: }
269:
270: public void start() {
271: start = System.currentTimeMillis();
272: }
273:
274: public void end() {
275: end = System.currentTimeMillis();
276: }
277:
278: public long getElapsedTimeInMillis() {
279: return end - start;
280: }
281: }
|