KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > workflow > Update


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

18 package edu.umd.cs.findbugs.workflow;
19
20 import java.io.File JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.util.Comparator JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.TreeMap JavaDoc;
28
29 import org.dom4j.DocumentException;
30
31 import edu.umd.cs.findbugs.AppVersion;
32 import edu.umd.cs.findbugs.BugDesignation;
33 import edu.umd.cs.findbugs.TigerSubstitutes;
34 import edu.umd.cs.findbugs.BugCollection;
35 import edu.umd.cs.findbugs.BugInstance;
36 import edu.umd.cs.findbugs.ClassAnnotation;
37 import edu.umd.cs.findbugs.DetectorFactoryCollection;
38 import edu.umd.cs.findbugs.Project;
39 import edu.umd.cs.findbugs.SortedBugCollection;
40 import edu.umd.cs.findbugs.VersionInsensitiveBugComparator;
41 import edu.umd.cs.findbugs.config.CommandLine;
42 import edu.umd.cs.findbugs.model.MovedClassMap;
43
44 /**
45  * Java main application to compute update a historical bug collection with
46  * results from another build/analysis.
47  *
48  * @author William Pugh
49  */

50
51 public class Update {
52
53     /**
54      *
55      */

56     private static final String JavaDoc USAGE = "Usage: " + Update.class.getName()
57             + " [options] data1File data2File data3File ... ";
58
59     private HashMap JavaDoc<BugInstance, BugInstance> mapFromNewToOldBug = new HashMap JavaDoc<BugInstance, BugInstance>();
60
61     private HashSet JavaDoc<BugInstance> matchedOldBugs = new HashSet JavaDoc<BugInstance>();
62
63     boolean noPackageMoves = false;
64
65     boolean preciseMatch = false;
66     boolean precisePriorityMatch = false;
67
68     class UpdateCommandLine extends CommandLine {
69         boolean overrideRevisionNames = false;
70
71         String JavaDoc outputFilename;
72
73         UpdateCommandLine() {
74             addSwitch("-overrideRevisionNames",
75                     "override revision names for each version with names computed filenames");
76             addSwitch(
77                     "-noPackageMoves",
78                     "if a class seems to have moved from one package to another, treat warnings in that class as two seperate warnings");
79             addSwitch("-preciseMatch",
80                     "require bug patterns to match precisely");
81             addSwitch("-precisePriorityMatch",
82                     "only consider two warnings to be the same if their priorities match exactly");
83             addOption("-output", "output file",
84                     "explicit filename for merged results (standard out used if not specified)");
85             addSwitch("-quiet",
86                     "don't generate any outout to standard out unless there is an error");
87
88         }
89
90         @Override JavaDoc
91         protected void handleOption(String JavaDoc option, String JavaDoc optionExtraPart)
92                 throws IOException JavaDoc {
93             if (option.equals("-overrideRevisionNames")) {
94                 if (optionExtraPart.length() == 0)
95                     overrideRevisionNames = true;
96                 else
97                     overrideRevisionNames = TigerSubstitutes
98                             .parseBoolean(optionExtraPart);
99             } else if (option.equals("-noPackageMoves")) {
100                 if (optionExtraPart.length() == 0)
101                     noPackageMoves = true;
102                 else
103                     noPackageMoves = TigerSubstitutes
104                             .parseBoolean(optionExtraPart);
105             } else if (option.equals("-preciseMatch")) {
106                 preciseMatch = true;
107             } else if (option.equals("-precisePriorityMatch")) {
108                 versionInsensitiveBugComparator.setComparePriorities(true);
109                 fuzzyBugPatternMatcher.setComparePriorities(true);
110                 precisePriorityMatch = true;
111             } else if (option.equals("-quiet"))
112                 verbose = false;
113             else
114                 throw new IllegalArgumentException JavaDoc("no option " + option);
115
116         }
117
118         @Override JavaDoc
119         protected void handleOptionWithArgument(String JavaDoc option, String JavaDoc argument)
120                 throws IOException JavaDoc {
121             if (option.equals("-output"))
122                 outputFilename = argument;
123             else
124                 throw new IllegalArgumentException JavaDoc("Can't handle option "
125                         + option);
126
127         }
128
129     }
130
131     VersionInsensitiveBugComparator versionInsensitiveBugComparator = new VersionInsensitiveBugComparator();
132
133     VersionInsensitiveBugComparator fuzzyBugPatternMatcher = new VersionInsensitiveBugComparator();
134     {
135         fuzzyBugPatternMatcher.setExactBugPatternMatch(false);
136     }
137
138     public BugCollection mergeCollections(BugCollection origCollection,
139             BugCollection newCollection, boolean copyDeadBugs) {
140
141         mapFromNewToOldBug.clear();
142
143         matchedOldBugs.clear();
144         BugCollection resultCollection = newCollection
145                 .createEmptyCollectionWithMetadata();
146         // Previous sequence number
147
long lastSequence = origCollection.getSequenceNumber();
148         // The AppVersion history is retained from the orig collection,
149
// adding an entry for the sequence/timestamp of the current state
150
// of the orig collection.
151
resultCollection.clearAppVersions();
152         for (Iterator JavaDoc<AppVersion> i = origCollection.appVersionIterator(); i
153                 .hasNext();) {
154             AppVersion appVersion = i.next();
155             resultCollection.addAppVersion((AppVersion) appVersion.clone());
156         }
157         // why not do: AppVersion origCollectionVersion =
158
// origCollection.getCurrentAppVersion();
159
AppVersion origCollectionVersion = new AppVersion(lastSequence);
160         origCollectionVersion.setTimestamp(origCollection
161                 .getCurrentAppVersion().getTimestamp());
162         origCollectionVersion.setReleaseName(origCollection
163                 .getCurrentAppVersion().getReleaseName());
164         origCollectionVersion.setNumClasses(origCollection.getProjectStats()
165                 .getNumClasses());
166         origCollectionVersion.setCodeSize(origCollection.getProjectStats()
167                 .getCodeSize());
168
169         resultCollection.addAppVersion(origCollectionVersion);
170
171         // We assign a sequence number to the new collection as one greater than
172
// the original collection.
173
long currentSequence = origCollection.getSequenceNumber() + 1;
174         resultCollection.setSequenceNumber(currentSequence);
175
176         int oldBugs = 0;
177         // move all inactive bugs
178
if (copyDeadBugs)
179             for (BugInstance bug : origCollection.getCollection())
180                 if (bug.getLastVersion() != -1) {
181                     oldBugs++;
182                     BugInstance newBug = (BugInstance) bug.clone();
183                     resultCollection.add(newBug, false);
184                 }
185
186         matchBugs(SortedBugCollection.BugInstanceComparator.instance,
187                 origCollection, newCollection);
188         matchBugs(versionInsensitiveBugComparator, origCollection,
189                 newCollection);
190         if (!preciseMatch) {
191             matchBugs(fuzzyBugPatternMatcher, origCollection, newCollection);
192         }
193         if (!noPackageMoves) {
194             VersionInsensitiveBugComparator movedBugComparator = new VersionInsensitiveBugComparator();
195             MovedClassMap movedClassMap = new MovedClassMap(
196                                 origCollection, newCollection).execute();
197             if (!movedClassMap.isEmpty()) {
198                 movedBugComparator.setClassNameRewriter(movedClassMap);
199                 movedBugComparator.setComparePriorities(precisePriorityMatch);
200                 matchBugs(movedBugComparator, origCollection, newCollection);
201                 if (!preciseMatch) {
202                     movedBugComparator.setExactBugPatternMatch(false);
203                     matchBugs(movedBugComparator, origCollection, newCollection);
204                 }
205             }
206         }
207
208         // matchBugs(new SloppyBugComparator(), origCollection, newCollection);
209

210         int newlyDeadBugs = 0;
211         int persistantBugs = 0;
212         int addedBugs = 0;
213         int addedInNewCode = 0;
214         int deadBugInDeadCode = 0;
215
216         // Copy unmatched bugs
217
if (copyDeadBugs)
218             for (BugInstance bug : origCollection.getCollection())
219                 if (!matchedOldBugs.contains(bug)) {
220                     if (bug.getLastVersion() == -1)
221                         newlyDeadBugs++;
222                     else
223                         oldBugs++;
224                     BugInstance newBug = (BugInstance) bug.clone();
225
226                     if (newBug.getLastVersion() == -1) {
227                         newBug.setLastVersion(lastSequence);
228                         ClassAnnotation classBugFoundIn = bug.getPrimaryClass();
229                         String JavaDoc className = classBugFoundIn.getClassName();
230                         if (newCollection.getProjectStats().getClassStats(
231                                 className) != null)
232                             newBug.setRemovedByChangeOfPersistingClass(true);
233                         else
234                             deadBugInDeadCode++;
235                     }
236
237                     if (newBug.getFirstVersion() > newBug.getLastVersion())
238                         throw new IllegalStateException JavaDoc(
239                                 "Illegal Version range: "
240                                         + newBug.getFirstVersion() + ".."
241                                         + newBug.getLastVersion());
242                     resultCollection.add(newBug, false);
243                 }
244         // Copy matched bugs
245
for (BugInstance bug : newCollection.getCollection()) {
246             BugInstance newBug = (BugInstance) bug.clone();
247             if (mapFromNewToOldBug.containsKey(bug)) {
248                 BugInstance origWarning = mapFromNewToOldBug.get(bug);
249                 assert origWarning.getLastVersion() == -1;
250
251                 copyBugHistory(origWarning, newBug);
252                 // handle getAnnotationText()/setAnnotationText() and
253
// designation key
254
BugDesignation designation = newBug.getUserDesignation();
255                 if (designation != null)
256                     designation.merge(origWarning.getUserDesignation());
257                 else
258                     newBug.setUserDesignation(origWarning.getUserDesignation()); // clone??
259

260                 persistantBugs++;
261             } else {
262                 newBug.setFirstVersion(lastSequence + 1);
263                 addedBugs++;
264
265                 ClassAnnotation classBugFoundIn = bug.getPrimaryClass();
266
267                 String JavaDoc className = classBugFoundIn.getClassName();
268                 if (origCollection.getProjectStats().getClassStats(className) != null) {
269                     newBug.setIntroducedByChangeOfExistingClass(true);
270                     // System.out.println("added bug to existing code " +
271
// newBug.getUniqueId() + " : " + newBug.getAbbrev() + " in
272
// " + classBugFoundIn);
273
} else
274                     addedInNewCode++;
275             }
276             assert newBug.getLastVersion() == -1;
277             if (newBug.getLastVersion() != -1)
278                 throw new IllegalStateException JavaDoc("Illegal Version range: "
279                         + newBug.getFirstVersion() + ".."
280                         + newBug.getLastVersion());
281             int oldSize = resultCollection.getCollection().size();
282             resultCollection.add(newBug, false);
283             int newSize = resultCollection.getCollection().size();
284             if (newSize != oldSize + 1) {
285                 System.out.println("Failed to add bug #" + newBug.getUniqueId()
286                         + " : " + newBug.getMessage());
287             }
288         }
289         if (false && verbose) {
290             System.out.println(origCollection.getCollection().size()
291                     + " orig bugs, " + newCollection.getCollection().size()
292                     + " new bugs");
293             System.out.println("Bugs: " + oldBugs + " old, "
294                     + deadBugInDeadCode + " in removed code, "
295                     + (newlyDeadBugs - deadBugInDeadCode) + " died, "
296                     + persistantBugs + " persist, " + addedInNewCode
297                     + " in new code, " + (addedBugs - addedInNewCode)
298                     + " added");
299             System.out.println(resultCollection.getCollection().size()
300                     + " resulting bugs");
301         }
302         return resultCollection;
303
304     }
305
306     boolean verbose = true;
307
308     public static String JavaDoc[] getFilePathParts(String JavaDoc filePath) {
309         String JavaDoc regex = (File.separatorChar=='\\' ? "\\\\" : File.separator);
310         return filePath.split(regex);
311     }
312
313     public static void main(String JavaDoc[] args) throws IOException JavaDoc,
314             DocumentException {
315         new Update().doit(args);
316     }
317
318     public void doit(String JavaDoc[] args) throws IOException JavaDoc, DocumentException {
319
320         DetectorFactoryCollection.instance();
321         UpdateCommandLine commandLine = new UpdateCommandLine();
322         int argCount = commandLine.parse(args, 2, Integer.MAX_VALUE, USAGE);
323
324         if (commandLine.outputFilename == null)
325             verbose = false;
326         String JavaDoc[] firstPathParts = getFilePathParts(args[argCount]);
327         int commonPrefix = firstPathParts.length;
328         for (int i = argCount + 1; i <= (args.length - 1); i++) {
329
330             commonPrefix = Math.min(commonPrefix, lengthCommonPrefix(
331                     firstPathParts, getFilePathParts(args[i])));
332         }
333
334         String JavaDoc origFilename = args[argCount++];
335         Project project = new Project();
336         BugCollection origCollection;
337         origCollection = new SortedBugCollection();
338         if (verbose)
339             System.out.println("Starting with " + origFilename);
340
341         origCollection.readXML(origFilename, project);
342
343         if (commandLine.overrideRevisionNames
344                 || origCollection.getReleaseName() == null
345                 || origCollection.getReleaseName().length() == 0)
346             origCollection.setReleaseName(firstPathParts[commonPrefix]);
347         for (BugInstance bug : origCollection.getCollection())
348             if (bug.getLastVersion() >= 0
349                     && bug.getFirstVersion() > bug.getLastVersion())
350                 throw new IllegalStateException JavaDoc("Illegal Version range: "
351                         + bug.getFirstVersion() + ".." + bug.getLastVersion());
352
353         while (argCount <= (args.length - 1)) {
354
355             BugCollection newCollection = new SortedBugCollection();
356
357             String JavaDoc newFilename = args[argCount++];
358             if (verbose)
359                 System.out.println("Merging " + newFilename);
360             project = new Project();
361             try {
362                 File JavaDoc f = new File JavaDoc(newFilename);
363                 if (f.length() == 0) {
364                     if (verbose)
365                         System.out.println("Empty input file: " + f);
366                     continue;
367                 }
368                 newCollection.readXML(newFilename, project);
369
370                 if (commandLine.overrideRevisionNames
371                         || newCollection.getReleaseName() == null
372                         || newCollection.getReleaseName().length() == 0)
373                     newCollection
374                             .setReleaseName(getFilePathParts(newFilename)[commonPrefix]);
375
376                 origCollection = mergeCollections(origCollection,
377                         newCollection, true);
378             } catch (IOException JavaDoc e) {
379                 if (verbose)
380                     System.out.println(e);
381                 else
382                     throw e;
383             }
384         }
385
386         if (commandLine.outputFilename != null)
387             origCollection.writeXML(commandLine.outputFilename, project);
388         else
389             origCollection.writeXML(System.out, project);
390
391     }
392
393     private static int lengthCommonPrefix(String JavaDoc[] string, String JavaDoc[] string2) {
394         int maxLength = Math.min(string.length, string2.length);
395         for (int result = 0; result < maxLength; result++)
396             if (!string[result].equals(string2[result]))
397                 return result;
398         return maxLength;
399     }
400
401     private static void copyBugHistory(BugInstance src, BugInstance dest) {
402
403         dest.setFirstVersion(src.getFirstVersion());
404         dest.setLastVersion(src.getLastVersion());
405         dest.setIntroducedByChangeOfExistingClass(src
406                 .isIntroducedByChangeOfExistingClass());
407         dest.setRemovedByChangeOfPersistingClass(src
408                 .isRemovedByChangeOfPersistingClass());
409     }
410
411     private void matchBugs(Comparator JavaDoc<BugInstance> bugInstanceComparator,
412             BugCollection origCollection, BugCollection newCollection) {
413
414         TreeMap JavaDoc<BugInstance, LinkedList JavaDoc<BugInstance>> set = new TreeMap JavaDoc<BugInstance, LinkedList JavaDoc<BugInstance>>(
415                 bugInstanceComparator);
416         int oldBugs = 0;
417         int newBugs = 0;
418         int matchedBugs = 0;
419         for (BugInstance bug : origCollection.getCollection())
420             if (bug.getLastVersion() == -1 && !matchedOldBugs.contains(bug)) {
421                 oldBugs++;
422                 LinkedList JavaDoc<BugInstance> q = set.get(bug);
423                 if (q == null) {
424                     q = new LinkedList JavaDoc<BugInstance>();
425                     set.put(bug, q);
426                 }
427                 q.add(bug);
428             }
429         for (BugInstance bug : newCollection.getCollection())
430             if (!mapFromNewToOldBug.containsKey(bug)) {
431                 newBugs++;
432                 LinkedList JavaDoc<BugInstance> q = set.get(bug);
433                 if (q != null && !q.isEmpty()) {
434                     matchedBugs++;
435                     BugInstance matchedBug = q.removeFirst();
436                     mapFromNewToOldBug.put(bug, matchedBug);
437                     matchedOldBugs.add(matchedBug);
438                 }
439             }
440         if (false && verbose)
441             System.out.println("matched " + matchedBugs + " of " + oldBugs
442                     + "o/" + newBugs + "n bugs using "
443                     + bugInstanceComparator.getClass().getName());
444     }
445
446 }
447
Popular Tags