KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * FindBugs - Find bugs in Java programs
3  * Copyright (C) 2003,2004 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.util.Arrays JavaDoc;
23 import java.util.Comparator JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28
29 import edu.umd.cs.findbugs.ba.AnalysisContext;
30 import edu.umd.cs.findbugs.ba.ClassNotFoundExceptionParser;
31 import edu.umd.cs.findbugs.ba.JavaClassAndMethod;
32 import edu.umd.cs.findbugs.ba.MethodUnprofitableException;
33 import edu.umd.cs.findbugs.ba.MissingClassException;
34 import edu.umd.cs.findbugs.classfile.ClassDescriptor;
35 import edu.umd.cs.findbugs.classfile.MethodDescriptor;
36
37 /**
38  * An abstract class which provides much of the functionality
39  * required of all BugReporter objects.
40  */

41 public abstract class AbstractBugReporter implements BugReporter {
42     private static final boolean DEBUG_MISSING_CLASSES = SystemProperties.getBoolean("findbugs.debug.missingclasses");
43     
44     private static class Error {
45         private int sequence;
46         private String JavaDoc message;
47         private Throwable JavaDoc cause;
48         
49         public Error(int sequence, String JavaDoc message) {
50             this(sequence, message, null);
51         }
52         
53         public Error(int sequence, String JavaDoc message, Throwable JavaDoc cause) {
54             this.sequence = sequence;
55             this.message = message;
56             this.cause = cause;
57         }
58         
59         public int getSequence() {
60             return sequence;
61         }
62         
63         public String JavaDoc getMessage() {
64             return message;
65         }
66         
67         public Throwable JavaDoc getCause() {
68             return cause;
69         }
70         
71         @Override JavaDoc
72         public int hashCode() {
73             int hashCode = message.hashCode();
74             if (cause != null) {
75                 hashCode += 1009 * cause.hashCode();
76             }
77             return hashCode;
78         }
79         
80         //@Override
81
@Override JavaDoc
82         public boolean equals(Object JavaDoc obj) {
83             if (obj == null || obj.getClass() != this.getClass())
84                 return false;
85             Error JavaDoc other = (Error JavaDoc) obj;
86             if (!message.equals(other.message))
87                 return false;
88             if (this.cause == other.cause)
89                 return true;
90             if (this.cause == null || other.cause == null)
91                 return false;
92             return this.cause.equals(other.cause);
93         }
94     }
95
96     private int verbosityLevel = NORMAL;
97     private int priorityThreshold;
98     private boolean analysisUnderway, relaxed;
99     private HashSet JavaDoc<String JavaDoc> missingClassMessageSet = new HashSet JavaDoc<String JavaDoc>();
100     private LinkedList JavaDoc<String JavaDoc> missingClassMessageList = new LinkedList JavaDoc<String JavaDoc>();
101     private Set JavaDoc<Error JavaDoc> errorSet = new HashSet JavaDoc<Error JavaDoc>();
102     private List JavaDoc<BugReporterObserver> observerList = new LinkedList JavaDoc<BugReporterObserver>();
103     private ProjectStats projectStats = new ProjectStats();
104     private int errorCount;
105
106     public void setErrorVerbosity(int level) {
107         this.verbosityLevel = level;
108     }
109
110     public void setPriorityThreshold(int threshold) {
111         this.priorityThreshold = threshold;
112     }
113
114     // Subclasses must override doReportBug(), not this method.
115
public final void reportBug(BugInstance bugInstance) {
116         if (!analysisUnderway) {
117             if (FindBugsAnalysisFeatures.isRelaxedMode()) {
118                 relaxed = true;
119             }
120
121             analysisUnderway = true;
122         }
123         ClassAnnotation primaryClass = bugInstance.getPrimaryClass();
124         if (primaryClass != null && !AnalysisContext.currentAnalysisContext().isApplicationClass(primaryClass.getClassName()))
125                 return;
126         if (bugInstance.getPriority() <= priorityThreshold || relaxed)
127             doReportBug(bugInstance);
128     }
129
130     public static String JavaDoc getMissingClassName(ClassNotFoundException JavaDoc ex) {
131         String JavaDoc message = ex.getMessage();
132
133         // Try to decode the error message by extracting the class name.
134
String JavaDoc className = ClassNotFoundExceptionParser.getMissingClassName(ex);
135         if (className != null) {
136             if (className.indexOf('/') >= 0) {
137                 className = className.replace('/','.');
138             }
139             return className;
140             
141         }
142
143         // Just return the entire message.
144
// It hopefully will still make sense to the user.
145
return message;
146     }
147
148     public void reportMissingClass(ClassNotFoundException JavaDoc ex) {
149         if (DEBUG_MISSING_CLASSES) {
150             System.out.println("Missing class: " + ex.toString());
151             ex.printStackTrace(System.out);
152         }
153         
154         if (verbosityLevel == SILENT)
155             return;
156
157         String JavaDoc message = getMissingClassName(ex);
158         
159         if (message.startsWith("[")) {
160             // Sometimes we see methods called on array classes.
161
// Obviously, these don't exist as class files.
162
// So, we should just ignore the exception.
163
// Really, we should fix the class/method search interfaces
164
// to be much more intelligent in resolving method
165
// implementations.
166
return;
167         }
168
169         logMissingClass(message);
170     }
171     
172     /* (non-Javadoc)
173      * @see edu.umd.cs.findbugs.classfile.IErrorLogger#reportMissingClass(edu.umd.cs.findbugs.classfile.ClassDescriptor)
174      */

175     public void reportMissingClass(ClassDescriptor classDescriptor) {
176         if (DEBUG_MISSING_CLASSES) {
177             System.out.println("Missing class: " + classDescriptor);
178         }
179
180         if (verbosityLevel == SILENT)
181             return;
182         
183         logMissingClass(classDescriptor.toDottedClassName());
184     }
185
186     /**
187      * @param message
188      */

189     private void logMissingClass(String JavaDoc message) {
190         if (!missingClassMessageSet.contains(message)) {
191             missingClassMessageSet.add(message);
192             missingClassMessageList.add(message);
193         }
194     }
195     
196     /**
197      * Report that we skipped some analysis of a method
198      * @param method
199      */

200     public void reportSkippedAnalysis(MethodDescriptor method) {
201         // TODO: log this
202
}
203     public void logError(String JavaDoc message) {
204         if (verbosityLevel == SILENT)
205             return;
206
207         Error JavaDoc error = new Error JavaDoc(errorCount++, message);
208         if (!errorSet.contains(error))
209             errorSet.add(error);
210     }
211     
212     public void logError(String JavaDoc message, Throwable JavaDoc e) {
213
214         if (e instanceof MethodUnprofitableException) {
215             // TODO: log this
216
return;
217         }
218         if (e instanceof MissingClassException) {
219             // Record the missing class, in case the exception thrower didn't.
220
MissingClassException missingClassEx = (MissingClassException) e;
221             ClassNotFoundException JavaDoc cnfe = missingClassEx.getClassNotFoundException();
222
223             reportMissingClass(cnfe);
224             // Don't report dataflow analysis exceptions due to missing classes.
225
// Too much noise.
226
return;
227         }
228         
229         if (verbosityLevel == SILENT)
230             return;
231     
232         Error JavaDoc error = new Error JavaDoc(errorCount++, message, e);
233         if (!errorSet.contains(error))
234             errorSet.add(error);
235     }
236
237     public void reportQueuedErrors() {
238         // Report unique errors in order of their sequence
239
Error JavaDoc[] errorList = errorSet.toArray(new Error JavaDoc[errorSet.size()]);
240         Arrays.sort(errorList, new Comparator JavaDoc<Error JavaDoc>() {
241             public int compare(Error JavaDoc o1, Error JavaDoc o2) {
242                 return o1.getSequence() - o2.getSequence();
243             }
244         });
245         for (Error JavaDoc error : errorList) {
246             reportAnalysisError(new AnalysisError(error.getMessage(), error.getCause()));
247         }
248
249         for (String JavaDoc aMissingClassMessageList : missingClassMessageList) {
250             reportMissingClass(aMissingClassMessageList);
251         }
252     }
253
254     public void addObserver(BugReporterObserver observer) {
255         observerList.add(observer);
256     }
257
258     public ProjectStats getProjectStats() {
259         return projectStats;
260     }
261
262     /**
263      * This should be called when a bug is reported by a subclass.
264      *
265      * @param bugInstance the bug to inform observers of
266      */

267     protected void notifyObservers(BugInstance bugInstance) {
268         for (BugReporterObserver aObserverList : observerList)
269             aObserverList.reportBug(bugInstance);
270     }
271
272     /**
273      * Subclasses must override this.
274      * It will be called only for bugs which meet the priority threshold.
275      *
276      * @param bugInstance the bug to report
277      */

278     protected abstract void doReportBug(BugInstance bugInstance);
279
280     /**
281      * Report a queued error.
282      *
283      * @param error the queued error
284      */

285     public abstract void reportAnalysisError(AnalysisError error);
286
287     /**
288      * Report a missing class.
289      *
290      * @param string the name of the class
291      */

292     public abstract void reportMissingClass(String JavaDoc string);
293 }
294
295 // vim:ts=4
296
Popular Tags