KickJava   Java API By Example, From Geeks To Geeks.

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


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
19 package edu.umd.cs.findbugs.workflow;
20
21 import java.beans.DesignMode JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.lang.reflect.Field JavaDoc;
25 import java.util.Date JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.SortedMap JavaDoc;
32 import java.util.TreeMap JavaDoc;
33 import java.util.regex.Pattern JavaDoc;
34
35 import edu.umd.cs.findbugs.AppVersion;
36 import edu.umd.cs.findbugs.BugCategory;
37 import edu.umd.cs.findbugs.BugCollection;
38 import edu.umd.cs.findbugs.BugInstance;
39 import edu.umd.cs.findbugs.BugPattern;
40 import edu.umd.cs.findbugs.DetectorFactoryCollection;
41 import edu.umd.cs.findbugs.I18N;
42 import edu.umd.cs.findbugs.Project;
43 import edu.umd.cs.findbugs.SortedBugCollection;
44 import edu.umd.cs.findbugs.SourceLineAnnotation;
45 import edu.umd.cs.findbugs.TigerSubstitutes;
46 import edu.umd.cs.findbugs.ba.SourceFinder;
47 import edu.umd.cs.findbugs.config.CommandLine;
48 import edu.umd.cs.findbugs.filter.FilterException;
49 import edu.umd.cs.findbugs.filter.Matcher;
50
51 /**
52  * Java main application to filter/transform an XML bug collection
53  * or bug history collection.
54  *
55  * @author William Pugh
56  */

57 public class Filter {
58     static class FilterCommandLine extends CommandLine {
59         /**
60          *
61          */

62         public static final long MILLISECONDS_PER_DAY = 24*60*60*1000L;
63         Pattern JavaDoc className,bugPattern;
64         public boolean notSpecified = false;
65         public boolean not = false;
66         long first;
67         String JavaDoc firstAsString;
68         long after;
69         String JavaDoc afterAsString;
70         long before;
71         String JavaDoc beforeAsString;
72         
73         long last;
74         String JavaDoc lastAsString;
75         String JavaDoc fixedAsString; // alternate way to specify 'last'
76
long present;
77         String JavaDoc presentAsString;
78         long absent;
79         String JavaDoc absentAsString;
80         String JavaDoc annotation;
81         public boolean activeSpecified = false;
82         public boolean active = false;
83     
84         public boolean withSource = false;
85         public boolean withSourceSpecified = false;
86         public boolean introducedByChange = false;
87         public boolean introducedByChangeSpecified = false;
88
89         public boolean removedByChange = false;
90         public boolean removedByChangeSpecified = false;
91         
92         public boolean newCode = false;
93         public boolean newCodeSpecified = false;
94
95         public boolean hashChanged = false;
96         public boolean hashChangedSpecified = false;
97
98         public boolean removedCode = false;
99         public boolean removedCodeSpecified = false;
100
101         public boolean classified = false;
102         public boolean classifiedSpecified = false;
103
104
105         public boolean withMessagesSpecified = false;
106         public boolean withMessages = false;
107         public boolean serious = false;
108         public boolean seriousSpecified = false;
109         
110         private Matcher includeFilter, excludeFilter;
111         String JavaDoc designationString;
112         String JavaDoc designationKey;
113         String JavaDoc categoryString;
114         String JavaDoc categoryKey;
115         int priority = 3;
116
117         FilterCommandLine() {
118             
119             addSwitch("-not", "reverse (all) switches for the filter");
120             addSwitchWithOptionalExtraPart("-withSource", "truth", "only warnings for switch source is available");
121             addSwitchWithOptionalExtraPart("-hashChanged", "truth", "only warnings for which the stored hash is not the same as the calculated hash");
122             addOption("-exclude", "filter file", "exclude bugs matching given filter");
123             addOption("-include", "filter file", "include only bugs matching given filter");
124             
125             addOption("-annotation", "text", "allow only warnings containing this text in an annotation");
126             addSwitchWithOptionalExtraPart("-classified", "truth", "allow only classified warnings");
127             addSwitchWithOptionalExtraPart("-withMessages", "truth", "generated XML should contain textual messages");
128             
129             addSwitchWithOptionalExtraPart("-serious", "truth", "allow only warnings classified as serious");
130             
131             addOption("-after", "when", "allow only warnings that first occurred after this version");
132             addOption("-before", "when", "allow only warnings that first occurred before this version");
133             addOption("-first", "when", "allow only warnings that first occurred in this version");
134             addOption("-last", "when", "allow only warnings that last occurred in this version");
135             addOption("-fixed", "when", "allow only warnings that last occurred in the previous version (clobbers last)");
136             addOption("-present", "when", "allow only warnings present in this version");
137             addOption("-absent", "when", "allow only warnings absent in this version");
138             addSwitchWithOptionalExtraPart("-active", "truth", "allow only warnings alive in the last sequence number");
139             
140             addSwitchWithOptionalExtraPart("-introducedByChange", "truth",
141                     "allow only warnings introduced by a change of an existing class");
142             addSwitchWithOptionalExtraPart("-removedByChange", "truth",
143                     "allow only warnings removed by a change of a persisting class");
144             addSwitchWithOptionalExtraPart("-newCode", "truth",
145             "allow only warnings introduced by the addition of a new class");
146             addSwitchWithOptionalExtraPart("-removedCode", "truth",
147             "allow only warnings removed by removal of a class");
148             addOption("-priority", "level", "allow only warnings with this priority or higher");
149             addOption("-class", "pattern", "allow only bugs whose primary class name matches this pattern");
150             addOption("-bugPattern", "pattern", "allow only bugs whose type matches this pattern");
151             addOption("-category", "category", "allow only warnings with a category that starts with this string");
152             addOption("-designation", "designation", "allow only warnings with this designation (e.g., -designation SHOULD_FIX)");
153     
154         }
155
156         static long getVersionNum(Map JavaDoc<String JavaDoc, AppVersion> versions,
157                 SortedMap JavaDoc<Long JavaDoc, AppVersion> timeStamps , String JavaDoc val,
158                 boolean roundToLaterVersion, long numVersions) {
159             if (val == null) return -1;
160             if (val.equals("last") || val.equals("lastVersion")) return numVersions -1;
161             
162             AppVersion v = versions.get(val);
163             if (v != null) return v.getSequenceNumber();
164             try {
165                 long time = 0;
166                 if (val.endsWith("daysAgo"))
167                     time = System.currentTimeMillis() - MILLISECONDS_PER_DAY * Integer.parseInt(val.substring(0, val.length() - 7));
168                 else time = Date.parse(val);
169                 return getAppropriateSeq(timeStamps, time, roundToLaterVersion);
170             } catch (Exception JavaDoc e) {
171                 try {
172                     long version = Long.parseLong(val);
173                     if (version < 0) {
174                         version = numVersions + version;
175                     }
176                     return version;
177                 }
178                 catch (NumberFormatException JavaDoc e1) {
179                     throw new IllegalArgumentException JavaDoc("Could not interpret version specification of '" + val + "'");
180                 }
181             }
182         }
183         
184         // timeStamps contains 0 10 20 30
185
// if roundToLater == true, ..0 = 0, 1..10 = 1, 11..20 = 2, 21..30 = 3, 31.. = Long.MAX
186
// if roundToLater == false, ..-1 = Long.MIN, 0..9 = 0, 10..19 = 1, 20..29 = 2, 30..39 = 3, 40 .. = 4
187
static private long getAppropriateSeq(SortedMap JavaDoc<Long JavaDoc, AppVersion> timeStamps, long when, boolean roundToLaterVersion) {
188             if (roundToLaterVersion) {
189                 SortedMap JavaDoc<Long JavaDoc, AppVersion> geq = timeStamps.tailMap(when);
190                 if (geq.isEmpty()) return Long.MAX_VALUE;
191                 return geq.get(geq.firstKey()).getSequenceNumber();
192             } else {
193                 SortedMap JavaDoc<Long JavaDoc, AppVersion> leq = timeStamps.headMap(when);
194                 if (leq.isEmpty()) return Long.MIN_VALUE;
195                 return leq.get(leq.lastKey()).getSequenceNumber();
196             }
197         }
198
199         void adjustFilter(BugCollection collection) {
200             Map JavaDoc<String JavaDoc, AppVersion> versions = new HashMap JavaDoc<String JavaDoc, AppVersion>();
201             SortedMap JavaDoc<Long JavaDoc, AppVersion> timeStamps = new TreeMap JavaDoc<Long JavaDoc, AppVersion>();
202
203             for(Iterator JavaDoc<AppVersion> i = collection.appVersionIterator(); i.hasNext(); ) {
204                 AppVersion v = i.next();
205                 versions.put(v.getReleaseName(), v);
206                 timeStamps.put(v.getTimestamp(), v);
207             }
208             // add current version to the maps
209
AppVersion v = collection.getCurrentAppVersion();
210             versions.put(v.getReleaseName(), v);
211             timeStamps.put(v.getTimestamp(), v);
212             
213             first = getVersionNum(versions, timeStamps, firstAsString, true, v.getSequenceNumber());
214             last = getVersionNum(versions, timeStamps, lastAsString, true, v.getSequenceNumber());
215             before = getVersionNum(versions, timeStamps, beforeAsString, true, v.getSequenceNumber());
216             after = getVersionNum(versions, timeStamps, afterAsString, false, v.getSequenceNumber());
217             present = getVersionNum(versions, timeStamps, presentAsString, true, v.getSequenceNumber());
218             absent = getVersionNum(versions, timeStamps, absentAsString, true, v.getSequenceNumber());
219
220             long fixed = getVersionNum(versions, timeStamps, fixedAsString, true, v.getSequenceNumber());
221             if (fixed >= 0) last = fixed - 1; // fixed means last on previous sequence (ok if -1)
222
}
223
224         boolean accept(BugInstance bug) {
225             boolean result = evaluate(bug);
226             if (not) return !result;
227             return result;
228         }
229                 boolean evaluate(BugInstance bug) {
230
231             if (includeFilter != null && !includeFilter.match(bug)) return false;
232             if (excludeFilter != null && excludeFilter.match(bug)) return false;
233             if (annotation != null && bug.getAnnotationText().indexOf(annotation) == -1)
234                 return false;
235             if (bug.getPriority() > priority)
236                 return false;
237             if (firstAsString != null && bug.getFirstVersion() != first)
238                 return false;
239             if (afterAsString != null && bug.getFirstVersion() <= after)
240                 return false;
241             if (beforeAsString != null && bug.getFirstVersion() >= before)
242                 return false;
243             if ((lastAsString != null || fixedAsString != null) && (last < 0 || bug.getLastVersion() != last))
244                 return false;
245             if (presentAsString != null && !bugLiveAt(bug, present))
246                 return false;
247             if (absentAsString != null && bugLiveAt(bug, absent))
248                 return false;
249             
250             if (activeSpecified && active != (bug.getLastVersion() == -1))
251                 return false;
252             if (removedByChangeSpecified
253                     && bug.isRemovedByChangeOfPersistingClass() != removedByChange)
254                 return false;
255             if (introducedByChangeSpecified
256                     && bug.isIntroducedByChangeOfExistingClass() != introducedByChange)
257                 return false;
258             if (newCodeSpecified && newCode != (!bug.isIntroducedByChangeOfExistingClass() && bug.getFirstVersion() != 0))
259                 return false;
260             if (removedCodeSpecified && removedCode != (!bug.isRemovedByChangeOfPersistingClass() && bug.getLastVersion() != -1))
261                 return false;
262
263             if (bugPattern != null && !bugPattern.matcher(bug.getType()).find())
264                     return false;
265             if (className != null && !className.matcher(bug.getPrimaryClass().getClassName()).find())
266                     return false;
267
268             BugPattern thisBugPattern = bug.getBugPattern();
269             if (categoryKey != null && thisBugPattern != null && !categoryKey.equals(thisBugPattern.getCategory()))
270                 return false;
271             if (designationKey != null && !designationKey.equals(bug.getUserDesignationKey()))
272                 return false;
273             
274             if (withSourceSpecified) {
275                 if (sourceSearcher.findSource(bug.getPrimarySourceLineAnnotation()) != withSource)
276                     return false;
277             }
278             if (hashChangedSpecified) {
279                 if (bug.isInstanceHashConsistent() == hashChanged)
280                     return false;
281             }
282
283             if (classifiedSpecified && classified != isClassified(bug)) {
284                 return false;
285             }
286
287             if (seriousSpecified) {
288                 Set JavaDoc<String JavaDoc> words = bug.getTextAnnotationWords();
289                 boolean thisOneIsSerious = words.contains("BUG")
290                 && !(words.contains("NOT_BUG") || words.contains("HARMLESS"));
291                 if (serious != thisOneIsSerious) return false;
292             }
293
294             return true;
295         }
296
297         private boolean isClassified(BugInstance bug) {
298             Set JavaDoc<String JavaDoc> words = bug.getTextAnnotationWords();
299             return words.contains("BUG") || words.contains("NOT_BUG");
300         }
301
302         private boolean bugLiveAt(BugInstance bug, long now) {
303             if (now < bug.getFirstVersion())
304                 return false;
305             if (bug.getLastVersion() != -1 && bug.getLastVersion() < now)
306                 return false;
307             return true;
308         }
309
310         @Override JavaDoc
311         protected void handleOption(String JavaDoc option, String JavaDoc optionExtraPart) throws IOException JavaDoc {
312             option = option.substring(1);
313             if (optionExtraPart.length() == 0)
314                 setField(option, true);
315             else
316                 setField(option, TigerSubstitutes.parseBoolean(optionExtraPart));
317             setField(option+"Specified", true);
318         }
319
320         private void setField(String JavaDoc fieldName, boolean value) {
321             try {
322             Field JavaDoc f = FilterCommandLine.class.getField(fieldName);
323             f.setBoolean(this, value);
324             } catch (RuntimeException JavaDoc e) {
325                 throw e;
326             } catch (Exception JavaDoc e) {
327                 throw new RuntimeException JavaDoc(e);
328             }
329             
330         }
331         @Override JavaDoc
332         protected void handleOptionWithArgument(String JavaDoc option, String JavaDoc argument) throws IOException JavaDoc {
333
334             if (option.equals("-priority")) {
335                 priority = parsePriority(argument);
336             }
337
338             
339             else if (option.equals("-first"))
340                 firstAsString = argument;
341             else if (option.equals("-last"))
342                 lastAsString = argument;
343             else if (option.equals("-fixed"))
344                 fixedAsString = argument;
345             else if (option.equals("-after"))
346                 afterAsString = argument;
347             else if (option.equals("-before"))
348                 beforeAsString = argument;
349             else if (option.equals("-present"))
350                 presentAsString = argument;
351             else if (option.equals("-absent"))
352                 absentAsString = argument;
353             
354             else if (option.equals("-category"))
355                 categoryString = argument;
356             else if (option.equals("-designation"))
357                 designationString = argument;
358             else if (option.equals("-class"))
359                     className = Pattern.compile(argument);
360             else if (option.equals("-bugPattern"))
361                     bugPattern = Pattern.compile(argument);
362             else if (option.equals("-annotation"))
363                 annotation = argument;
364             else if (option.equals("-include")) {
365                 try {
366                     includeFilter = new edu.umd.cs.findbugs.filter.Filter(argument);
367                 } catch (FilterException e) {
368                     throw new IllegalArgumentException JavaDoc("Error processing include file: " + argument, e);
369                 }
370             } else if (option.equals("-exclude")) {
371                 try {
372                     excludeFilter = new edu.umd.cs.findbugs.filter.Filter(argument);
373                 } catch (FilterException e) {
374                     throw new IllegalArgumentException JavaDoc("Error processing include file: " + argument, e);
375                 }
376             } else throw new IllegalArgumentException JavaDoc("can't handle command line argument of " + option);
377         }
378
379
380
381     }
382     public static int parsePriority(String JavaDoc argument) {
383         int i = " HMLE".indexOf(argument);
384         if (i == -1)
385             i = " 1234".indexOf(argument);
386         if (i == -1)
387             throw new IllegalArgumentException JavaDoc("Bad priority: " + argument);
388         return i;
389     }
390
391     static SourceSearcher sourceSearcher;
392     
393     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
394         DetectorFactoryCollection.instance();
395         final FilterCommandLine commandLine = new FilterCommandLine();
396
397         int argCount = commandLine.parse(args, 0, 2, "Usage: " + Filter.class.getName()
398                 + " [options] [<orig results> [<new results]] ");
399         Project project = new Project();
400         SortedBugCollection origCollection = new SortedBugCollection();
401
402         if (argCount == args.length)
403             origCollection.readXML(System.in, project);
404         else
405             origCollection.readXML(args[argCount++], project);
406         boolean verbose = argCount < args.length;
407         I18N i18n = I18N.instance();
408         if (commandLine.categoryString != null) {
409             for (BugCategory bugCategory : i18n
410                     .getBugCategoryObjects())
411                 if (bugCategory.getAbbrev().equals(commandLine.categoryString)) {
412                     commandLine.categoryKey = bugCategory.getCategory();
413                     break;
414                 }
415             if (commandLine.categoryKey == null)
416                 for (BugCategory bugCategory : i18n
417                         .getBugCategoryObjects())
418                     if (bugCategory.getAbbrev().startsWith(
419                             commandLine.categoryString)) {
420                         commandLine.categoryKey = bugCategory.getCategory();
421                         break;
422                     }
423         }
424         
425         if (commandLine.designationString != null) {
426             for (String JavaDoc designationKey : i18n.getUserDesignationKeys()) {
427                 if (designationKey.startsWith(commandLine.designationString)
428                         || i18n.getUserDesignation(designationKey).startsWith(commandLine.designationString)) {
429                     commandLine.designationKey = designationKey;
430                     break;
431                 }
432                     
433             }
434         }
435         SortedBugCollection resultCollection = origCollection.createEmptyCollectionWithMetadata();
436         int passed = 0;
437         int dropped = 0;
438         resultCollection.setWithMessages(commandLine.withMessages);
439         if (commandLine.hashChangedSpecified)
440             origCollection.computeBugHashes();
441         commandLine.adjustFilter(resultCollection);
442         resultCollection.getProjectStats().clearBugCounts();
443         sourceSearcher = new SourceSearcher(project);
444         for (BugInstance bug : origCollection.getCollection())
445             if (commandLine.accept(bug)) {
446                 resultCollection.add(bug, false);
447                 if (bug.getLastVersion() == -1 )
448                     resultCollection.getProjectStats().addBug(bug);
449                 passed++;
450             } else
451                 dropped++;
452
453         if (verbose)
454             System.out.println(passed + " warnings passed through, " + dropped
455                 + " warnings dropped");
456         if (argCount == args.length) {
457             assert !verbose;
458             resultCollection.writeXML(System.out, project);
459         }
460         else {
461             resultCollection.writeXML(args[argCount++], project);
462
463         }
464
465     }
466
467 }
468
469 // vim:ts=4
470
Popular Tags