KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > classfile > impl > AnalysisCache


1 /*
2  * FindBugs - Find Bugs in Java programs
3  * Copyright (C) 2006, 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.classfile.impl;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Map.Entry;
25
26 import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
27 import edu.umd.cs.findbugs.classfile.ClassDescriptor;
28 import edu.umd.cs.findbugs.classfile.IAnalysisCache;
29 import edu.umd.cs.findbugs.classfile.IAnalysisEngine;
30 import edu.umd.cs.findbugs.classfile.IClassAnalysisEngine;
31 import edu.umd.cs.findbugs.classfile.IClassPath;
32 import edu.umd.cs.findbugs.classfile.IDatabaseFactory;
33 import edu.umd.cs.findbugs.classfile.IErrorLogger;
34 import edu.umd.cs.findbugs.classfile.IMethodAnalysisEngine;
35 import edu.umd.cs.findbugs.classfile.MethodDescriptor;
36 import edu.umd.cs.findbugs.util.MapCache;
37
38 /**
39  * Implementation of IAnalysisCache.
40  * This object is responsible for registering class and method analysis engines
41  * and caching analysis results.
42  *
43  * @author David Hovemeyer
44  */

45 public class AnalysisCache implements IAnalysisCache {
46     /**
47      * Maximum number of class or method analysis results
48      * to cache for a particular ClassDescriptor/MethodDescriptor.
49      */

50     private static final int CACHE_SIZE = 5;
51
52     // Fields
53
private IClassPath classPath;
54     private IErrorLogger errorLogger;
55     private Map JavaDoc<Class JavaDoc<?>, IClassAnalysisEngine> classAnalysisEngineMap;
56     private Map JavaDoc<Class JavaDoc<?>, IMethodAnalysisEngine> methodAnalysisEngineMap;
57     private Map JavaDoc<Class JavaDoc<?>, IDatabaseFactory<?>> databaseFactoryMap;
58     private Map JavaDoc<Class JavaDoc<?>, Map JavaDoc<ClassDescriptor, Object JavaDoc>> classAnalysisMap;
59     private Map JavaDoc<Class JavaDoc<?>, Map JavaDoc<MethodDescriptor, Object JavaDoc>> methodAnalysisMap;
60     private Map JavaDoc<Class JavaDoc<?>, Object JavaDoc> databaseMap;
61
62     /**
63      * Object indicating that an analysis could not be computed
64      * because an exception occurred.
65      */

66     static class AnalysisError {
67         CheckedAnalysisException exception;
68         
69         public AnalysisError(CheckedAnalysisException exception) {
70             this.exception = exception;
71         }
72     }
73
74     /**
75      * Constructor.
76      *
77      * @param classPath the IClassPath to load resources from
78      * @param errorLogger the IErrorLogger
79      */

80     AnalysisCache(IClassPath classPath, IErrorLogger errorLogger) {
81         this.classPath = classPath;
82         this.errorLogger = errorLogger;
83         this.classAnalysisEngineMap = new HashMap JavaDoc<Class JavaDoc<?>, IClassAnalysisEngine>();
84         this.methodAnalysisEngineMap = new HashMap JavaDoc<Class JavaDoc<?>, IMethodAnalysisEngine>();
85         this.databaseFactoryMap = new HashMap JavaDoc<Class JavaDoc<?>, IDatabaseFactory<?>>();
86         
87         this.classAnalysisMap = new HashMap JavaDoc<Class JavaDoc<?>, Map JavaDoc<ClassDescriptor,Object JavaDoc>>();
88         this.methodAnalysisMap = new HashMap JavaDoc<Class JavaDoc<?>, Map JavaDoc<MethodDescriptor,Object JavaDoc>>();
89         
90         this.databaseMap = new HashMap JavaDoc<Class JavaDoc<?>, Object JavaDoc>();
91     }
92     
93     /* (non-Javadoc)
94      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#getClassPath()
95      */

96     public IClassPath getClassPath() {
97         return classPath;
98     }
99
100     /* (non-Javadoc)
101      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#getClassAnalysis(java.lang.Class, edu.umd.cs.findbugs.classfile.ClassDescriptor)
102      */

103     public <E> E getClassAnalysis(Class JavaDoc<E> analysisClass,
104             ClassDescriptor classDescriptor) throws CheckedAnalysisException {
105         return analyzeClassOrMethod(
106                 this,
107                 classAnalysisMap,
108                 classAnalysisEngineMap,
109                 classDescriptor,
110                 analysisClass);
111     }
112     
113     /* (non-Javadoc)
114      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#probeClassAnalysis(java.lang.Class, edu.umd.cs.findbugs.classfile.ClassDescriptor)
115      */

116     public <E> E probeClassAnalysis(Class JavaDoc<E> analysisClass, ClassDescriptor classDescriptor) {
117         Map JavaDoc<ClassDescriptor, Object JavaDoc> descriptorMap = classAnalysisMap.get(analysisClass);
118         if (descriptorMap == null) {
119             return null;
120         }
121         return (E) descriptorMap.get(classDescriptor);
122     }
123
124     /* (non-Javadoc)
125      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#getMethodAnalysis(java.lang.Class, edu.umd.cs.findbugs.classfile.MethodDescriptor)
126      */

127     public <E> E getMethodAnalysis(Class JavaDoc<E> analysisClass,
128             MethodDescriptor methodDescriptor) throws CheckedAnalysisException {
129         return analyzeClassOrMethod(
130                 this,
131                 methodAnalysisMap,
132                 methodAnalysisEngineMap,
133                 methodDescriptor,
134                 analysisClass);
135     }
136     
137     /**
138      * Analyze a class or method,
139      * or get the cached analysis result.
140      *
141      * @param <DescriptorType> type of descriptor (class or method)
142      * @param <E> type of analysis result
143      * @param analysisCache the IAnalysisCache object
144      * @param analysisClassToDescriptorMapMap the map of analysis classes to descriptor->result maps
145      * @param engineMap engine map for this kind of descriptor
146      * @param descriptor the class or method descriptor
147      * @param analysisClass the analysis result type Class object
148      * @return the analysis result object
149      * @throws CheckedAnalysisException if an analysis error occurs
150      */

151     static<DescriptorType, E> E analyzeClassOrMethod(
152             final AnalysisCache analysisCache,
153             final Map JavaDoc<Class JavaDoc<?>, Map JavaDoc<DescriptorType, Object JavaDoc>> analysisClassToDescriptorMapMap,
154             final Map JavaDoc<Class JavaDoc<?>, ? extends IAnalysisEngine<DescriptorType>> engineMap,
155             final DescriptorType descriptor,
156             final Class JavaDoc<E> analysisClass
157     ) throws CheckedAnalysisException {
158         
159         // Get the descriptor->result map for this analysis class,
160
// creating if necessary
161
Map JavaDoc<DescriptorType, Object JavaDoc> descriptorMap = analysisClassToDescriptorMapMap.get(analysisClass);
162         if (descriptorMap == null) {
163             // Create a MapCache that allows the analysis engine to
164
// decide that analysis results should be retained indefinitely.
165
descriptorMap = new MapCache<DescriptorType, Object JavaDoc>(CACHE_SIZE) {
166                 IAnalysisEngine<DescriptorType> engine = engineMap.get(analysisClass);
167                 
168                 /* (non-Javadoc)
169                  * @see edu.umd.cs.findbugs.util.MapCache#removeEldestEntry(java.util.Map.Entry)
170                  */

171                 @Override JavaDoc
172                 protected boolean removeEldestEntry(Entry<DescriptorType, Object JavaDoc> eldest) {
173                     if (engine.retainAnalysisResults()) {
174                         return false;
175                     } else {
176                         return super.removeEldestEntry(eldest);
177                     }
178                 }
179             };
180             analysisClassToDescriptorMapMap.put(analysisClass, descriptorMap);
181         }
182         
183         // See if there is a cached result in the descriptor map
184
Object JavaDoc analysisResult = descriptorMap.get(descriptor);
185         if (analysisResult == null) {
186             // No cached result - compute (or recompute)
187
IAnalysisEngine<DescriptorType> engine = engineMap.get(analysisClass);
188             if (engine == null) {
189                 throw new IllegalArgumentException JavaDoc(
190                         "No analysis engine registered to produce " + analysisClass.getName());
191             }
192             
193             // Perform the analysis
194
try {
195                 analysisResult = engine.analyze(analysisCache, descriptor);
196             } catch (CheckedAnalysisException e) {
197                 // Whoops, an error occurred when performing the analysis.
198
// Make a note.
199
analysisResult = new AnalysisError(e);
200             }
201
202             // Save the result
203
descriptorMap.put(descriptor, analysisResult);
204         }
205
206         // Error occurred?
207
if (analysisResult instanceof AnalysisError) {
208             throw ((AnalysisError) analysisResult).exception;
209         }
210         
211         // If we could assume a 1.5 or later JVM, the Class.cast()
212
// method could do this cast without a warning.
213
return (E) analysisResult;
214     }
215
216     /* (non-Javadoc)
217      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#registerClassAnalysisEngine(java.lang.Class, edu.umd.cs.findbugs.classfile.IClassAnalysisEngine)
218      */

219     public <E> void registerClassAnalysisEngine(Class JavaDoc<E> analysisResultType,
220             IClassAnalysisEngine classAnalysisEngine) {
221         classAnalysisEngineMap.put(analysisResultType, classAnalysisEngine);
222     }
223
224     /* (non-Javadoc)
225      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#registerMethodAnalysisEngine(java.lang.Class, edu.umd.cs.findbugs.classfile.IMethodAnalysisEngine)
226      */

227     public <E> void registerMethodAnalysisEngine(Class JavaDoc<E> analysisResultType,
228             IMethodAnalysisEngine methodAnalysisEngine) {
229         methodAnalysisEngineMap.put(analysisResultType, methodAnalysisEngine);
230     }
231     
232     /* (non-Javadoc)
233      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#registerDatabaseFactory(java.lang.Class, edu.umd.cs.findbugs.classfile.IDatabaseFactory)
234      */

235     public <E> void registerDatabaseFactory(Class JavaDoc<E> databaseClass, IDatabaseFactory<E> databaseFactory) {
236         databaseFactoryMap.put(databaseClass, databaseFactory);
237     }
238     
239     /* (non-Javadoc)
240      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#getDatabase(java.lang.Class)
241      */

242     public <E> E getDatabase(Class JavaDoc<E> databaseClass) throws CheckedAnalysisException {
243         Object JavaDoc database = databaseMap.get(databaseClass);
244         
245         if (database == null) {
246             try {
247                 // Find the database factory
248
IDatabaseFactory<?> databaseFactory = databaseFactoryMap.get(databaseClass);
249                 if (databaseFactory == null) {
250                     throw new IllegalArgumentException JavaDoc(
251                             "No database factory registered for " + databaseClass.getName());
252                 }
253                 
254                 // Create the database
255
database = databaseFactory.createDatabase();
256             } catch (CheckedAnalysisException e) {
257                 // Error - record the analysis error
258
database = new AnalysisError(e);
259             }
260             
261             databaseMap.put(databaseClass, database);
262         }
263         
264         if (database instanceof AnalysisError) {
265             throw ((AnalysisError)database).exception;
266         }
267         
268         // Again, we really should be using Class.cast()
269
return (E) database;
270     }
271
272     /* (non-Javadoc)
273      * @see edu.umd.cs.findbugs.classfile.IAnalysisCache#getErrorLogger()
274      */

275     public IErrorLogger getErrorLogger() {
276         return errorLogger;
277     }
278 }
279
Popular Tags