KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > SortedBugCollection


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003-2005 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs;
21
22 import java.io.BufferedInputStream JavaDoc;
23 import java.io.BufferedOutputStream JavaDoc;
24 import java.io.BufferedReader JavaDoc;
25 import java.io.ByteArrayInputStream JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.FileInputStream JavaDoc;
28 import java.io.FileOutputStream JavaDoc;
29 import java.io.IOException JavaDoc;
30 import java.io.InputStream JavaDoc;
31 import java.io.InputStreamReader JavaDoc;
32 import java.io.OutputStream JavaDoc;
33 import java.io.Reader JavaDoc;
34 import java.io.StringWriter JavaDoc;
35 import java.math.BigInteger JavaDoc;
36 import java.security.MessageDigest JavaDoc;
37 import java.util.Collection JavaDoc;
38 import java.util.Comparator JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.HashSet JavaDoc;
41 import java.util.Iterator JavaDoc;
42 import java.util.LinkedList JavaDoc;
43 import java.util.List JavaDoc;
44 import java.util.Map JavaDoc;
45 import java.util.Set JavaDoc;
46 import java.util.SortedSet JavaDoc;
47 import java.util.TreeMap JavaDoc;
48 import java.util.TreeSet JavaDoc;
49 import java.util.zip.GZIPInputStream JavaDoc;
50
51 import javax.xml.transform.TransformerException JavaDoc;
52
53 import org.dom4j.Document;
54 import org.dom4j.DocumentException;
55 import org.dom4j.DocumentFactory;
56 import org.xml.sax.InputSource JavaDoc;
57 import org.xml.sax.SAXException JavaDoc;
58 import org.xml.sax.SAXParseException JavaDoc;
59 import org.xml.sax.XMLReader JavaDoc;
60 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
61
62 import edu.umd.cs.findbugs.annotations.CheckForNull;
63 import edu.umd.cs.findbugs.ba.MissingClassException;
64 import edu.umd.cs.findbugs.model.ClassFeatureSet;
65 import edu.umd.cs.findbugs.xml.Dom4JXMLOutput;
66 import edu.umd.cs.findbugs.xml.OutputStreamXMLOutput;
67 import edu.umd.cs.findbugs.xml.XMLAttributeList;
68 import edu.umd.cs.findbugs.xml.XMLOutput;
69 import edu.umd.cs.findbugs.xml.XMLOutputUtil;
70
71 /**
72  * An implementation of {@link BugCollection} that keeps the BugInstances
73  * sorted by class (using the native comparison ordering of BugInstance's
74  * compareTo() method as a tie-breaker).
75  *
76  * @see BugInstance
77  * @author David Hovemeyer
78  */

79 public class SortedBugCollection implements BugCollection {
80     long analysisTimestamp = System.currentTimeMillis();
81     private boolean withMessages = false;
82     private static final boolean REPORT_SUMMARY_HTML =
83         SystemProperties.getBoolean("findbugs.report.SummaryHTML");
84
85     public long getAnalysisTimestamp() {
86         return analysisTimestamp;
87     }
88
89     public void setAnalysisTimestamp(long timestamp) {
90         analysisTimestamp = timestamp;
91     }
92
93     /**
94      * Add a Collection of BugInstances to this BugCollection object.
95      * This just calls add(BugInstance) for each instance in the input collection.
96      *
97      * @param collection the Collection of BugInstances to add
98      */

99     public void addAll(Collection JavaDoc<BugInstance> collection) {
100         for (BugInstance aCollection : collection) {
101             add(aCollection);
102         }
103     }
104
105     /**
106      * Add a Collection of BugInstances to this BugCollection object.
107      *
108      * @param collection the Collection of BugInstances to add
109      * @param updateActiveTime true if active time of added BugInstances should
110      * be updated to match collection: false if not
111      */

112     public void addAll(Collection JavaDoc<BugInstance> collection, boolean updateActiveTime) {
113         for (BugInstance warning : collection) {
114             add(warning, updateActiveTime);
115         }
116     }
117
118     /**
119      * Add a BugInstance to this BugCollection.
120      * This just calls add(bugInstance, true).
121      *
122      * @param bugInstance the BugInstance
123      * @return true if the BugInstance was added, or false if a matching
124      * BugInstance was already in the BugCollection
125      */

126     public boolean add(BugInstance bugInstance) {
127         return add(bugInstance, true);
128     }
129
130     /**
131      * Add an analysis error.
132      *
133      * @param message the error message
134      */

135     public void addError(String JavaDoc message) {
136         addError(message, null);
137     }
138
139     /**
140      * Get the current AppVersion.
141      */

142     public AppVersion getCurrentAppVersion() {
143         return new AppVersion(getSequenceNumber())
144             .setReleaseName(getReleaseName())
145             .setTimestamp(getTimestamp())
146             .setNumClasses(getProjectStats().getNumClasses())
147             .setCodeSize(getProjectStats().getCodeSize());
148     }
149
150     /**
151      * Read XML data from given file into this object,
152      * populating given Project as a side effect.
153      *
154      * @param fileName name of the file to read
155      * @param project the Project
156      */

157     public void readXML(String JavaDoc fileName, Project project)
158             throws IOException JavaDoc, DocumentException {
159         try {
160         InputStream JavaDoc in = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(fileName));
161         if (fileName.endsWith(".gz"))
162             in = new GZIPInputStream JavaDoc(in);
163         readXML(in, project);
164         } catch (IOException JavaDoc e) {
165             IOException JavaDoc e2 = new IOException JavaDoc("Error reading " + fileName + ": " + e.getMessage());
166             e2.setStackTrace(e.getStackTrace());
167             throw e2;
168         }
169     }
170
171     /**
172      * Read XML data from given file into this object,
173      * populating given Project as a side effect.
174      *
175      * @param file the file
176      * @param project the Project
177      */

178     public void readXML(File JavaDoc file, Project project)
179             throws IOException JavaDoc, DocumentException {
180         InputStream JavaDoc in = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(file));
181         if (file.getName().endsWith(".gz"))
182             in = new GZIPInputStream JavaDoc(in);
183         readXML(in, project);
184     }
185
186     /**
187      * Read XML data from given input stream into this
188      * object, populating the Project as a side effect.
189      * An attempt will be made to close the input stream
190      * (even if an exception is thrown).
191      *
192      * @param in the InputStream
193      * @param project the Project
194      */

195     public void readXML(InputStream JavaDoc in, Project project)
196             throws IOException JavaDoc, DocumentException {
197         if (in == null) throw new IllegalArgumentException JavaDoc();
198
199         try {
200             if (project == null) throw new IllegalArgumentException JavaDoc();
201             doReadXML(in, project);
202         } finally {
203             in.close();
204         }
205     }
206
207     private void doReadXML(InputStream JavaDoc in, Project project) throws IOException JavaDoc, DocumentException {
208
209         checkInputStream(in);
210
211         try {
212             SAXBugCollectionHandler handler = new SAXBugCollectionHandler(this, project);
213
214             
215             XMLReader JavaDoc xr = null;
216             if (false) try { // try this in 1.1.4
217
xr = XMLReaderFactory.createXMLReader();
218               } catch (SAXException JavaDoc e) {
219                 System.err.println(e.getMessage());
220               }
221             
222             if (xr == null) {
223                // FIXME: for now, use dom4j's XML parser
224
xr = new org.dom4j.io.aelfred.SAXDriver();
225                 }
226             xr.setContentHandler(handler);
227             xr.setErrorHandler(handler);
228
229             Reader JavaDoc reader = new InputStreamReader JavaDoc(in);
230
231             xr.parse(new InputSource JavaDoc(reader));
232         } catch (SAXParseException JavaDoc e) {
233             throw new DocumentException("Parse error at line " + e.getLineNumber()
234                     + " : " + e.getColumnNumber(), e);
235         } catch (SAXException JavaDoc e) {
236             // FIXME: throw SAXException from method?
237
throw new DocumentException("Sax error ", e);
238         }
239
240         // Presumably, project is now up-to-date
241
project.setModified(false);
242     }
243
244     /**
245      * Write this BugCollection to a file as XML.
246      *
247      * @param fileName the file to write to
248      * @param project the Project from which the BugCollection was generated
249      */

250     public void writeXML(String JavaDoc fileName, Project project) throws IOException JavaDoc {
251         BufferedOutputStream JavaDoc out = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(fileName));
252         writeXML(out, project);
253     }
254
255     /**
256      * Write this BugCollection to a file as XML.
257      *
258      * @param file the file to write to
259      * @param project the Project from which the BugCollection was generated
260      */

261     public void writeXML(File JavaDoc file, Project project) throws IOException JavaDoc {
262         BufferedOutputStream JavaDoc out = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(file));
263         writeXML(out, project);
264     }
265
266     /**
267      * Convert the BugCollection into a dom4j Document object.
268      *
269      * @param project the Project from which the BugCollection was generated
270      * @return the Document representing the BugCollection as a dom4j tree
271      */

272     public Document toDocument(Project project) {
273         DocumentFactory docFactory = new DocumentFactory();
274         Document document = docFactory.createDocument();
275         Dom4JXMLOutput treeBuilder = new Dom4JXMLOutput(document);
276
277         try {
278             writeXML(treeBuilder, project);
279         } catch (IOException JavaDoc e) {
280             // Can't happen
281
}
282
283         return document;
284     }
285
286     /**
287      * Write the BugCollection to given output stream as XML.
288      * The output stream will be closed, even if an exception is thrown.
289      *
290      * @param out the OutputStream to write to
291      * @param project the Project from which the BugCollection was generated
292      */

293     public void writeXML(OutputStream JavaDoc out, Project project) throws IOException JavaDoc {
294         XMLOutput xmlOutput;
295         if (withMessages) xmlOutput= new OutputStreamXMLOutput(out, "http://findbugs.sourceforge.net/xsl/default.xsl");
296         else xmlOutput= new OutputStreamXMLOutput(out);
297
298         writeXML(xmlOutput, project);
299     }
300
301     public void writePrologue(XMLOutput xmlOutput, Project project) throws IOException JavaDoc {
302         xmlOutput.beginDocument();
303         xmlOutput.openTag(ROOT_ELEMENT_NAME,
304             new XMLAttributeList()
305                 .addAttribute("version",Version.RELEASE)
306                 .addAttribute("sequence",String.valueOf(getSequenceNumber()))
307                 .addAttribute("timestamp", String.valueOf(getTimestamp()))
308                 .addAttribute("analysisTimestamp", String.valueOf(getAnalysisTimestamp()))
309
310                 .addAttribute("release", getReleaseName())
311         );
312         project.writeXML(xmlOutput);
313     }
314     
315     private String JavaDoc getQuickInstanceHash(BugInstance bugInstance) {
316         String JavaDoc hash = bugInstance.getInstanceHash();
317         if (hash != null) return hash;
318         MessageDigest JavaDoc digest = null;
319         try { digest = MessageDigest.getInstance("MD5");
320         } catch (Exception JavaDoc e2) {
321             // OK, we won't digest
322
assert true;
323         }
324         hash = bugInstance.getInstanceKey();
325         if (digest != null) {
326             byte [] data = digest.digest(hash.getBytes());
327             String JavaDoc tmp = new BigInteger JavaDoc(1,data).toString(16);
328             if (false) System.out.println(hash + " -> " + tmp);
329             hash = tmp;
330         }
331         bugInstance.setInstanceHash(hash);
332         return hash;
333     }
334
335     public void computeBugHashes() {
336         if (preciseHashOccurrenceNumbersAvailable) return;
337         invalidateHashes();
338         MessageDigest JavaDoc digest = null;
339         try { digest = MessageDigest.getInstance("MD5");
340         } catch (Exception JavaDoc e2) {
341             // OK, we won't digest
342
}
343         
344         HashMap JavaDoc<String JavaDoc, Integer JavaDoc> seen = new HashMap JavaDoc<String JavaDoc, Integer JavaDoc>();
345         
346         for(BugInstance bugInstance : getCollection()) {
347             String JavaDoc hash = bugInstance.getInstanceHash();
348             if (hash == null) {
349                 hash = bugInstance.getInstanceKey();
350
351                 if (digest != null) {
352                     byte [] data = digest.digest(hash.getBytes());
353                     String JavaDoc tmp = new BigInteger JavaDoc(1,data).toString(16);
354                     if (false) System.out.println(hash + " -> " + tmp);
355                     hash = tmp;
356                 }
357                 bugInstance.setInstanceHash(hash);
358             }
359             Integer JavaDoc count = seen.get(hash);
360             if (count == null) {
361                 bugInstance.setInstanceOccurrenceNum(0);
362                 seen.put(hash,0);
363             } else {
364                 bugInstance.setInstanceOccurrenceNum(count+1);
365                 seen.put(hash, count+1);
366             }
367         }
368         for(BugInstance bugInstance : getCollection())
369             bugInstance.setInstanceOccurrenceMax(seen.get(bugInstance.getInstanceHash()));
370         preciseHashOccurrenceNumbersAvailable = true;
371     }
372     /**
373      * Write the BugCollection to an XMLOutput object.
374      * The finish() method of the XMLOutput object is guaranteed
375      * to be called.
376      *
377      * <p>
378      * To write the SummaryHTML element, set property
379      * findbugs.report.SummaryHTML to "true".
380      * </p>
381      *
382      * @param xmlOutput the XMLOutput object
383      * @param project the Project from which the BugCollection was generated
384      */

385     public void writeXML(XMLOutput xmlOutput, Project project) throws IOException JavaDoc {
386         try {
387             writePrologue(xmlOutput, project);
388             if (withMessages) computeBugHashes();
389             
390             // Write BugInstances
391
for(BugInstance bugInstance : getCollection())
392                 bugInstance.writeXML(xmlOutput, withMessages);
393
394             writeEpilogue(xmlOutput);
395         } finally {
396             xmlOutput.finish();
397         }
398     }
399
400     public void writeEpilogue(XMLOutput xmlOutput) throws IOException JavaDoc {
401         if (withMessages) {
402             writeBugCategories( xmlOutput);
403             writeBugPatterns( xmlOutput);
404             writeBugCodes( xmlOutput);
405         }
406         // Errors, missing classes
407
emitErrors(xmlOutput);
408
409         // Statistics
410
getProjectStats().writeXML(xmlOutput);
411
412 // // Class and method hashes
413
// xmlOutput.openTag(CLASS_HASHES_ELEMENT_NAME);
414
// for (Iterator<ClassHash> i = classHashIterator(); i.hasNext();) {
415
// ClassHash classHash = i.next();
416
// classHash.writeXML(xmlOutput);
417
// }
418
// xmlOutput.closeTag(CLASS_HASHES_ELEMENT_NAME);
419

420         // Class features
421
xmlOutput.openTag("ClassFeatures");
422         for (Iterator JavaDoc<ClassFeatureSet> i = classFeatureSetIterator(); i.hasNext();) {
423             ClassFeatureSet classFeatureSet = i.next();
424             classFeatureSet.writeXML(xmlOutput);
425         }
426         xmlOutput.closeTag("ClassFeatures");
427
428         // AppVersions
429
xmlOutput.openTag(HISTORY_ELEMENT_NAME);
430         for (Iterator JavaDoc<AppVersion> i = appVersionIterator(); i.hasNext();) {
431             AppVersion appVersion = i.next();
432             appVersion.writeXML(xmlOutput);
433         }
434         xmlOutput.closeTag(HISTORY_ELEMENT_NAME);
435
436         // Summary HTML
437
if ( REPORT_SUMMARY_HTML ) {
438             String JavaDoc html = getSummaryHTML();
439             if (html != null && !html.equals("")) {
440                 xmlOutput.openTag(SUMMARY_HTML_ELEMENT_NAME);
441                 xmlOutput.writeCDATA(html);
442                 xmlOutput.closeTag(SUMMARY_HTML_ELEMENT_NAME);
443             }
444         }
445
446         xmlOutput.closeTag(ROOT_ELEMENT_NAME);
447     }
448
449     private void writeBugPatterns(XMLOutput xmlOutput) throws IOException JavaDoc {
450         // Find bug types reported
451
Set JavaDoc<String JavaDoc> bugTypeSet = new HashSet JavaDoc<String JavaDoc>();
452         for (Iterator JavaDoc<BugInstance> i = iterator(); i.hasNext();) {
453             BugInstance bugInstance = i.next();
454             BugPattern bugPattern = bugInstance.getBugPattern();
455             if (bugPattern != null) {
456                 bugTypeSet.add(bugPattern.getType());
457             }
458         }
459         // Emit element describing each reported bug pattern
460
for (String JavaDoc bugType : bugTypeSet) {
461             BugPattern bugPattern = I18N.instance().lookupBugPattern(bugType);
462             if (bugPattern == null)
463                 continue;
464
465             XMLAttributeList attributeList = new XMLAttributeList();
466             attributeList.addAttribute("type", bugType);
467             attributeList.addAttribute("abbrev", bugPattern.getAbbrev());
468             attributeList.addAttribute("category", bugPattern.getCategory());
469
470             xmlOutput.openTag("BugPattern", attributeList);
471
472             xmlOutput.openTag("ShortDescription");
473             xmlOutput.writeText(bugPattern.getShortDescription());
474             xmlOutput.closeTag("ShortDescription");
475
476             xmlOutput.openTag("Details");
477             xmlOutput.writeCDATA(bugPattern.getDetailText());
478             xmlOutput.closeTag("Details");
479
480             xmlOutput.closeTag("BugPattern");
481         }
482     }
483
484     private void writeBugCodes(XMLOutput xmlOutput) throws IOException JavaDoc {
485         // Find bug codes reported
486
Set JavaDoc<String JavaDoc> bugCodeSet = new HashSet JavaDoc<String JavaDoc>();
487         for (Iterator JavaDoc<BugInstance> i = iterator(); i.hasNext();) {
488             BugInstance bugInstance = i.next();
489             String JavaDoc bugCode = bugInstance.getAbbrev();
490             if (bugCode != null) {
491                 bugCodeSet.add(bugCode);
492             }
493         }
494         // Emit element describing each reported bug code
495
for (String JavaDoc bugCode : bugCodeSet) {
496             String JavaDoc bugCodeDescription = I18N.instance().getBugTypeDescription(bugCode);
497             if (bugCodeDescription == null)
498                 continue;
499
500             XMLAttributeList attributeList = new XMLAttributeList();
501             attributeList.addAttribute("abbrev", bugCode);
502
503             xmlOutput.openTag("BugCode", attributeList);
504
505             xmlOutput.openTag("Description");
506             xmlOutput.writeText(bugCodeDescription);
507             xmlOutput.closeTag("Description");
508
509             xmlOutput.closeTag("BugCode");
510         }
511     }
512
513     private void writeBugCategories(XMLOutput xmlOutput) throws IOException JavaDoc {
514         // Find bug categories reported
515
Set JavaDoc<String JavaDoc> bugCatSet = new HashSet JavaDoc<String JavaDoc>();
516         for (Iterator JavaDoc<BugInstance> i = iterator(); i.hasNext();) {
517             BugInstance bugInstance = i.next();
518             BugPattern bugPattern = bugInstance.getBugPattern();
519             if (bugPattern != null) {
520                 bugCatSet.add(bugPattern.getCategory());
521             }
522         }
523         // Emit element describing each reported bug code
524
for (String JavaDoc bugCat : bugCatSet) {
525             String JavaDoc bugCatDescription = I18N.instance().getBugCategoryDescription(bugCat);
526             if (bugCatDescription == null)
527                 continue;
528
529             XMLAttributeList attributeList = new XMLAttributeList();
530             attributeList.addAttribute("category", bugCat);
531
532             xmlOutput.openTag("BugCategory", attributeList);
533
534             xmlOutput.openTag("Description");
535             xmlOutput.writeText(bugCatDescription);
536             xmlOutput.closeTag("Description");
537
538             xmlOutput.closeTag("BugCategory");
539         }
540     }
541
542     private void emitErrors(XMLOutput xmlOutput) throws IOException JavaDoc {
543         //System.err.println("Writing errors to XML output");
544

545         xmlOutput.openTag(ERRORS_ELEMENT_NAME);
546
547         // Emit Error elements describing analysis errors
548
for (Iterator JavaDoc<AnalysisError> i = errorIterator(); i.hasNext(); ) {
549             AnalysisError error = i.next();
550             xmlOutput.openTag(ERROR_ELEMENT_NAME);
551
552             xmlOutput.openTag(ERROR_MESSAGE_ELEMENT_NAME);
553             xmlOutput.writeText(error.getMessage());
554             xmlOutput.closeTag(ERROR_MESSAGE_ELEMENT_NAME);
555
556             if (error.getExceptionMessage() != null) {
557                 xmlOutput.openTag(ERROR_EXCEPTION_ELEMENT_NAME);
558                 xmlOutput.writeText(error.getExceptionMessage());
559                 xmlOutput.closeTag(ERROR_EXCEPTION_ELEMENT_NAME);
560             }
561
562             String JavaDoc stackTrace[] = error.getStackTrace();
563             if (stackTrace != null) {
564                 for (String JavaDoc aStackTrace : stackTrace) {
565                     xmlOutput.openTag(ERROR_STACK_TRACE_ELEMENT_NAME);
566                     xmlOutput.writeText(aStackTrace);
567                     xmlOutput.closeTag(ERROR_STACK_TRACE_ELEMENT_NAME);
568                 }
569             }
570
571             xmlOutput.closeTag(ERROR_ELEMENT_NAME);
572         }
573
574         // Emit missing classes
575
XMLOutputUtil.writeElementList(xmlOutput, MISSING_CLASS_ELEMENT_NAME,
576             missingClassIterator());
577
578         xmlOutput.closeTag(ERRORS_ELEMENT_NAME);
579     }
580
581     private void checkInputStream(InputStream JavaDoc in) throws IOException JavaDoc {
582         if (in.markSupported()) {
583             byte[] buf = new byte[200];
584             in.mark(buf.length);
585
586             int numRead = 0;
587             while (numRead < buf.length) {
588                 int n = in.read(buf, numRead, buf.length - numRead);
589                 if (n < 0)
590                     throw new IOException JavaDoc("XML does not contain saved bug data");
591                 numRead += n;
592             }
593
594             in.reset();
595
596             BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(new ByteArrayInputStream JavaDoc(buf)));
597             String JavaDoc line;
598             while ((line = reader.readLine()) != null) {
599                 if (line.startsWith("<BugCollection"))
600                     return;
601             }
602
603             throw new IOException JavaDoc("XML does not contain saved bug data");
604         }
605     }
606
607     /**
608      * Clone all of the BugInstance objects in the source Collection
609      * and add them to the destination Collection.
610      *
611      * @param dest the destination Collection
612      * @param source the source Collection
613      */

614     public static void cloneAll(Collection JavaDoc<BugInstance> dest, Collection JavaDoc<BugInstance> source) {
615         for (BugInstance obj : source) {
616             dest.add((BugInstance) obj.clone());
617         }
618     }
619
620     public static class BugInstanceComparator implements Comparator JavaDoc<BugInstance> {
621         private BugInstanceComparator() {}
622         public int compare(BugInstance lhs, BugInstance rhs) {
623             ClassAnnotation lca = lhs.getPrimaryClass();
624             ClassAnnotation rca = rhs.getPrimaryClass();
625             if (lca == null || rca == null)
626                 throw new IllegalStateException JavaDoc("null class annotation: " + lca + "," + rca);
627             int cmp = lca.getClassName().compareTo(rca.getClassName());
628             if (cmp != 0)
629                 return cmp;
630             return lhs.compareTo(rhs);
631         }
632         public static final BugInstanceComparator instance = new BugInstanceComparator();
633     }
634
635     public static class MultiversionBugInstanceComparator extends BugInstanceComparator {
636         @Override JavaDoc
637         public int compare(BugInstance lhs, BugInstance rhs) {
638             int result = super.compare(lhs,rhs);
639             if (result != 0) return result;
640             long diff = lhs.getFirstVersion() - rhs.getFirstVersion();
641             if (diff == 0)
642                 diff = lhs.getLastVersion() - rhs.getLastVersion();
643             if (diff < 0) return -1;
644             if (diff > 0) return 1;
645             return 0;
646         }
647         public static final MultiversionBugInstanceComparator instance = new MultiversionBugInstanceComparator();
648     }
649     private Comparator JavaDoc<BugInstance> comparator;
650     private TreeSet JavaDoc<BugInstance> bugSet;
651     private List JavaDoc<AnalysisError> errorList;
652     private TreeSet JavaDoc<String JavaDoc> missingClassSet;
653     @CheckForNull private String JavaDoc summaryHTML;
654     private ProjectStats projectStats;
655 // private Map<String, ClassHash> classHashMap;
656
private Map JavaDoc<String JavaDoc, ClassFeatureSet> classFeatureSetMap;
657     private List JavaDoc<AppVersion> appVersionList;
658
659     
660     private boolean preciseHashOccurrenceNumbersAvailable = false;
661     /**
662      * Sequence number of the most-recently analyzed version
663      * of the code.
664      */

665     private long sequence;
666     /**
667      * Release name of the analyzed application.
668      */

669     private String JavaDoc releaseName;
670     /**
671      * Current analysis timestamp.
672      */

673     private long timestamp;
674
675     /**
676      * Constructor.
677      * Creates an empty object.
678      */

679     public SortedBugCollection() {
680         this(new ProjectStats());
681     }
682
683     /**
684      * Constructor.
685      * Creates an empty object.
686      */

687     public SortedBugCollection(Comparator JavaDoc<BugInstance> comparator) {
688         this(new ProjectStats(), comparator);
689     }
690
691     /**
692      * Constructor.
693      * Creates an empty object given an existing ProjectStats.
694      *
695      * @param projectStats the ProjectStats
696      */

697     public SortedBugCollection(ProjectStats projectStats) {
698         this(projectStats, MultiversionBugInstanceComparator.instance);
699     }
700     /**
701      * Constructor.
702      * Creates an empty object given an existing ProjectStats.
703      *
704      * @param projectStats the ProjectStats
705      * @param comparator to use for sorting bug instances
706      */

707     public SortedBugCollection(ProjectStats projectStats, Comparator JavaDoc<BugInstance> comparator) {
708         this.projectStats = projectStats;
709         this.comparator = comparator;
710         bugSet = new TreeSet JavaDoc<BugInstance>(comparator);
711         errorList = new LinkedList JavaDoc<AnalysisError>();
712         missingClassSet = new TreeSet JavaDoc<String JavaDoc>();
713         summaryHTML = null;
714         classFeatureSetMap = new TreeMap JavaDoc<String JavaDoc, ClassFeatureSet>();
715         sequence = 0L;
716         appVersionList = new LinkedList JavaDoc<AppVersion>();
717         releaseName = "";
718         timestamp = -1L;
719     }
720
721     public boolean add(BugInstance bugInstance, boolean updateActiveTime) {
722         preciseHashOccurrenceNumbersAvailable = false;
723         if (updateActiveTime) {
724             bugInstance.setFirstVersion(sequence);
725         }
726
727         return bugSet.add(bugInstance);
728     }
729
730
731     
732     private void invalidateHashes() {
733         preciseHashOccurrenceNumbersAvailable = false;
734     }
735     public boolean remove(BugInstance bugInstance) {
736         invalidateHashes();
737         return bugSet.remove(bugInstance);
738     }
739
740     public Iterator JavaDoc<BugInstance> iterator() {
741         return bugSet.iterator();
742     }
743
744     public Collection JavaDoc<BugInstance> getCollection() {
745         return bugSet;
746     }
747
748     
749     public void addError(String JavaDoc message, Throwable JavaDoc exception) {
750         if (exception instanceof MissingClassException) {
751             MissingClassException e = (MissingClassException) exception;
752             addMissingClass(AbstractBugReporter.getMissingClassName(e.getClassNotFoundException()));
753             return;
754         }
755         if (exception instanceof ClassNotFoundException JavaDoc) {
756             ClassNotFoundException JavaDoc e = (ClassNotFoundException JavaDoc) exception;
757             addMissingClass(AbstractBugReporter.getMissingClassName(e));
758             return;
759         }
760         errorList.add(new AnalysisError(message, exception));
761     }
762
763
764     public void addError(AnalysisError error) {
765         errorList.add(error);
766     }
767
768     public void addMissingClass(String JavaDoc className) {
769         if (className.startsWith("[")) {
770             assert false : "Bad class name " + className;
771             return;
772         }
773         missingClassSet.add(className);
774     }
775
776     public Iterator JavaDoc<AnalysisError> errorIterator() {
777         return errorList.iterator();
778     }
779
780     public Iterator JavaDoc<String JavaDoc> missingClassIterator() {
781         return missingClassSet.iterator();
782     }
783
784     public boolean contains(BugInstance bugInstance) {
785         return bugSet.contains(bugInstance);
786     }
787
788     public BugInstance getMatching(BugInstance bugInstance) {
789         SortedSet JavaDoc<BugInstance> tailSet = bugSet.tailSet(bugInstance);
790         if (tailSet.isEmpty())
791             return null;
792         BugInstance first = tailSet.first();
793         return bugInstance.equals(first) ? first : null;
794     }
795
796     public String JavaDoc getSummaryHTML() throws IOException JavaDoc {
797         if ( summaryHTML == null ) {
798             try {
799                 StringWriter JavaDoc writer = new StringWriter JavaDoc();
800                 ProjectStats stats = getProjectStats();
801                 stats.transformSummaryToHTML(writer);
802                 summaryHTML = writer.toString();
803             } catch (final TransformerException JavaDoc e) {
804                 IOException JavaDoc ioe = new IOException JavaDoc("Couldn't generate summary HTML");
805                 ioe.initCause(e);
806                 throw ioe;
807             }
808         }
809
810         return summaryHTML;
811     }
812
813     public ProjectStats getProjectStats() {
814         return projectStats;
815     }
816
817     /* (non-Javadoc)
818          * @see edu.umd.cs.findbugs.BugCollection#lookupFromUniqueId(java.lang.String)
819          */

820     @Deprecated JavaDoc
821     public BugInstance lookupFromUniqueId(String JavaDoc uniqueId) {
822         for(BugInstance bug : bugSet)
823             if (bug.getInstanceHash().equals(uniqueId)) return bug;
824         return null;
825     }
826
827         public long getSequenceNumber() {
828         return sequence;
829     }
830
831     public void setSequenceNumber(long sequence) {
832         this.sequence = sequence;
833     }
834
835
836
837     public SortedBugCollection duplicate() {
838         SortedBugCollection dup = new SortedBugCollection((ProjectStats) projectStats.clone(), comparator);
839
840         SortedBugCollection.cloneAll(dup.bugSet, this.bugSet);
841         dup.errorList.addAll(this.errorList);
842         dup.missingClassSet.addAll(this.missingClassSet);
843         dup.summaryHTML = this.summaryHTML;
844 // dup.classHashMap.putAll(this.classHashMap);
845
dup.classFeatureSetMap.putAll(this.classFeatureSetMap);
846         dup.sequence = this.sequence;
847         dup.timestamp = this.timestamp;
848         dup.releaseName = this.releaseName;
849         for (AppVersion appVersion : appVersionList) {
850             dup.appVersionList.add((AppVersion) appVersion.clone());
851         }
852
853         return dup;
854     }
855
856     /* (non-Javadoc)
857      * @see edu.umd.cs.findbugs.BugCollection#clearBugInstances()
858      */

859
860     public void clearBugInstances() {
861         bugSet.clear();
862         invalidateHashes();
863
864     }
865
866     /* (non-Javadoc)
867          * @see edu.umd.cs.findbugs.BugCollection#getReleaseName()
868          */

869
870     public String JavaDoc getReleaseName() {
871         return releaseName;
872     }
873
874     /* (non-Javadoc)
875          * @see edu.umd.cs.findbugs.BugCollection#setReleaseName(java.lang.String)
876          */

877
878     public void setReleaseName(String JavaDoc releaseName) {
879         this.releaseName = releaseName;
880     }
881
882     /* (non-Javadoc)
883      * @see edu.umd.cs.findbugs.BugCollection#appVersionIterator()
884      */

885
886     public Iterator JavaDoc<AppVersion> appVersionIterator() {
887         return appVersionList.iterator();
888     }
889
890     /* (non-Javadoc)
891      * @see edu.umd.cs.findbugs.BugCollection#addAppVersion(edu.umd.cs.findbugs.AppVersion)
892      */

893
894     public void addAppVersion(AppVersion appVersion) {
895         appVersionList.add(appVersion);
896     }
897
898     /* (non-Javadoc)
899      * @see edu.umd.cs.findbugs.BugCollection#clearAppVersions()
900      */

901
902     public void clearAppVersions() {
903         appVersionList.clear();
904     }
905
906     /* (non-Javadoc)
907      * @see edu.umd.cs.findbugs.BugCollection#createEmptyCollectionWithMetadata()
908      */

909
910     public SortedBugCollection createEmptyCollectionWithMetadata() {
911         SortedBugCollection dup = new SortedBugCollection((ProjectStats) projectStats.clone(), comparator);
912         dup.errorList.addAll(this.errorList);
913         dup.missingClassSet.addAll(this.missingClassSet);
914         dup.summaryHTML = this.summaryHTML;
915         dup.classFeatureSetMap.putAll(this.classFeatureSetMap);
916         dup.sequence = this.sequence;
917         dup.timestamp = this.timestamp;
918         dup.releaseName = this.releaseName;
919         for (AppVersion appVersion : appVersionList) {
920             dup.appVersionList.add((AppVersion) appVersion.clone());
921         }
922
923         return dup;
924     }
925
926     /* (non-Javadoc)
927      * @see edu.umd.cs.findbugs.BugCollection#setTimestamp(long)
928      */

929
930     public void setTimestamp(long timestamp) {
931         this.timestamp = timestamp;
932     }
933
934     /* (non-Javadoc)
935      * @see edu.umd.cs.findbugs.BugCollection#getTimestamp()
936      */

937
938     public long getTimestamp() {
939         return timestamp;
940     }
941
942     /* (non-Javadoc)
943      * @see edu.umd.cs.findbugs.BugCollection#getClassFeatureSet(java.lang.String)
944      */

945
946     public ClassFeatureSet getClassFeatureSet(String JavaDoc className) {
947         return classFeatureSetMap.get(className);
948     }
949
950     /* (non-Javadoc)
951      * @see edu.umd.cs.findbugs.BugCollection#setClassFeatureSet(edu.umd.cs.findbugs.model.ClassFeatureSet)
952      */

953
954     public void setClassFeatureSet(ClassFeatureSet classFeatureSet) {
955         classFeatureSetMap.put(classFeatureSet.getClassName(), classFeatureSet);
956     }
957
958     /* (non-Javadoc)
959      * @see edu.umd.cs.findbugs.BugCollection#classFeatureSetIterator()
960      */

961
962     public Iterator JavaDoc<ClassFeatureSet> classFeatureSetIterator() {
963         return classFeatureSetMap.values().iterator();
964     }
965
966     /* (non-Javadoc)
967          * @see edu.umd.cs.findbugs.BugCollection#clearClassFeatures()
968          */

969     public void clearClassFeatures() {
970         classFeatureSetMap.clear();
971     }
972
973     /**
974      * @param withMessages The withMessages to set.
975      */

976     public void setWithMessages(boolean withMessages) {
977         this.withMessages = withMessages;
978     }
979
980     /**
981      * @return Returns the withMessages.
982      */

983     public boolean getWithMessages() {
984         return withMessages;
985     }
986
987     /* (non-Javadoc)
988      * @see edu.umd.cs.findbugs.BugCollection#getAppVersionFromSequenceNumber(int)
989      */

990     public AppVersion getAppVersionFromSequenceNumber(long target) {
991         for(AppVersion av : appVersionList)
992             if (av.getSequenceNumber() == target) return av;
993         if(target == this.getSequenceNumber())
994             return this.getCurrentAppVersion();
995         return null;
996     }
997
998     /* (non-Javadoc)
999      * @see edu.umd.cs.findbugs.BugCollection#findBug(java.lang.String, java.lang.String, int)
1000     */

1001    public BugInstance findBug(String JavaDoc instanceHash, String JavaDoc bugType,
1002            int lineNumber) {
1003        for(BugInstance bug : bugSet)
1004            if (bug.getInstanceHash().equals(instanceHash) && bug.getBugPattern().getType().equals(bugType)
1005                    && bug.getPrimarySourceLineAnnotation().getStartLine() == lineNumber) return bug;
1006        return null;
1007    }
1008}
1009
1010// vim:ts=4
1011
Popular Tags