forked from phoedos/pmd
pmd: fix #1037 Facing a showstopper issue in PMD Report Class
* wrapping the report listeners in a thread safe (synchronized) class * overtaking the listeners for each thread / report
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
???? ??, 2012 - 5.0.2:
|
???? ??, 2012 - 5.0.2:
|
||||||
|
|
||||||
Fixed bug 1026: PMD doesn't handle 'value =' in SuppressWarnings annotation
|
Fixed bug 1026: PMD doesn't handle 'value =' in SuppressWarnings annotation
|
||||||
|
Fixed bug 1037: Facing a showstopper issue in PMD Report Class (report listeners)
|
||||||
Fixed bug 1043: node.getEndLine() always returns 0 (ECMAscript)
|
Fixed bug 1043: node.getEndLine() always returns 0 (ECMAscript)
|
||||||
Fixed bug 1044: Unknown option: -excludemarker
|
Fixed bug 1044: Unknown option: -excludemarker
|
||||||
Fixed bug 1047: False Positive in 'for' loops for LocalVariableCouldBeFinal in 5.0.1
|
Fixed bug 1047: False Positive in 'for' loops for LocalVariableCouldBeFinal in 5.0.1
|
||||||
|
@ -22,15 +22,18 @@ import net.sourceforge.pmd.util.StringUtil;
|
|||||||
|
|
||||||
public class Report {
|
public class Report {
|
||||||
|
|
||||||
public static Report createReport(RuleContext ctx, String fileName) {
|
public static Report createReport(RuleContext ctx, String fileName) {
|
||||||
|
Report report = new Report();
|
||||||
Report report = new Report();
|
|
||||||
ctx.setReport(report);
|
// overtake the listener
|
||||||
ctx.setSourceCodeFilename(fileName);
|
report.addSynchronizedListeners(ctx.getReport().getSynchronizedListeners());
|
||||||
ctx.setSourceCodeFile(new File(fileName));
|
|
||||||
return report;
|
ctx.setReport(report);
|
||||||
}
|
ctx.setSourceCodeFilename(fileName);
|
||||||
|
ctx.setSourceCodeFile(new File(fileName));
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
public static class ReadableDuration {
|
public static class ReadableDuration {
|
||||||
private final long duration;
|
private final long duration;
|
||||||
|
|
||||||
@ -112,7 +115,7 @@ public class Report {
|
|||||||
// Note that this and the above data structure are both being maintained for a bit
|
// Note that this and the above data structure are both being maintained for a bit
|
||||||
private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
|
private final List<RuleViolation> violations = new ArrayList<RuleViolation>();
|
||||||
private final Set<Metric> metrics = new HashSet<Metric>();
|
private final Set<Metric> metrics = new HashSet<Metric>();
|
||||||
private final List<ReportListener> listeners = new ArrayList<ReportListener>();
|
private final List<SynchronizedReportListener> listeners = new ArrayList<SynchronizedReportListener>();
|
||||||
private List<ProcessingError> errors;
|
private List<ProcessingError> errors;
|
||||||
private List<RuleConfigurationError> configErrors;
|
private List<RuleConfigurationError> configErrors;
|
||||||
private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
|
private Map<Integer, String> linesToSuppress = new HashMap<Integer, String>();
|
||||||
@ -164,7 +167,7 @@ public class Report {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(ReportListener listener) {
|
public void addListener(ReportListener listener) {
|
||||||
listeners.add(listener);
|
listeners.add(new SynchronizedReportListener(listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SuppressedViolation> getSuppressedRuleViolations() {
|
public List<SuppressedViolation> getSuppressedRuleViolations() {
|
||||||
@ -266,13 +269,13 @@ public class Report {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<ProcessingError> errors() {
|
public Iterator<ProcessingError> errors() {
|
||||||
return errors == null ? EmptyIterator.instance : errors.iterator();
|
return errors == null ? EmptyIterator.<ProcessingError> instance() : errors.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<RuleConfigurationError> configErrors() {
|
public Iterator<RuleConfigurationError> configErrors() {
|
||||||
return configErrors == null ? EmptyIterator.instance : errors.iterator();
|
return configErrors == null ? EmptyIterator.<RuleConfigurationError> instance() : configErrors.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int treeSize() {
|
public int treeSize() {
|
||||||
return violationTree.size();
|
return violationTree.size();
|
||||||
}
|
}
|
||||||
@ -292,4 +295,12 @@ public class Report {
|
|||||||
public long getElapsedTimeInMillis() {
|
public long getElapsedTimeInMillis() {
|
||||||
return end - start;
|
return end - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SynchronizedReportListener> getSynchronizedListeners() {
|
||||||
|
return listeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSynchronizedListeners(List<SynchronizedReportListener> synchronizedListeners) {
|
||||||
|
listeners.addAll(synchronizedListeners);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,10 +42,11 @@ public class RuleContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor which shares attributes with the given RuleContext.
|
* Constructor which shares attributes and report listeners with the given RuleContext.
|
||||||
*/
|
*/
|
||||||
public RuleContext(RuleContext ruleContext) {
|
public RuleContext(RuleContext ruleContext) {
|
||||||
this.attributes = ruleContext.attributes;
|
this.attributes = ruleContext.attributes;
|
||||||
|
this.report.addSynchronizedListeners(ruleContext.getReport().getSynchronizedListeners());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||||
|
*/
|
||||||
|
package net.sourceforge.pmd;
|
||||||
|
|
||||||
|
import net.sourceforge.pmd.stat.Metric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a report listener in order to synchronize calls to it.
|
||||||
|
*/
|
||||||
|
public final class SynchronizedReportListener implements ReportListener {
|
||||||
|
|
||||||
|
private final ReportListener wrapped;
|
||||||
|
|
||||||
|
public SynchronizedReportListener(ReportListener listener) {
|
||||||
|
this.wrapped = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void ruleViolationAdded(RuleViolation ruleViolation) {
|
||||||
|
wrapped.ruleViolationAdded(ruleViolation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void metricAdded(Metric metric) {
|
||||||
|
wrapped.metricAdded(metric);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,3 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||||
|
*/
|
||||||
package net.sourceforge.pmd.util;
|
package net.sourceforge.pmd.util;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -9,10 +12,15 @@ import java.util.Iterator;
|
|||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public class EmptyIterator<T extends Object> implements Iterator<T> {
|
public class EmptyIterator<T extends Object> implements Iterator<T> {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public static final Iterator instance = new EmptyIterator();
|
public static final Iterator instance = new EmptyIterator();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static final <T extends Object> Iterator<T> instance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
private EmptyIterator() {}
|
private EmptyIterator() {}
|
||||||
|
|
||||||
@ -23,4 +31,4 @@ public class EmptyIterator<T extends Object> implements Iterator<T> {
|
|||||||
public void remove() {
|
public void remove() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
};
|
}
|
Reference in New Issue
Block a user