View Javadoc

1   /*
2   *
3   * Distributable under LGPL license.
4   * See terms of license at gnu.org.
5   */
6   package org.backsource.utils.lang;
7   
8   import java.net.URL;
9   import java.net.URLClassLoader;
10  import java.util.Enumeration;
11  import java.util.Vector;
12  /***
13   * <p>A URLClassLoader wrapper that loads classes and resouces first from the
14   leafs of the classloader tree, and not from the root as is the case with
15   the sun classloader.
16   
17   <p>It is important to understand that all classes are loaded into the classloader wrapper and the new wrapper it created around its parent.
18   
19   <p>It is also important to know that if a URLClassLoader has a parent that is not a URLClassLoader, the normal classloading and resource finding mechanisms will be used.
20  
21   <p>May be really handy if you want to override a resource (or class) in 
22   a component loaded in leaf classloader, as is often the case in JBoss and Tomcat for example.
23   *
24   *
25   * @author Peter Antman
26   * @version $Revision: 1.1.1.1 $
27   */
28  
29  public class ReverseClassLoader  extends URLClassLoader{
30      ClassLoader  wrappedClassLoader= null;
31      
32      /***
33       * <p>Wrap a URLClassLoader.
34       *
35       * <p>The all URLs the classloader wikk be search first, and lodaded
36       * in this classloader, and not in the wrapped one.
37       */
38      public ReverseClassLoader(URLClassLoader wrappedClassLoader) {
39  	super(wrappedClassLoader.getURLs(), wrappedClassLoader.getParent());
40  	this.wrappedClassLoader = wrappedClassLoader;
41      }
42  
43      public ClassLoader getWrappedClassLoader() {
44  	return wrappedClassLoader;
45      }
46  
47      /***
48       * Get resource through a bottom up search. I.e try find the resource
49       * in the wrapped loader before proceding to the parent.
50       */
51      public URL getResource(String name) {
52  	return getResource(this,name);
53      }
54  
55      /***
56       * Try find the resource in the classloader, if not proced to parent.
57       * If parent is null, call getResource on the cl.
58       */
59      private URL getResource(ReverseClassLoader cl, String name) {
60  	URL url = cl.findResource(name);
61  	if (url != null)
62  	    return url;
63  	else {
64  	    // Go to parent, wrap it in reverse to get protected methods to work
65  	    ClassLoader parent = cl.getParent();
66  
67  	    if (parent !=null) {
68  		if(parent instanceof URLClassLoader) {
69  		    // Wrap it and continue
70  		    ReverseClassLoader wrap = new ReverseClassLoader((URLClassLoader)parent);
71  		    return getResource(wrap,name);
72  		}else {
73  		    // Can't wrap ordinary cl, let it do its jobb.
74  		    return parent.getResource(name);
75  		}
76  	    } else {
77  		// We are at the top, call get on the cl and let it call,
78  		// System CL if it wants
79  		return cl.getWrappedClassLoader().getResource(name);
80  	    }
81  	}
82      }
83  
84      public URL findResource(String name) {
85  	return super.findResource(name);
86      }
87      /*
88       * Try find the resources and list them in reverse order compared to
89       whats normal. This is a heavy waigth operation.
90       */
91      
92      //public Enumeration getResources(String name) throws IOException {
93  	// this bugger is final, lets see if this works.
94      //	return reverseEnumeration(super.getResources(name));
95      //}
96      /***
97       * Try find the resurce in the classloader, if not proced to parent.
98       * If parent is null, call getResource on the cl.
99       *
100      */
101     private Enumeration reverseEnumeration(Enumeration enum) {
102 	Vector v = new Vector();
103 	while(enum.hasMoreElements()) {
104 	    v.add(enum.nextElement());
105 	}
106 	Vector rev = new Vector();
107 	for(int i = v.size(); i > 0; i--) {
108 	    rev.add(v.elementAt(i-1));
109 	}
110 	return rev.elements();
111     }
112 
113     /***
114      * <p>Load a class by looking in this classloader and searching upwards as
115      * long as the parent classloaders are URLClassloader.
116      *
117      * <p>It is important to notice that the classes will be loaded in this
118      * classloader or in any of its contsucted parents (also ReverseClassLoader) and not in the wrapped classloader.
119      */
120     public Class loadClass(String name) throws ClassNotFoundException {
121 	return loadClass(this,name);
122     }
123 
124     /* Protected so cant use it on final loader
125     protected synchronized Class loadClass(String name, boolean resolve)
126         throws ClassNotFoundException
127     {
128 	return loadClass(this,name,resolve);
129     }
130     */
131     protected Class loadClass(ReverseClassLoader cl, String name)
132         throws ClassNotFoundException
133     {
134         // First, check if the class has already been loaded
135         Class c = cl.findLoadedClass(name);
136         if (c == null) {
137 	    // try find
138 	    try {
139 		c = cl.findClass(name);
140 	    }catch(ClassNotFoundException e) {
141 		// Class not found procede to parent
142 		ClassLoader parent = cl.getParent();
143 		if (parent !=null) {
144 		    if (parent instanceof URLClassLoader) {
145 			ReverseClassLoader wrap = new ReverseClassLoader((URLClassLoader)parent);
146 			return loadClass(wrap,name);
147 		    }else {
148 			return parent.loadClass(name);
149 		    }
150 		} else {
151 		    // We are at the top, call get on the cl and let it call,
152 		    // System CL if it wants
153 		    return cl.getWrappedClassLoader().loadClass(name);
154 		    //return cl.loadClassParent(name,resolve);
155 		}
156 	    }
157 	    
158         }
159 	return c;
160     }
161 
162 
163     
164 
165 
166 } // ReverseClassLoader
167 
168 
169 
170 
171 
172 
173 
174 
175