KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bcel > util > ClassLoader


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.ByteArrayInputStream JavaDoc;
20 import java.util.Hashtable JavaDoc;
21 import org.apache.bcel.Constants;
22 import org.apache.bcel.classfile.ClassParser;
23 import org.apache.bcel.classfile.ConstantClass;
24 import org.apache.bcel.classfile.ConstantPool;
25 import org.apache.bcel.classfile.ConstantUtf8;
26 import org.apache.bcel.classfile.JavaClass;
27 import org.apache.bcel.classfile.Utility;
28
29 /**
30  * <p>Drop in replacement for the standard class loader of the JVM. You can use it
31  * in conjunction with the JavaWrapper to dynamically modify/create classes
32  * as they're requested.</p>
33  *
34  * <p>This class loader recognizes special requests in a distinct
35  * format, i.e., when the name of the requested class contains with
36  * "$$BCEL$$" it calls the createClass() method with that name
37  * (everything bevor the $$BCEL$$ is considered to be the package
38  * name. You can subclass the class loader and override that
39  * method. "Normal" classes class can be modified by overriding the
40  * modifyClass() method which is called just before defineClass().</p>
41  *
42  * <p>There may be a number of packages where you have to use the
43  * default class loader (which may also be faster). You can define the
44  * set of packages where to use the system class loader in the
45  * constructor. The default value contains "java.", "sun.",
46  * "javax."</p>
47  *
48  * @version $Id: ClassLoader.java 386056 2006-03-15 11:31:56Z tcurdt $
49  * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
50  * @see JavaWrapper
51  * @see ClassPath
52  */

53 public class ClassLoader extends java.lang.ClassLoader JavaDoc {
54
55     public static final String JavaDoc[] DEFAULT_IGNORED_PACKAGES = {
56             "java.", "javax.", "sun."
57     };
58     private Hashtable JavaDoc classes = new Hashtable JavaDoc(); // Hashtable is synchronized thus thread-safe
59
private String JavaDoc[] ignored_packages;
60     private Repository repository = SyntheticRepository.getInstance();
61
62
63     /** Ignored packages are by default ( "java.", "sun.",
64      * "javax."), i.e. loaded by system class loader
65      */

66     public ClassLoader() {
67         this(DEFAULT_IGNORED_PACKAGES);
68     }
69
70
71     /** @param deferTo delegate class loader to use for ignored packages
72      */

73     public ClassLoader(java.lang.ClassLoader JavaDoc deferTo) {
74         super(deferTo);
75         this.ignored_packages = DEFAULT_IGNORED_PACKAGES;
76         this.repository = new ClassLoaderRepository(deferTo);
77     }
78
79
80     /** @param ignored_packages classes contained in these packages will be loaded
81      * with the system class loader
82      */

83     public ClassLoader(String JavaDoc[] ignored_packages) {
84         this.ignored_packages = ignored_packages;
85     }
86
87
88     /** @param ignored_packages classes contained in these packages will be loaded
89      * with the system class loader
90      * @param deferTo delegate class loader to use for ignored packages
91      */

92     public ClassLoader(java.lang.ClassLoader JavaDoc deferTo, String JavaDoc[] ignored_packages) {
93         this(ignored_packages);
94         this.repository = new ClassLoaderRepository(deferTo);
95     }
96
97
98     protected Class JavaDoc loadClass( String JavaDoc class_name, boolean resolve ) throws ClassNotFoundException JavaDoc {
99         Class JavaDoc cl = null;
100         /* First try: lookup hash table.
101          */

102         if ((cl = (Class JavaDoc) classes.get(class_name)) == null) {
103             /* Second try: Load system class using system class loader. You better
104              * don't mess around with them.
105              */

106             for (int i = 0; i < ignored_packages.length; i++) {
107                 if (class_name.startsWith(ignored_packages[i])) {
108                     cl = getParent().loadClass(class_name);
109                     break;
110                 }
111             }
112             if (cl == null) {
113                 JavaClass clazz = null;
114                 /* Third try: Special request?
115                  */

116                 if (class_name.indexOf("$$BCEL$$") >= 0) {
117                     clazz = createClass(class_name);
118                 } else { // Fourth try: Load classes via repository
119
if ((clazz = repository.loadClass(class_name)) != null) {
120                         clazz = modifyClass(clazz);
121                     } else {
122                         throw new ClassNotFoundException JavaDoc(class_name);
123                     }
124                 }
125                 if (clazz != null) {
126                     byte[] bytes = clazz.getBytes();
127                     cl = defineClass(class_name, bytes, 0, bytes.length);
128                 } else {
129                     cl = Class.forName(class_name);
130                 }
131             }
132             if (resolve) {
133                 resolveClass(cl);
134             }
135         }
136         classes.put(class_name, cl);
137         return cl;
138     }
139
140
141     /** Override this method if you want to alter a class before it gets actually
142      * loaded. Does nothing by default.
143      */

144     protected JavaClass modifyClass( JavaClass clazz ) {
145         return clazz;
146     }
147
148
149     /**
150      * Override this method to create you own classes on the fly. The
151      * name contains the special token $$BCEL$$. Everything before that
152      * token is consddered to be a package name. You can encode you own
153      * arguments into the subsequent string. You must regard however not
154      * to use any "illegal" characters, i.e., characters that may not
155      * appear in a Java class name too<br>
156      *
157      * The default implementation interprets the string as a encoded compressed
158      * Java class, unpacks and decodes it with the Utility.decode() method, and
159      * parses the resulting byte array and returns the resulting JavaClass object.
160      *
161      * @param class_name compressed byte code with "$$BCEL$$" in it
162      */

163     protected JavaClass createClass( String JavaDoc class_name ) {
164         int index = class_name.indexOf("$$BCEL$$");
165         String JavaDoc real_name = class_name.substring(index + 8);
166         JavaClass clazz = null;
167         try {
168             byte[] bytes = Utility.decode(real_name, true);
169             ClassParser parser = new ClassParser(new ByteArrayInputStream JavaDoc(bytes), "foo");
170             clazz = parser.parse();
171         } catch (Throwable JavaDoc e) {
172             e.printStackTrace();
173             return null;
174         }
175         // Adapt the class name to the passed value
176
ConstantPool cp = clazz.getConstantPool();
177         ConstantClass cl = (ConstantClass) cp.getConstant(clazz.getClassNameIndex(),
178                 Constants.CONSTANT_Class);
179         ConstantUtf8 name = (ConstantUtf8) cp.getConstant(cl.getNameIndex(),
180                 Constants.CONSTANT_Utf8);
181         name.setBytes(class_name.replace('.', '/'));
182         return clazz;
183     }
184 }
185
Popular Tags