KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > mbeanserver > ClassLoaderRepositorySupport


1 /*
2  * @(#)ClassLoaderRepositorySupport.java 1.25 05/05/27
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.jmx.mbeanserver;
9
10 // Java import
11
import java.util.ArrayList JavaDoc;
12 import java.util.Arrays JavaDoc;
13 import java.util.Hashtable JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.List JavaDoc;
16 import java.util.Vector JavaDoc;
17
18 // JMX import
19
import javax.management.ObjectName JavaDoc;
20 import javax.management.loading.ClassLoaderRepository JavaDoc;
21 import javax.management.loading.PrivateClassLoader JavaDoc;
22
23 import com.sun.jmx.trace.Trace;
24
25 /**
26  * This class keeps the list of Class Loaders registered in the MBean Server.
27  * It provides the necessary methods to load classes using the
28  * registered Class Loaders.
29  *
30  * @since 1.5
31  * @since.unbundled JMX RI 1.2
32  */

33 final class ClassLoaderRepositorySupport
34     implements ModifiableClassLoaderRepository {
35
36     /* We associate an optional ObjectName with each entry so that
37        we can remove the correct entry when unregistering an MBean
38        that is a ClassLoader. The same object could be registered
39        under two different names (even though this is not recommended)
40        so if we did not do this we could disturb the defined
41        semantics for the order of ClassLoaders in the repository. */

42     private static class LoaderEntry {
43     ObjectName JavaDoc name; // can be null
44
ClassLoader JavaDoc loader;
45
46     LoaderEntry(ObjectName JavaDoc name, ClassLoader JavaDoc loader) {
47         this.name = name;
48         this.loader = loader;
49     }
50     }
51
52     private static final LoaderEntry[] EMPTY_LOADER_ARRAY = new LoaderEntry[0];
53
54     /**
55      * List of class loaders
56      * Only read-only actions should be performed on this object.
57      *
58      * We do O(n) operations on this array, e.g. when removing
59      * a ClassLoader. The assumption is that the number of elements
60      * is small, probably less than ten, and that the vast majority
61      * of operations are searches (loadClass) which are by definition
62      * linear.
63      */

64     private LoaderEntry[] loaders = EMPTY_LOADER_ARRAY;
65
66     /**
67      * Same behaviour as add(Object o) in {@link java.util.List}.
68      * Replace the loader list with a new one in which the new
69      * loader has been added.
70      **/

71     private synchronized boolean add(ObjectName JavaDoc name, ClassLoader JavaDoc cl) {
72     List JavaDoc l = new ArrayList JavaDoc(Arrays.asList(loaders));
73     l.add(new LoaderEntry(name, cl));
74     loaders = (LoaderEntry[]) l.toArray(EMPTY_LOADER_ARRAY);
75     return true;
76     }
77
78     /**
79      * Same behaviour as remove(Object o) in {@link java.util.List}.
80      * Replace the loader list with a new one in which the old loader
81      * has been removed.
82      *
83      * The ObjectName may be null, in which case the entry to
84      * be removed must also have a null ObjectName and the ClassLoader
85      * values must match. If the ObjectName is not null, then
86      * the first entry with a matching ObjectName is removed,
87      * regardless of whether ClassLoader values match. (In fact,
88      * the ClassLoader parameter will usually be null in this case.)
89      **/

90     private synchronized boolean remove(ObjectName JavaDoc name, ClassLoader JavaDoc cl) {
91     final int size = loaders.length;
92     for (int i = 0; i < size; i++) {
93         LoaderEntry entry = loaders[i];
94         boolean match =
95         (name == null) ?
96         cl == entry.loader :
97         name.equals(entry.name);
98         if (match) {
99         LoaderEntry[] newloaders = new LoaderEntry[size - 1];
100         System.arraycopy(loaders, 0, newloaders, 0, i);
101         System.arraycopy(loaders, i + 1, newloaders, i,
102                  size - 1 - i);
103         loaders = newloaders;
104         return true;
105         }
106     }
107     return false;
108     }
109
110
111     /**
112      * List of valid search
113      */

114     private final Hashtable JavaDoc search= new Hashtable JavaDoc(10);
115
116     /**
117      * List of named class loaders.
118      */

119     private final Hashtable JavaDoc loadersWithNames = new Hashtable JavaDoc(10);
120
121     
122     private final static String JavaDoc dbgTag = "ClassLoaderRepositorySupport";
123
124
125     // from javax.management.loading.DefaultLoaderRepository
126
public final Class JavaDoc loadClass(String JavaDoc className)
127     throws ClassNotFoundException JavaDoc {
128     return loadClass(loaders, className, null, null);
129     }
130
131     
132     // from javax.management.loading.DefaultLoaderRepository
133
public final Class JavaDoc loadClassWithout(ClassLoader JavaDoc without, String JavaDoc className)
134         throws ClassNotFoundException JavaDoc {
135     if (isTraceOn()) {
136         trace("loadClassWithout", className + "\twithout " + without);
137     }
138
139     // without is null => just behave as loadClass
140
//
141
if (without == null)
142         return loadClass(loaders, className, null, null);
143     
144     // We must try to load the class without the given loader.
145
//
146
startValidSearch(without, className);
147     try {
148         return loadClass(loaders, className, without, null);
149     } finally {
150         stopValidSearch(without, className);
151     }
152     }
153
154
155     public final Class JavaDoc loadClassBefore(ClassLoader JavaDoc stop, String JavaDoc className)
156         throws ClassNotFoundException JavaDoc {
157     if (isTraceOn())
158         trace("loadClassBefore", className + "\tbefore " + stop);
159
160     if (stop == null)
161         return loadClass(loaders, className, null, null);
162
163     startValidSearch(stop, className);
164     try {
165         return loadClass(loaders, className, null, stop);
166     } finally {
167         stopValidSearch(stop, className);
168     }
169     }
170
171
172     private Class JavaDoc loadClass(final LoaderEntry list[],
173                 final String JavaDoc className,
174                 final ClassLoader JavaDoc without,
175                 final ClassLoader JavaDoc stop)
176         throws ClassNotFoundException JavaDoc {
177     final int size = list.length;
178         for(int i=0; i<size; i++) {
179         try {
180         final ClassLoader JavaDoc cl = list[i].loader;
181         if (cl == null) // bootstrap class loader
182
return Class.forName(className, false, null);
183         if (cl == without)
184             continue;
185         if (cl == stop)
186             break;
187         if (isTraceOn()) {
188             trace("loadClass", "trying loader = " + cl);
189         }
190         /* We used to have a special case for "instanceof
191            MLet" here, where we invoked the method
192            loadClass(className, null) to prevent infinite
193            recursion. But the rule whereby the MLet only
194            consults loaders that precede it in the CLR (via
195            loadClassBefore) means that the recursion can't
196            happen, and the test here caused some legitimate
197            classloading to fail. For example, if you have
198            dependencies C->D->E with loaders {E D C} in the
199            CLR in that order, you would expect to be able to
200            load C. The problem is that while resolving D, CLR
201            delegation is disabled, so it can't find E. */

202         return Class.forName(className, false, cl);
203             } catch (ClassNotFoundException JavaDoc e) {
204         // OK: continue with next class
205
}
206         }
207
208         throw new ClassNotFoundException JavaDoc(className);
209     }
210
211     private synchronized void startValidSearch(ClassLoader JavaDoc aloader,
212                            String JavaDoc className)
213         throws ClassNotFoundException JavaDoc {
214         // Check if we have such a current search
215
//
216
Vector JavaDoc excluded= (Vector JavaDoc) search.get(className);
217         if ((excluded!= null) && (excluded.contains(aloader))) {
218         if (isTraceOn()) {
219         trace("startValidSearch", "already requested loader=" +
220               aloader + " class= " + className);
221         }
222             throw new ClassNotFoundException JavaDoc(className);
223         }
224       
225         // Add an entry
226
//
227
if (excluded == null) {
228             excluded= new Vector JavaDoc(1);
229             search.put(className, excluded);
230         }
231         excluded.addElement(aloader);
232     if (isTraceOn()) {
233         trace("startValidSearch", "loader=" + aloader + " class= " +
234           className);
235     }
236     }
237
238     private synchronized void stopValidSearch(ClassLoader JavaDoc aloader,
239                           String JavaDoc className) {
240     
241         // Retrieve the search.
242
//
243
Vector JavaDoc excluded= (Vector JavaDoc) search.get(className);
244         if (excluded!= null) {
245             excluded.removeElement(aloader);
246         if (isTraceOn()) {
247         trace("stopValidSearch", "loader=" + aloader +
248               " class= " + className);
249         }
250     }
251     }
252   
253     public final void addClassLoader(ClassLoader JavaDoc loader) {
254     add(null, loader);
255     }
256
257     public final void removeClassLoader(ClassLoader JavaDoc loader) {
258     remove(null, loader);
259     }
260
261     public final synchronized void addClassLoader(ObjectName JavaDoc name,
262                           ClassLoader JavaDoc loader) {
263     loadersWithNames.put(name, loader);
264     if (!(loader instanceof PrivateClassLoader JavaDoc))
265         add(name, loader);
266     }
267
268     public final synchronized void removeClassLoader(ObjectName JavaDoc name) {
269     ClassLoader JavaDoc loader = (ClassLoader JavaDoc) loadersWithNames.remove(name);
270     if (!(loader instanceof PrivateClassLoader JavaDoc))
271         remove(name, loader);
272     }
273
274     public final ClassLoader JavaDoc getClassLoader(ObjectName JavaDoc name) {
275     return (ClassLoader JavaDoc)loadersWithNames.get(name);
276     }
277
278     // TRACES & DEBUG
279
//---------------
280

281     private static boolean isTraceOn() {
282         return Trace.isSelected(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER);
283     }
284
285     private static void trace(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
286         Trace.send(Trace.LEVEL_TRACE, Trace.INFO_MBEANSERVER,clz,func,info);
287     }
288
289     private static void trace(String JavaDoc func, String JavaDoc info) {
290         trace(dbgTag, func, info);
291     }
292
293     private static boolean isDebugOn() {
294         return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER);
295     }
296
297     private static void debug(String JavaDoc clz, String JavaDoc func, String JavaDoc info) {
298         Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_MBEANSERVER,clz,func,info);
299     }
300
301     private static void debug(String JavaDoc func, String JavaDoc info) {
302         debug(dbgTag, func, info);
303     }
304  
305 }
306
Popular Tags