KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > Loader


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist;
17
18 import java.io.*;
19 import java.util.Hashtable JavaDoc;
20 import java.util.Vector JavaDoc;
21
22 /**
23  * The class loader for Javassist.
24  *
25  * <p>This is a sample class loader using <code>ClassPool</code>.
26  * Unlike a regular class loader, this class loader obtains bytecode
27  * from a <code>ClassPool</code>.
28  *
29  * <p>Note that Javassist can be used without this class loader; programmers
30  * can define their own versions of class loader. They can run
31  * a program even without any user-defined class loader if that program
32  * is statically translated with Javassist.
33  * This class loader is just provided as a utility class.
34  *
35  * <p>Suppose that an instance of <code>MyTranslator</code> implementing
36  * the interface <code>Translator</code> is responsible for modifying
37  * class files.
38  * The startup program of an application using <code>MyTranslator</code>
39  * should be something like this:
40  *
41  * <ul><pre>
42  * import javassist.*;
43  *
44  * public class Main {
45  * public static void main(String[] args) throws Throwable {
46  * MyTranslator myTrans = new MyTranslator();
47  * ClassPool cp = ClassPool.getDefault();
48  * Loader cl = new Loader(cp);
49  * cl.addTranslator(cp, myTrans);
50  * cl.run("MyApp", args);
51  * }
52  * }
53  * </pre></ul>
54  *
55  * <p>Class <code>MyApp</code> is the main program of the application.
56  *
57  * <p>This program should be executed as follows:
58  *
59  * <ul><pre>
60  * % java Main <i>arg1</i> <i>arg2</i>...
61  * </pre></ul>
62  *
63  * <p>It modifies the class <code>MyApp</code> with a <code>MyTranslator</code>
64  * object before the JVM loads it.
65  * Then it calls <code>main()</code> in <code>MyApp</code> with arguments
66  * <i>arg1</i>, <i>arg2</i>, ...
67  *
68  * <p>This program execution is equivalent to:
69  *
70  * <ul><pre>
71  * % java MyApp <i>arg1</i> <i>arg2</i>...
72  * </pre></ul>
73  *
74  * <p>except that classes are translated by <code>MyTranslator</code>
75  * at load time.
76  *
77  * <p>If only a particular class must be modified when it is loaded,
78  * the startup program can be simpler; <code>MyTranslator</code> is
79  * unnecessary. For example, if only a class <code>test.Rectangle</code>
80  * is modified, the <code>main()</code> method above will be the following:
81  *
82  * <ul><pre>
83  * ClassPool cp = ClassPool.getDefault();
84  * Loader cl = new Loader(cp);
85  * CtClass ct = cp.get("test.Rectangle");
86  * ct.setSuperclass(cp.get("test.Point"));
87  * cl.run("MyApp", args);</pre></ul>
88  *
89  * <p>This program changes the super class of the <code>test.Rectangle</code>
90  * class.
91  *
92  * <p><b>Note 1:</b>
93  *
94  * <p>This class loader does not allow the users to intercept the loading
95  * of <code>java.*</code> and <code>javax.*</code> classes unless
96  * <code>Loader.doDelegation</code> is <code>false</code>. Also see
97  * Note 2.
98  *
99  * <p><b>Note 2:</b>
100  *
101  * <p>If classes are loaded with different class loaders, they belong to
102  * separate name spaces. If class <code>C</code> is loaded by a class
103  * loader <code>CL</code>, all classes that the class <code>C</code>
104  * refers to are also loaded by <code>CL</code>. However, if <code>CL</code>
105  * delegates the loading of the class <code>C</code> to <code>CL'</code>,
106  * then those classes that the class <code>C</code> refers to
107  * are loaded by a parent class loader <code>CL'</code>
108  * instead of <code>CL</code>.
109  *
110  * <p>If an object of class <code>C</code> is assigned
111  * to a variable of class <code>C</code> belonging to a different name
112  * space, then a <code>ClassCastException</code> is thrown.
113  *
114  * <p>Because of the fact above, this loader delegates only the loading of
115  * <code>javassist.Loader</code>
116  * and classes included in package <code>java.*</code> and
117  * <code>javax.*</code> to the parent class
118  * loader. Other classes are directly loaded by this loader.
119  *
120  * <p>For example, suppose that <code>java.lang.String</code> would be loaded
121  * by this loader while <code>java.io.File</code> is loaded by the parent
122  * class loader. If the constructor of <code>java.io.File</code> is called
123  * with an instance of <code>java.lang.String</code>, then it may throw
124  * an exception since it accepts an instance of only the
125  * <code>java.lang.String</code> loaded by the parent class loader.
126  *
127  * @see javassist.ClassPool
128  * @see javassist.Translator
129  */

130 public class Loader extends ClassLoader JavaDoc {
131     private Hashtable JavaDoc notDefinedHere; // must be atomic.
132
private Vector JavaDoc notDefinedPackages; // must be atomic.
133
private ClassPool source;
134     private Translator translator;
135
136     /**
137      * Specifies the algorithm of class loading.
138      *
139      * <p>This class loader uses the parent class loader for
140      * <code>java.*</code> and <code>javax.*</code> classes.
141      * If this variable <code>doDelegation</code>
142      * is <code>false</code>, this class loader does not delegate those
143      * classes to the parent class loader.
144      *
145      * <p>The default value is <code>true</code>.
146      */

147     public boolean doDelegation = true;
148
149     /**
150      * Creates a new class loader.
151      */

152     public Loader() {
153         this(null);
154     }
155
156     /**
157      * Creates a new class loader.
158      *
159      * @param cp the source of class files.
160      */

161     public Loader(ClassPool cp) {
162         init(cp);
163     }
164
165     /**
166      * Creates a new class loader
167      * using the specified parent class loader for delegation.
168      *
169      * @param parent the parent class loader.
170      * @param cp the source of class files.
171      */

172     public Loader(ClassLoader JavaDoc parent, ClassPool cp) {
173         super(parent);
174         init(cp);
175     }
176
177     private void init(ClassPool cp) {
178         notDefinedHere = new Hashtable JavaDoc();
179         notDefinedPackages = new Vector JavaDoc();
180         source = cp;
181         translator = null;
182         delegateLoadingOf("javassist.Loader");
183     }
184
185     /**
186      * Records a class so that the loading of that class is delegated
187      * to the parent class loader.
188      *
189      * <p>If the given class name ends with <code>.</code> (dot), then
190      * that name is interpreted as a package name. All the classes
191      * in that package and the sub packages are delegated.
192      */

193     public void delegateLoadingOf(String JavaDoc classname) {
194         if (classname.endsWith("."))
195             notDefinedPackages.addElement(classname);
196         else
197             notDefinedHere.put(classname, this);
198     }
199
200     /**
201      * Sets the soruce <code>ClassPool</code>.
202      */

203     public void setClassPool(ClassPool cp) {
204         source = cp;
205     }
206
207     /**
208      * Adds a translator, which is called whenever a class is loaded.
209      *
210      * @param cp the <code>ClassPool</code> object for obtaining
211      * a class file.
212      * @param t a translator.
213      * @throws NotFoundException if <code>t.start()</code> throws an exception.
214      * @throws CannotCompileException if <code>t.start()</code> throws an exception.
215      */

216     public void addTranslator(ClassPool cp, Translator t)
217         throws NotFoundException, CannotCompileException {
218         source = cp;
219         translator = t;
220         t.start(cp);
221     }
222
223     /**
224      * Loads a class with an instance of <code>Loader</code>
225      * and calls <code>main()</code> of that class.
226      *
227      * <p>This method calls <code>run()</code>.
228      *
229      * @param args command line parameters.
230      * <ul>
231      * <code>args[0]</code> is the class name to be loaded.
232      * <br><code>args[1..n]</code> are parameters passed
233      * to the target <code>main()</code>.
234      * </ul>
235      *
236      * @see javassist.Loader#run(String[])
237      */

238     public static void main(String JavaDoc[] args) throws Throwable JavaDoc {
239         Loader cl = new Loader();
240         cl.run(args);
241     }
242
243     /**
244      * Loads a class and calls <code>main()</code> in that class.
245      *
246      * @param args command line parameters.
247      * <ul>
248      * <code>args[0]</code> is the class name to be loaded.
249      * <br><code>args[1..n]</code> are parameters passed
250      * to the target <code>main()</code>.
251      * </ul>
252      */

253     public void run(String JavaDoc[] args) throws Throwable JavaDoc {
254         int n = args.length - 1;
255         if (n >= 0) {
256             String JavaDoc[] args2 = new String JavaDoc[n];
257             for (int i = 0; i < n; ++i)
258                 args2[i] = args[i + 1];
259
260             run(args[0], args2);
261         }
262     }
263
264     /**
265      * Loads a class and calls <code>main()</code> in that class.
266      *
267      * @param classname the loaded class.
268      * @param args parameters passed to <code>main()</code>.
269      */

270     public void run(String JavaDoc classname, String JavaDoc[] args) throws Throwable JavaDoc {
271         Class JavaDoc c = loadClass(classname);
272         try {
273             c.getDeclaredMethod("main", new Class JavaDoc[] { String JavaDoc[].class }).invoke(
274                 null,
275                 new Object JavaDoc[] { args });
276         }
277         catch (java.lang.reflect.InvocationTargetException JavaDoc e) {
278             throw e.getTargetException();
279         }
280     }
281
282     /**
283      * Requests the class loader to load a class.
284      */

285     protected Class JavaDoc loadClass(String JavaDoc name, boolean resolve)
286         throws ClassFormatError JavaDoc, ClassNotFoundException JavaDoc {
287         Class JavaDoc c = findLoadedClass(name);
288         if (c == null)
289             c = loadClassByDelegation(name);
290
291         if (c == null)
292             c = findClass(name);
293
294         if (c == null)
295             c = delegateToParent(name);
296
297         if (resolve)
298             resolveClass(c);
299
300         return c;
301     }
302
303     /**
304      * Finds the specified class using <code>ClassPath</code>.
305      * If the source throws an exception, this returns null.
306      *
307      * <p>This method can be overridden by a subclass of
308      * <code>Loader</code>. Note that the overridden method must not throw
309      * an exception when it just fails to find a class file.
310      *
311      * @return null if the specified class could not be found.
312      * @throws ClassNotFoundException if an exception is thrown while
313      * obtaining a class file.
314      */

315     protected Class JavaDoc findClass(String JavaDoc name) throws ClassNotFoundException JavaDoc {
316         byte[] classfile;
317         try {
318             if (source != null) {
319                 if (translator != null)
320                     translator.onLoad(source, name);
321
322                 try {
323                     classfile = source.get(name).toBytecode();
324                 }
325                 catch (NotFoundException e) {
326                     return null;
327                 }
328             }
329             else {
330                 String JavaDoc jarname = "/" + name.replace('.', '/') + ".class";
331                 InputStream in = this.getClass().getResourceAsStream(jarname);
332                 if (in == null)
333                     return null;
334
335                 classfile = ClassPoolTail.readStream(in);
336             }
337         }
338         catch (Exception JavaDoc e) {
339             throw new ClassNotFoundException JavaDoc(
340                 "caught an exception while obtaining a class file for "
341                 + name, e);
342         }
343
344         int i = name.lastIndexOf('.');
345         if (i != -1) {
346             String JavaDoc pname = name.substring(0, i);
347             if (getPackage(pname) == null)
348                 try {
349                     definePackage(
350                         pname, null, null, null, null, null, null, null);
351                 }
352                 catch (IllegalArgumentException JavaDoc e) {
353                     // ignore. maybe the package object for the same
354
// name has been created just right away.
355
}
356         }
357
358         return defineClass(name, classfile, 0, classfile.length);
359     }
360
361     protected Class JavaDoc loadClassByDelegation(String JavaDoc name)
362         throws ClassNotFoundException JavaDoc
363     {
364         /* The swing components must be loaded by a system
365          * class loader.
366          * javax.swing.UIManager loads a (concrete) subclass
367          * of LookAndFeel by a system class loader and cast
368          * an instance of the class to LookAndFeel for
369          * (maybe) a security reason. To avoid failure of
370          * type conversion, LookAndFeel must not be loaded
371          * by this class loader.
372          */

373
374         Class JavaDoc c = null;
375         if (doDelegation)
376             if (name.startsWith("java.")
377                 || name.startsWith("javax.")
378                 || name.startsWith("sun.")
379                 || name.startsWith("com.sun.")
380                 || name.startsWith("org.w3c.")
381                 || name.startsWith("org.xml.")
382                 || notDelegated(name))
383                 c = delegateToParent(name);
384
385         return c;
386     }
387
388     private boolean notDelegated(String JavaDoc name) {
389         if (notDefinedHere.get(name) != null)
390             return true;
391
392         int n = notDefinedPackages.size();
393         for (int i = 0; i < n; ++i)
394             if (name.startsWith((String JavaDoc)notDefinedPackages.elementAt(i)))
395                 return true;
396
397         return false;
398     }
399
400     protected Class JavaDoc delegateToParent(String JavaDoc classname)
401         throws ClassNotFoundException JavaDoc
402     {
403         ClassLoader JavaDoc cl = getParent();
404         if (cl != null)
405             return cl.loadClass(classname);
406         else
407             return findSystemClass(classname);
408     }
409
410     protected Package JavaDoc getPackage(String JavaDoc name) {
411         return super.getPackage(name);
412     }
413     /*
414         // Package p = super.getPackage(name);
415         Package p = null;
416         if (p == null)
417             return definePackage(name, null, null, null,
418                                  null, null, null, null);
419         else
420             return p;
421     }
422     */

423 }
424
Popular Tags