View Javadoc

1   /*
2    * Copyright  2000-2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License"); 
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License. 
15   *
16   */
17  package org.apache.bcel.util;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.lang.ref.SoftReference;
22  import java.util.HashMap;
23  import java.util.Map;
24  import org.apache.bcel.classfile.ClassParser;
25  import org.apache.bcel.classfile.JavaClass;
26  
27  /***
28   * This repository is used in situations where a Class is created
29   * outside the realm of a ClassLoader. Classes are loaded from
30   * the file systems using the paths specified in the given
31   * class path. By default, this is the value returned by
32   * ClassPath.getClassPath().
33   * <br>
34   * It is designed to be used as a singleton, however it
35   * can also be used with custom classpaths.
36   *
37   /**
38   * Abstract definition of a class repository. Instances may be used
39   * to load classes from different sources and may be used in the
40   * Repository.setRepository method.
41   *
42   * @see org.apache.bcel.Repository
43   *
44   * @version $Id: SyntheticRepository.java 386056 2006-03-15 11:31:56Z tcurdt $
45   * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
46   * @author David Dixon-Peugh
47   */
48  public class SyntheticRepository implements Repository {
49  
50      private static final String DEFAULT_PATH = ClassPath.getClassPath();
51      private static Map _instances = new HashMap(); // CLASSPATH X REPOSITORY
52      private ClassPath _path = null;
53      private Map _loadedClasses = new HashMap(); // CLASSNAME X JAVACLASS
54  
55  
56      private SyntheticRepository(ClassPath path) {
57          _path = path;
58      }
59  
60  
61      public static SyntheticRepository getInstance() {
62          return getInstance(ClassPath.SYSTEM_CLASS_PATH);
63      }
64  
65  
66      public static SyntheticRepository getInstance( ClassPath classPath ) {
67          SyntheticRepository rep = (SyntheticRepository) _instances.get(classPath);
68          if (rep == null) {
69              rep = new SyntheticRepository(classPath);
70              _instances.put(classPath, rep);
71          }
72          return rep;
73      }
74  
75  
76      /***
77       * Store a new JavaClass instance into this Repository.
78       */
79      public void storeClass( JavaClass clazz ) {
80          _loadedClasses.put(clazz.getClassName(), new SoftReference(clazz));
81          clazz.setRepository(this);
82      }
83  
84  
85      /***
86       * Remove class from repository
87       */
88      public void removeClass( JavaClass clazz ) {
89          _loadedClasses.remove(clazz.getClassName());
90      }
91  
92  
93      /***
94       * Find an already defined (cached) JavaClass object by name.
95       */
96      public JavaClass findClass( String className ) {
97          SoftReference ref = (SoftReference) _loadedClasses.get(className);
98          if (ref == null) {
99              return null;
100         }
101         return (JavaClass) ref.get();
102     }
103 
104 
105     /***
106      * Find a JavaClass object by name.
107      * If it is already in this Repository, the Repository version
108      * is returned.  Otherwise, the Repository's classpath is searched for
109      * the class (and it is added to the Repository if found).
110      *
111      * @param className the name of the class
112      * @return the JavaClass object
113      * @throws ClassNotFoundException if the class is not in the
114      *   Repository, and could not be found on the classpath
115      */
116     public JavaClass loadClass( String className ) throws ClassNotFoundException {
117         if (className == null || className.equals("")) {
118             throw new IllegalArgumentException("Invalid class name " + className);
119         }
120         className = className.replace('/', '.'); // Just in case, canonical form
121         JavaClass clazz = findClass(className);
122         if (clazz != null) {
123             return clazz;
124         }
125         try {
126             return loadClass(_path.getInputStream(className), className);
127         } catch (IOException e) {
128             throw new ClassNotFoundException("Exception while looking for class " + className
129                     + ": " + e.toString());
130         }
131     }
132 
133 
134     /***
135      * Find the JavaClass object for a runtime Class object.
136      * If a class with the same name is already in this Repository,
137      * the Repository version is returned.  Otherwise, getResourceAsStream()
138      * is called on the Class object to find the class's representation.
139      * If the representation is found, it is added to the Repository.
140      *
141      * @see Class
142      * @param clazz the runtime Class object
143      * @return JavaClass object for given runtime class
144      * @throws ClassNotFoundException if the class is not in the
145      *   Repository, and its representation could not be found
146      */
147     public JavaClass loadClass( Class clazz ) throws ClassNotFoundException {
148         String className = clazz.getName();
149         JavaClass repositoryClass = findClass(className);
150         if (repositoryClass != null) {
151             return repositoryClass;
152         }
153         String name = className;
154         int i = name.lastIndexOf('.');
155         if (i > 0) {
156             name = name.substring(i + 1);
157         }
158         return loadClass(clazz.getResourceAsStream(name + ".class"), className);
159     }
160 
161 
162     private JavaClass loadClass( InputStream is, String className ) throws ClassNotFoundException {
163         try {
164             if (is != null) {
165                 ClassParser parser = new ClassParser(is, className);
166                 JavaClass clazz = parser.parse();
167                 storeClass(clazz);
168                 return clazz;
169             }
170         } catch (IOException e) {
171             throw new ClassNotFoundException("Exception while looking for class " + className
172                     + ": " + e.toString());
173         }
174         throw new ClassNotFoundException("SyntheticRepository could not load " + className);
175     }
176 
177 
178     /*** ClassPath associated with the Repository.
179      */
180     public ClassPath getClassPath() {
181         return _path;
182     }
183 
184 
185     /*** Clear all entries from cache.
186      */
187     public void clear() {
188         _loadedClasses.clear();
189     }
190 }