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 }