KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > aop > standalone > SystemClassLoader


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.aop.standalone;
23
24 import java.io.File JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.lang.reflect.InvocationTargetException JavaDoc;
29 import java.lang.reflect.Method JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.security.AccessController JavaDoc;
32 import java.security.CodeSource JavaDoc;
33 import java.security.PrivilegedAction JavaDoc;
34 import java.security.PrivilegedActionException JavaDoc;
35 import java.security.PrivilegedExceptionAction JavaDoc;
36 import java.security.ProtectionDomain JavaDoc;
37 import java.security.cert.Certificate JavaDoc;
38 import java.util.Enumeration JavaDoc;
39
40 /**
41  * A classloader that can be installed as the system classloader
42  * to enable aop translation based on files in META-INF/jboss-aop.xml
43  * in the classpath.<p>
44  *
45  * You will need the following jars in your classpath (log4j.jar is optional):<p>
46  * <ul>
47  * <li>jboss-aop.jar</li>
48  * <li>javassist.jar</li>
49  * <li>jboss-common.jar</li>
50  * </ul>
51  *
52  * Start the virtual machine with something like the following command:
53  *
54  * <pre>
55  * java -Djava.system.class.loader=org.jboss.aop.standalone.SystemClassLoader my.Main
56  * </pre>
57  *
58  * Implementation Detail: All access to non-jre classes must be done through reflection the
59  * classes must be loaded using the loadLocally method.
60  *
61  * @todo The delegation for jre classes is important. Need to
62  * figure out how to do this generically
63  * @todo java security model, protection domain, etc.
64  * @author <a HREF="mailto:adrian@jboss.org">Adrian Brock</a>
65  * @author <a HREF="mailto:juha@jboss.org">Juha Lindfors</a>
66  * @version $Revision: 45832 $
67  */

68 public class SystemClassLoader
69    extends ClassLoader JavaDoc
70 {
71    /**
72     * Not yet installed as the system classloader
73     */

74    private static final int NOT_INSTALLED = 0;
75
76    /**
77     * Installed as the system classloader
78     */

79    private static final int INSTALLED = 1;
80
81    /**
82     * Installing the aspect manager
83     */

84    private static final int INITIALIZING = 2;
85
86    /**
87     * Aspect manager install
88     */

89    private static final int INITIALIZED = 3;
90
91    /**
92     * The current state
93     */

94    private int state = NOT_INSTALLED;
95
96    /**
97     * Our parent, the default system classloader
98     */

99    ClassLoader JavaDoc parent = null;
100
101
102    /**
103     * org.jboss.aop.AspectXmlDeployer.deployXML(java.util.URL url);
104     */

105    Method JavaDoc deployXML;
106
107    /** Translator.transform(ClassLoader loader, String name,
108     * Class classBeingRedefined, ProtectionDomain pd,
109     * byte[] classfileBuffer)
110     */

111    Method JavaDoc transform;
112
113    /**
114     * static org.jboss.aop.AspectManager.instance();
115     */

116    Method JavaDoc instance;
117
118    /**
119     * The aspect manager;
120     */

121    Object JavaDoc aspectManager;
122
123    /**
124     * Construct a new system classloader.<p>
125     *
126     * We cannot do much here, we need to avoid recursion
127     *
128     * @param parent the default system classloader
129     */

130    public SystemClassLoader(ClassLoader JavaDoc parent)
131    {
132       super(parent);
133       install();
134    }
135
136    /**
137     * Load a class, overridden to transform aop enhanced classes
138     * and load non jre classes through this classloader.
139     *
140     * @param name the class name
141     * @param resolve whether to resolve the class
142     * @return the class
143     * @throws ClassNotFoundException when there is no class
144     */

145    public synchronized Class JavaDoc loadClass(String JavaDoc name, boolean resolve)
146       throws ClassNotFoundException JavaDoc
147    {
148       // Have we already loaded the class?
149
Class JavaDoc clazz = findLoadedClass(name);
150       if (clazz != null)
151       {
152          if (resolve) resolveClass(clazz);
153          return clazz;
154       }
155
156       // Is it a jre class?
157
clazz = loadClassByDelegation(name);
158       if (clazz != null)
159       {
160          if (resolve) resolveClass(clazz);
161          return clazz;
162       }
163
164       // First non jre loadClass initializes
165
initialize();
166
167       // Load the class
168
try
169       {
170          ClassBytes origBytes = loadClassBytes(name);
171          ClassBytes classBytes = new ClassBytes();
172
173          // If we are initialized check for aop translation
174
if (state == INITIALIZED)
175          {
176             final Object JavaDoc[] args = {this, name, null, null, origBytes.bytes};
177             if (!name.startsWith("org.jboss.aop"))
178             {
179                classBytes.bytes = (byte[]) transform.invoke(aspectManager, args);
180                classBytes.protectionDomain = origBytes.protectionDomain;
181             }
182          }
183          if (classBytes.bytes == null)
184             classBytes = origBytes;
185
186          // Define the class
187
return defineClassFromBytes(name, classBytes, resolve);
188       }
189       catch (IOException JavaDoc ioe)
190       {
191          throw new ClassNotFoundException JavaDoc("Unable to load " + name, ioe);
192       }
193       catch (IllegalAccessException JavaDoc iae)
194       {
195          throw new Error JavaDoc(iae);
196       }
197       catch (InvocationTargetException JavaDoc ite)
198       {
199          throw new Error JavaDoc("Error transforming the class " + name, ite.getCause());
200       }
201    }
202
203    /**
204     * Load the bytecode for a class
205     */

206    protected ClassBytes loadClassBytes(String JavaDoc name)
207       throws ClassNotFoundException JavaDoc, IOException JavaDoc
208    {
209       final String JavaDoc classFileName = name.replace('.', '/') + ".class";
210       final URL JavaDoc url = (URL JavaDoc) AccessController.doPrivileged(new PrivilegedAction JavaDoc()
211       {
212          public Object JavaDoc run()
213          {
214             return getParent().getResource(classFileName);
215          }
216       });
217       ProtectionDomain JavaDoc protectionDomain = null;
218       InputStream JavaDoc in = null;
219       if (url != null)
220       {
221          try
222          {
223             in = (InputStream JavaDoc) AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc()
224             {
225                public Object JavaDoc run() throws Exception JavaDoc
226                {
227                   return url.openStream();
228                }
229             });
230          }
231          catch (PrivilegedActionException JavaDoc e)
232          {
233             throw new ClassNotFoundException JavaDoc(name, e);
234          }
235          String JavaDoc urlstring = url.toExternalForm();
236          URL JavaDoc urlCS = url;
237          if (urlstring.startsWith("jar:"))
238          {
239             int i = urlstring.indexOf('!');
240             String JavaDoc cs = urlstring.substring(4, i);
241             urlCS = new URL JavaDoc(cs);
242          }
243          else
244          {
245             int i = urlstring.indexOf(classFileName);
246             if (i != -1)
247             {
248                String JavaDoc cs = urlstring.substring(0, i);
249                urlCS = new URL JavaDoc(cs);
250             }
251          }
252          CodeSource JavaDoc codeSource = new CodeSource JavaDoc(urlCS, (Certificate JavaDoc[]) null);
253          protectionDomain = new ProtectionDomain JavaDoc(codeSource, null, this, null);
254       }
255       else
256       {
257          /* Try the system tmpdir/aopdynclasses, the default location
258          the AOPClassPool writes dynamic class files to.
259          */

260          try
261          {
262             in = (InputStream JavaDoc) AccessController.doPrivileged(new PrivilegedExceptionAction JavaDoc()
263             {
264                public Object JavaDoc run() throws Exception JavaDoc
265                {
266                   String JavaDoc tmpdir = System.getProperty("java.io.tmpdir");
267                   File JavaDoc aopdynclasses = new File JavaDoc(tmpdir, "aopdynclasses");
268                   File JavaDoc classFile = new File JavaDoc(aopdynclasses, classFileName);
269                   return new FileInputStream JavaDoc(classFile);
270                }
271             });
272          }
273          catch (PrivilegedActionException JavaDoc e)
274          {
275             throw new ClassNotFoundException JavaDoc(name, e);
276          }
277       }
278
279       byte[][] bufs = new byte[8][];
280       int bufsize = 4096;
281
282       for (int i = 0; i < 8; ++i)
283       {
284          bufs[i] = new byte[bufsize];
285          int size = 0;
286          int len = 0;
287          do
288          {
289             len = in.read(bufs[i], size, bufsize - size);
290             if (len >= 0)
291                size += len;
292             else
293             {
294                byte[] result = new byte[bufsize - 4096 + size];
295                int s = 0;
296                for (int j = 0; j < i; ++j)
297                {
298                   System.arraycopy(bufs[j], 0, result, s, s + 4096);
299                   s = s + s + 4096;
300                }
301
302                System.arraycopy(bufs[i], 0, result, s, size);
303                ClassBytes classBytes = new ClassBytes();
304                classBytes.bytes = result;
305                classBytes.protectionDomain = protectionDomain;
306                return classBytes;
307             }
308          }
309          while (size < bufsize);
310          bufsize *= 2;
311       }
312
313       throw new IOException JavaDoc("too much data loading class " + name);
314    }
315
316    /**
317     * Define a class from the bytes
318     *
319     * @name the class to define
320     * @param b the bytecode
321     * @param resolve whether to resolve the class
322     * @returns the class
323     */

324    protected Class JavaDoc defineClassFromBytes(String JavaDoc name, ClassBytes bytes, boolean resolve)
325    {
326       definePackage(name);
327       byte[] b = bytes.bytes;
328       Class JavaDoc clazz = defineClass(name, b, 0, b.length, bytes.protectionDomain);
329       if (resolve) resolveClass(clazz);
330       return clazz;
331    }
332
333    /**
334     * Define the package for the class if not already done
335     *
336     * @todo this properly
337     * @param name the class name
338     */

339    protected void definePackage(String JavaDoc className)
340    {
341       int i = className.lastIndexOf('.');
342       if (i == -1)
343          return;
344
345       try
346       {
347          definePackage(className.substring(0, i), null, null, null, null, null, null, null);
348       }
349       catch (IllegalArgumentException JavaDoc alreadyDone)
350       {
351       }
352    }
353
354    /**
355     * Load a class using this classloader only
356     *
357     * @param name the class name
358     * @return the class
359     * @throws ClassNotFoundException when there is no class
360     */

361    protected Class JavaDoc loadClassLocally(String JavaDoc name)
362       throws ClassNotFoundException JavaDoc
363    {
364       try
365       {
366          ClassBytes bytes = loadClassBytes(name);
367          return defineClassFromBytes(name, bytes, true);
368       }
369       catch (Throwable JavaDoc ex)
370       {
371          throw new ClassNotFoundException JavaDoc(name, ex);
372       }
373    }
374
375    /**
376     * Load jre classes from the parent classloader
377     *
378     * @param name the class name
379     * @return the class
380     * @throws ClassNotFoundException when there is no class
381     */

382    protected Class JavaDoc loadClassByDelegation(String JavaDoc name)
383       throws ClassNotFoundException JavaDoc
384    {
385       // FIXME: Only works for Sun for now
386
if (name.startsWith("java.") || name.startsWith("javax.")
387          || name.startsWith("sun.") || name.startsWith("com.sun.")
388          || name.startsWith("org.apache.xerces.") || name.startsWith("org.xml.sax.")
389          || name.startsWith("org.w3c.dom."))
390          return getParent().loadClass(name);
391
392       return null;
393    }
394
395    /**
396     * Install the classloader, get reflection objects and load
397     * classes using ourself.
398     */

399    protected synchronized void install()
400    {
401       try
402       {
403          // AspectManager
404
Class JavaDoc clazz = loadClassLocally("org.jboss.aop.AspectManager");
405          Class JavaDoc[] transformSig = {ClassLoader JavaDoc.class, String JavaDoc.class,
406                                  Class JavaDoc.class, ProtectionDomain JavaDoc.class, byte[].class};
407          transform = clazz.getMethod("transform", transformSig);
408          instance = clazz.getMethod("instance", new Class JavaDoc[0]);
409
410          // AspectXmlLoader
411
clazz = loadClassLocally("org.jboss.aop.AspectXmlLoader");
412          deployXML = clazz.getMethod("deployXML", new Class JavaDoc[]{URL JavaDoc.class});
413
414 /*
415          // loadClassLocally("org.jboss.aop.Advisable");
416          loadClassLocally("org.jboss.aop.Advised");
417          // loadClassLocally("org.jboss.aop.Advisor");
418          loadClassLocally("org.jboss.aop.AlreadyAdvisedException");
419          // loadClassLocally("org.jboss.aop.AOPClassPool");
420          // loadClassLocally("org.jboss.aop.AspectManager");
421          loadClassLocally("org.jboss.aop.AspectNotificationHandler");
422          // loadClassLocally("org.jboss.aop.AspectXmlLoader");
423          // loadClassLocally("org.jboss.aop.ClassAdvisor");
424          loadClassLocally("org.jboss.aop.ClassInstanceAdvisor");
425          // loadClassLocally("org.jboss.aop.ClassMetaData");
426          // loadClassLocally("org.jboss.aop.ClassMetaDataLoader");
427          loadClassLocally("org.jboss.aop.CLClassPath");
428          loadClassLocally("org.jboss.aop.ConstructorComparator");
429          loadClassLocally("org.jboss.aop.ConstructorConfig");
430          loadClassLocally("org.jboss.aop.ConstructorInvocation");
431          loadClassLocally("org.jboss.aop.ConstructorMetaData");
432          loadClassLocally("org.jboss.aop.CtConstructorComparator");
433          loadClassLocally("org.jboss.aop.CtFieldComparator");
434          loadClassLocally("org.jboss.aop.CtMethodComparator");
435          loadClassLocally("org.jboss.aop.Dispatcher");
436          loadClassLocally("org.jboss.aop.FieldComparator");
437          loadClassLocally("org.jboss.aop.FieldInvocation");
438          loadClassLocally("org.jboss.aop.FieldMetaData");
439          loadClassLocally("org.jboss.aop.GenericInterceptorFactory");
440          // loadClassLocally("org.jboss.aop.InstanceAdvised");
441          // loadClassLocally("org.jboss.aop.InstanceAdvisor");
442          loadClassLocally("org.jboss.aop.Instrumentor");
443          // loadClassLocally("org.jboss.aop.InterceptorFactory");
444          loadClassLocally("org.jboss.aop.InterceptorFilter");
445          // loadClassLocally("org.jboss.aop.Interceptor");
446          // loadClassLocally("org.jboss.aop.ClassPointcut");
447          // loadClassLocally("org.jboss.aop.InterceptorStack");
448          // loadClassLocally("org.jboss.aop.IntroductionPointcut");
449          loadClassLocally("org.jboss.aop.InvocationFilterInterceptor");
450          loadClassLocally("org.jboss.aop.Invocation");
451          loadClassLocally("org.jboss.aop.InvocationResponse");
452          loadClassLocally("org.jboss.aop.InvocationType");
453          loadClassLocally("org.jboss.aop.Loader");
454          loadClassLocally("org.jboss.aop.MarshalledValueInputStream");
455          loadClassLocally("org.jboss.aop.MarshalledValue");
456          loadClassLocally("org.jboss.aop.MarshalledValueOutputStream");
457          // loadClassLocally("org.jboss.aop.MetaDataResolver");
458          loadClassLocally("org.jboss.aop.MethodComparator");
459          loadClassLocally("org.jboss.aop.MethodConfig");
460          loadClassLocally("org.jboss.aop.MethodHashing");
461          loadClassLocally("org.jboss.aop.MethodInvocation");
462          loadClassLocally("org.jboss.aop.MethodMetaData");
463          loadClassLocally("org.jboss.aop.NotAdvisableException");
464          loadClassLocally("org.jboss.aop.NotAdvisedException");
465          loadClassLocally("org.jboss.aop.PayloadKey");
466          loadClassLocally("org.jboss.aop.SimpleClassMetaData");
467          loadClassLocally("org.jboss.aop.SimpleClassMetaDataLoader");
468          loadClassLocally("org.jboss.aop.SimpleMetaData");
469          loadClassLocally("org.jboss.aop.SingletonInterceptorFactory");
470          loadClassLocally("org.jboss.aop.StandaloneClassLoader");
471          loadClassLocally("org.jboss.aop.ThreadMetaData");
472          loadClassLocally("org.jboss.aop.proxy.ClassProxyFactory");
473          loadClassLocally("org.jboss.aop.proxy.ClassProxy");
474          loadClassLocally("org.jboss.aop.proxy.ClassProxyTemplate");
475          loadClassLocally("org.jboss.aop.proxy.DynamicProxyIH");
476          // loadClassLocally("org.jboss.aop.proxy.ProxyAdvisor");
477          loadClassLocally("org.jboss.util.loading.Translatable");
478          loadClassLocally("javassist.compiler.CompileError");
479          loadClassLocally("javassist.bytecode.BadBytecode");
480          loadClassLocally("javassist.bytecode.ClassFile");
481          loadClassLocally("javassist.bytecode.ConstPool");
482          */

483
484          state = INSTALLED;
485       }
486       catch (Throwable JavaDoc t)
487       {
488          t.printStackTrace();
489          throw new Error JavaDoc("Error initializing system classloader", t);
490       }
491    }
492
493    /**
494     * Initialize the aspect manager and load the static aspects
495     */

496    protected synchronized void initialize()
497    {
498       // Only one thread will initialize
499
if (state != INSTALLED)
500          return;
501       state = INITIALIZING;
502
503       // Set the context classloader to ourselves
504
Thread.currentThread().setContextClassLoader(this);
505
506       // Set up the aspect manager, once this is done we
507
// are ready to go
508
try
509       {
510          try
511          {
512             System.setProperty("jboss.aop.optimized", "false");
513             aspectManager = instance.invoke(null, new Object JavaDoc[0]);
514          }
515          catch (InvocationTargetException JavaDoc ite)
516          {
517             throw ite.getCause();
518          }
519          state = INITIALIZED;
520       }
521       catch (Throwable JavaDoc t)
522       {
523          t.printStackTrace();
524          throw new Error JavaDoc("Error installing aspect manager", t);
525       }
526
527       // Install the aop configurations
528
try
529       {
530          Enumeration JavaDoc enumeration = getParent().getResources("META-INF/jboss-aop.xml");
531          while (enumeration.hasMoreElements())
532          {
533             URL JavaDoc url = (URL JavaDoc) enumeration.nextElement();
534             deployXML.invoke(null, new Object JavaDoc[]{url});
535          }
536       }
537       catch (Throwable JavaDoc t)
538       {
539          t.printStackTrace();
540          throw new Error JavaDoc("Error deploying aop configrations", t);
541       }
542    }
543
544    /**
545     * ClassBytes.
546     */

547    private static class ClassBytes
548    {
549       public ProtectionDomain JavaDoc protectionDomain;
550       public byte[] bytes;
551    }
552 }
553
Popular Tags