~ubuntu-branches/ubuntu/natty/aspectj/natty

« back to all changes in this revision

Viewing changes to org.aspectj/modules/bcel-builder/src/org/aspectj/apache/bcel/util/ClassLoaderRepository.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-10-04 16:37:23 UTC
  • mfrom: (1.1.3 upstream) (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20091004163723-ck4y7j7fhjxskkie
Tags: 1.6.6+dfsg-1
* New upstream release.
  - Update 02_use_gjdoc.diff patch
* Update my email address

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
package org.aspectj.apache.bcel.util;
2
 
 
3
 
/* ====================================================================
4
 
 * The Apache Software License, Version 1.1
5
 
 *
6
 
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
7
 
 * reserved.
8
 
 *
9
 
 * Redistribution and use in source and binary forms, with or without
10
 
 * modification, are permitted provided that the following conditions
11
 
 * are met:
12
 
 *
13
 
 * 1. Redistributions of source code must retain the above copyright
14
 
 *    notice, this list of conditions and the following disclaimer.
15
 
 *
16
 
 * 2. Redistributions in binary form must reproduce the above copyright
17
 
 *    notice, this list of conditions and the following disclaimer in
18
 
 *    the documentation and/or other materials provided with the
19
 
 *    distribution.
20
 
 *
21
 
 * 3. The end-user documentation included with the redistribution,
22
 
 *    if any, must include the following acknowledgment:
23
 
 *       "This product includes software developed by the
24
 
 *        Apache Software Foundation (http://www.apache.org/)."
25
 
 *    Alternately, this acknowledgment may appear in the software itself,
26
 
 *    if and wherever such third-party acknowledgments normally appear.
27
 
 *
28
 
 * 4. The names "Apache" and "Apache Software Foundation" and
29
 
 *    "Apache BCEL" must not be used to endorse or promote products
30
 
 *    derived from this software without prior written permission. For
31
 
 *    written permission, please contact apache@apache.org.
32
 
 *
33
 
 * 5. Products derived from this software may not be called "Apache",
34
 
 *    "Apache BCEL", nor may "Apache" appear in their name, without
35
 
 *    prior written permission of the Apache Software Foundation.
36
 
 *
37
 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38
 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40
 
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41
 
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42
 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43
 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44
 
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45
 
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46
 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47
 
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
 
 * SUCH DAMAGE.
49
 
 * ====================================================================
50
 
 *
51
 
 * This software consists of voluntary contributions made by many
52
 
 * individuals on behalf of the Apache Software Foundation.  For more
53
 
 * information on the Apache Software Foundation, please see
54
 
 * <http://www.apache.org/>.
55
 
 */
56
 
 
57
 
import java.io.IOException;
58
 
import java.io.InputStream;
59
 
import java.lang.ref.Reference;
60
 
import java.lang.ref.ReferenceQueue;
61
 
import java.lang.ref.SoftReference;
62
 
import java.net.URL;
63
 
import java.net.URLClassLoader;
64
 
import java.util.AbstractMap;
65
 
import java.util.Collections;
66
 
import java.util.HashMap;
67
 
import java.util.Map;
68
 
import java.util.Set;
69
 
import java.util.WeakHashMap;
70
 
 
71
 
import org.aspectj.apache.bcel.classfile.ClassParser;
72
 
import org.aspectj.apache.bcel.classfile.JavaClass;
73
 
 
74
 
/**
75
 
 * The repository maintains information about which classes have
76
 
 * been loaded.
77
 
 *
78
 
 * It loads its data from the ClassLoader implementation
79
 
 * passed into its constructor.
80
 
 *
81
 
 * @see org.aspectj.apache.bcel.Repository
82
 
 *
83
 
 * @version $Id: ClassLoaderRepository.java,v 1.9 2006/10/12 19:58:18 aclement Exp $
84
 
 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
85
 
 * @author David Dixon-Peugh
86
 
 */
87
 
public class ClassLoaderRepository implements Repository {
88
 
  private static java.lang.ClassLoader bootClassLoader = null;
89
 
  private java.lang.ClassLoader loader;
90
 
  
91
 
  // Choice of cache...
92
 
  private         WeakHashMap /*<URL,SoftRef(JavaClass)>*/localCache = new WeakHashMap(); 
93
 
  private static SoftHashMap /*<URL,JavaClass>*/sharedCache = new SoftHashMap(Collections.synchronizedMap(new HashMap()));
94
 
  
95
 
  // For fast translation of the classname *intentionally not static*
96
 
  private SoftHashMap /*<String,URL>*/ nameMap = new SoftHashMap(new HashMap(), false);
97
 
  
98
 
  public static boolean useSharedCache = 
99
 
          System.getProperty("org.aspectj.apache.bcel.useSharedCache","true").equalsIgnoreCase("true");
100
 
  
101
 
  private static int  cacheHitsShared    = 0;
102
 
  private static int  missSharedEvicted  = 0; // Misses in shared cache access due to reference GC
103
 
  private long timeManipulatingURLs = 0L; 
104
 
  private long timeSpentLoading     = 0L;
105
 
  private int  classesLoadedCount = 0;
106
 
  private int  misses             = 0;
107
 
  private int  cacheHitsLocal     = 0;
108
 
  private int  missLocalEvicted   = 0; // Misses in local cache access due to reference GC
109
 
 
110
 
  public ClassLoaderRepository( java.lang.ClassLoader loader ) {
111
 
      this.loader = (loader != null) ? loader : getBootClassLoader();
112
 
  }
113
 
  
114
 
  private static synchronized java.lang.ClassLoader getBootClassLoader() {
115
 
          if (bootClassLoader == null) {
116
 
                  bootClassLoader = new URLClassLoader(new URL[0]);
117
 
          }
118
 
          return bootClassLoader;
119
 
  }
120
 
  
121
 
  // Can track back to its key
122
 
  public static class SoftHashMap extends AbstractMap {
123
 
          private Map map;
124
 
          boolean recordMiss = true; // only interested in recording miss stats sometimes
125
 
          private ReferenceQueue rq = new ReferenceQueue(); 
126
 
          
127
 
      public SoftHashMap(Map map) { this.map = map; }
128
 
          public SoftHashMap() { this(new HashMap()); }
129
 
          public SoftHashMap(Map map, boolean b) { this(map); this.recordMiss=b;}
130
 
        
131
 
          class SpecialValue extends SoftReference {
132
 
                  private final Object key;
133
 
                  SpecialValue(Object k,Object v) {
134
 
                    super(v,rq);
135
 
                    this.key = k;
136
 
                  }
137
 
          }  
138
 
 
139
 
          private void processQueue() {
140
 
                SpecialValue sv = null;
141
 
                while ((sv = (SpecialValue)rq.poll())!=null) {
142
 
                        map.remove(sv.key);
143
 
                }
144
 
          }
145
 
        
146
 
          public Object get(Object key) {
147
 
                SpecialValue value = (SpecialValue)map.get(key);
148
 
                if (value==null) return null;
149
 
                if (value.get()==null) {
150
 
                        // it got GC'd
151
 
                        map.remove(value.key);
152
 
                        if (recordMiss) missSharedEvicted++;
153
 
                        return null;
154
 
                } else {
155
 
                        return value.get();
156
 
                }
157
 
          }
158
 
 
159
 
          public Object put(Object k, Object v) {
160
 
                processQueue();
161
 
                return map.put(k, new SpecialValue(k,v));
162
 
          }
163
 
 
164
 
          public Set entrySet() {
165
 
                return map.entrySet();
166
 
          }
167
 
        
168
 
          public void clear() {
169
 
                processQueue();
170
 
                map.clear();
171
 
          }
172
 
        
173
 
          public int size() {
174
 
                processQueue();
175
 
                return map.size();
176
 
          }
177
 
        
178
 
          public Object remove(Object k) {
179
 
                processQueue();
180
 
                SpecialValue value = (SpecialValue)map.remove(k);
181
 
                if (value==null) return null;
182
 
                if (value.get()!=null) {
183
 
                        return value.get();
184
 
                }
185
 
                return null;
186
 
          }
187
 
  }
188
 
 
189
 
  /**
190
 
   * Store a new JavaClass into this repository as a soft reference and return the reference
191
 
   */
192
 
  private void storeClassAsReference(URL url, JavaClass clazz ) {
193
 
        if (useSharedCache) {
194
 
                clazz.setRepository(null); // can't risk setting repository, we'll get in a pickle!
195
 
                sharedCache.put(url, clazz);
196
 
        } else {
197
 
            clazz.setRepository(this);
198
 
                localCache.put(url, new SoftReference(clazz));
199
 
        }
200
 
  }
201
 
  
202
 
  /**
203
 
   * Store a new JavaClass into this Repository.
204
 
   */
205
 
  public void storeClass( JavaClass clazz ) {
206
 
          storeClassAsReference(toURL(clazz.getClassName()),clazz);
207
 
  }
208
 
 
209
 
  /**
210
 
   * Remove class from repository
211
 
   */
212
 
  public void removeClass(JavaClass clazz) {
213
 
    if (useSharedCache) sharedCache.remove(toURL(clazz.getClassName()));
214
 
    else                localCache.remove(toURL(clazz.getClassName()));
215
 
  }
216
 
 
217
 
  /**
218
 
   * Find an already defined JavaClass in the local cache.
219
 
   */
220
 
  public JavaClass findClass( String className ) {
221
 
          if (useSharedCache) return findClassShared(toURL(className));
222
 
          else                return findClassLocal(toURL(className));
223
 
  }
224
 
  
225
 
  private JavaClass findClassLocal( URL url ) {
226
 
    Object o = localCache.get(url);
227
 
    if (o != null) {
228
 
        o = ((Reference)o).get();
229
 
        if (o != null) {
230
 
                return (JavaClass)o;
231
 
        } else {
232
 
                missLocalEvicted++;
233
 
        }
234
 
    }
235
 
    return null;
236
 
  }
237
 
  
238
 
  /**
239
 
   * Find an already defined JavaClass in the shared cache.
240
 
   */
241
 
  private JavaClass findClassShared(URL url) {
242
 
          return (JavaClass)sharedCache.get(url);
243
 
  }
244
 
 
245
 
  private URL toURL(String className) {
246
 
          URL url = (URL)nameMap.get(className);
247
 
          if (url==null) {
248
 
                  String classFile = className.replace('.', '/');
249
 
              url = loader.getResource( classFile + ".class" );
250
 
              nameMap.put(className, url);
251
 
          }
252
 
      return url;
253
 
  }
254
 
  
255
 
  /**
256
 
   * Lookup a JavaClass object from the Class Name provided.
257
 
   */
258
 
  public JavaClass loadClass( String className ) throws ClassNotFoundException {
259
 
    
260
 
        // translate to a URL
261
 
        long time = System.currentTimeMillis();
262
 
    java.net.URL url = toURL(className);
263
 
        timeManipulatingURLs += (System.currentTimeMillis() - time);
264
 
        if (url==null) throw new ClassNotFoundException(className + " not found - unable to determine URL");
265
 
    
266
 
        JavaClass clazz = null;
267
 
 
268
 
        // Look in the appropriate cache
269
 
        if (useSharedCache) {
270
 
                clazz = findClassShared(url);
271
 
                if (clazz != null) { cacheHitsShared++; return clazz; }         
272
 
        } else {
273
 
            clazz = findClassLocal(url);
274
 
            if (clazz != null) { cacheHitsLocal++; return clazz; }
275
 
        }
276
 
    
277
 
        // Didn't find it in either cache
278
 
        misses++;
279
 
 
280
 
    try {       
281
 
        // Load it
282
 
            String classFile = className.replace('.', '/');
283
 
                InputStream is = (useSharedCache?url.openStream():loader.getResourceAsStream( classFile + ".class" ));
284
 
            if (is == null) { 
285
 
                  throw new ClassNotFoundException(className + " not found "+(url==null?"":"- using url "+url));
286
 
            }
287
 
                ClassParser parser = new ClassParser( is, className );
288
 
        clazz = parser.parse();
289
 
            
290
 
        // Cache it
291
 
        storeClassAsReference(url, clazz );
292
 
 
293
 
        timeSpentLoading += (System.currentTimeMillis() - time);
294
 
            classesLoadedCount++;
295
 
        return clazz;
296
 
    } catch (IOException e) {
297
 
      throw new ClassNotFoundException( e.toString() );
298
 
    }
299
 
  }
300
 
  
301
 
 
302
 
  /**
303
 
   * Produce a report on cache usage.
304
 
   */
305
 
  public String report() {
306
 
          StringBuffer sb = new StringBuffer();
307
 
          sb.append("BCEL repository report.");
308
 
          if (useSharedCache) sb.append(" (shared cache)");
309
 
          else                sb.append(" (local cache)");
310
 
          sb.append(" Total time spent loading: "+timeSpentLoading+"ms.");
311
 
          sb.append(" Time spent manipulating URLs: "+timeManipulatingURLs+"ms.");
312
 
          sb.append(" Classes loaded: "+classesLoadedCount+".");
313
 
          if (useSharedCache) {
314
 
                  sb.append(" Shared cache size: "+sharedCache.size());
315
 
              sb.append(" Shared cache (hits/missDueToEviction): ("+cacheHitsShared+"/"+missSharedEvicted+").");
316
 
          } else {
317
 
                  sb.append(" Local cache size: "+localCache.size());
318
 
                  sb.append(" Local cache (hits/missDueToEviction): ("+cacheHitsLocal+"/"+missLocalEvicted+").");
319
 
          }
320
 
          return sb.toString();
321
 
  }
322
 
  
323
 
  /**
324
 
   * Returns an array of the stats, for testing, the order is fixed:
325
 
   * 0=time spent loading (static)
326
 
   * 1=time spent manipulating URLs (static)
327
 
   * 2=classes loaded (static)
328
 
   * 3=cache hits shared (static)
329
 
   * 4=misses in shared due to eviction (static)
330
 
   * 5=cache hits local
331
 
   * 6=misses in local due to eviction
332
 
   * 7=shared cache size
333
 
   */
334
 
  public long[] reportStats() {
335
 
          return new long[]{timeSpentLoading,timeManipulatingURLs,classesLoadedCount,
336
 
                                     cacheHitsShared,missSharedEvicted,cacheHitsLocal,missLocalEvicted,
337
 
                                     sharedCache.size()};
338
 
  }
339
 
  
340
 
  /**
341
 
   * Reset statistics and clear all caches
342
 
   */
343
 
  public void reset() {
344
 
          timeManipulatingURLs = 0L; 
345
 
          timeSpentLoading = 0L;
346
 
          classesLoadedCount = 0;
347
 
          cacheHitsLocal    = 0;
348
 
          cacheHitsShared   = 0;
349
 
          missSharedEvicted = 0; 
350
 
          missLocalEvicted  = 0; 
351
 
          misses = 0;
352
 
          clear();
353
 
  }
354
 
  
355
 
  
356
 
  public JavaClass loadClass(Class clazz) throws ClassNotFoundException {
357
 
    return loadClass(clazz.getName());
358
 
  }
359
 
 
360
 
  /** Clear all entries from the local cache */
361
 
  public void clear() {
362
 
          if (useSharedCache) sharedCache.clear();
363
 
          else                localCache.clear();
364
 
  }
365
 
  
366
 
}
367
 
 
368