1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();
52 private ClassPath _path = null;
53 private Map _loadedClasses = new HashMap();
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('/', '.');
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 }