001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.loading;
023:
024: import java.net.URL;
025: import java.security.AccessController;
026: import java.security.PrivilegedAction;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Set;
030:
031: import javax.management.AttributeNotFoundException;
032: import javax.management.InstanceNotFoundException;
033: import javax.management.MBeanException;
034: import javax.management.MBeanServer;
035: import javax.management.ObjectName;
036: import javax.management.ReflectionException;
037:
038: import org.jboss.mx.loading.LoadMgr3.PkgClassLoader;
039: import org.jboss.mx.util.ObjectNameFactory;
040:
041: /** A simple extension of UnifiedLoaderRepository3 that adds the notion of a
042: * parent UnifiedLoaderRepository. Classes and resources are loaded from child
043: * first and then the parent depending on the java2ParentDelegation flag.
044: *
045: * @author Scott.Stark@jboss.org
046: * @version $Revision: 57200 $
047: */
048: public class HeirarchicalLoaderRepository3 extends
049: UnifiedLoaderRepository3 {
050: private static ObjectName DEFAULT_LOADER_OBJECT_NAME = ObjectNameFactory
051: .create(DEFAULT_LOADER_NAME);
052:
053: /** A ClassLoader override that prevents a child class loader from looking
054: * beyond its URLs for classes.
055: */
056: static class NoParentClassLoader extends ClassLoader {
057: NoParentClassLoader() {
058: super (HeirarchicalLoaderRepository3.class.getClassLoader());
059: }
060:
061: /** Override to always return null to force the UCL to only load from
062: * its URLs.
063: * @param name
064: * @return
065: */
066: public URL getResource(String name) {
067: return null;
068: }
069:
070: /** Override to always throw a CNFE to force the UCL to only load from
071: * its URLs.
072: * @param name
073: * @param resolve
074: * @return nothing
075: * @throws ClassNotFoundException always
076: */
077: protected synchronized Class loadClass(String name,
078: boolean resolve) throws ClassNotFoundException {
079: throw new ClassNotFoundException(
080: "NoParentClassLoader has no classes");
081: }
082:
083: /** Override to always throw a CNFE to force the UCL to only load from
084: * its URLs.
085: * @param name
086: * @return
087: * @throws ClassNotFoundException
088: */
089: protected Class findClass(String name)
090: throws ClassNotFoundException {
091: throw new ClassNotFoundException(
092: "NoParentClassLoader has no classes");
093: }
094: }
095:
096: static class CacheClassLoader extends UnifiedClassLoader3 {
097: Class cacheClass;
098:
099: CacheClassLoader(Class cacheClass, LoaderRepository rep) {
100: super (null, null, new NoParentClassLoader(), rep);
101: this .cacheClass = cacheClass;
102: }
103:
104: protected Class findClass(String name)
105: throws ClassNotFoundException {
106: Class c = cacheClass;
107: if (name.equals(cacheClass.getName()) == false)
108: c = null;
109: return c;
110: }
111: }
112:
113: /** The repository to which we delegate if requested classes or resources
114: are not available from this repository.
115: */
116: private UnifiedLoaderRepository3 parentRepository;
117: /** A flag indicating if the standard parent delegation loading where the
118: parent repository is used before this repository.
119: */
120: private boolean java2ParentDelegation;
121:
122: /** The package classloader */
123: private PkgClassLoader packageClassLoader;
124:
125: /** Create a HeirarchicalLoaderRepository3 with an explicit parent.
126: *
127: * @param parent
128: * @throws AttributeNotFoundException
129: * @throws InstanceNotFoundException
130: * @throws MBeanException
131: * @throws ReflectionException
132: */
133: public HeirarchicalLoaderRepository3(UnifiedLoaderRepository3 parent)
134: throws AttributeNotFoundException,
135: InstanceNotFoundException, MBeanException,
136: ReflectionException {
137: this .parentRepository = parent;
138: init();
139: }
140:
141: /** Create a HeirarchicalLoaderRepository3 with a parent obtained by querying
142: * the server for the ServerConstants.DEFAULT_LOADER_NAME mbean.
143: *
144: * @param server
145: * @throws AttributeNotFoundException
146: * @throws InstanceNotFoundException
147: * @throws MBeanException
148: * @throws ReflectionException
149: */
150: public HeirarchicalLoaderRepository3(MBeanServer server)
151: throws AttributeNotFoundException,
152: InstanceNotFoundException, MBeanException,
153: ReflectionException {
154: this (server, DEFAULT_LOADER_OBJECT_NAME);
155: }
156:
157: /** Create a HeirarchicalLoaderRepository3 with a parent obtained by querying
158: * the server for the parentName mbean.
159: *
160: * @param server
161: * @param parentName
162: * @throws AttributeNotFoundException
163: * @throws InstanceNotFoundException
164: * @throws MBeanException
165: * @throws ReflectionException
166: */
167: public HeirarchicalLoaderRepository3(MBeanServer server,
168: ObjectName parentName) throws AttributeNotFoundException,
169: InstanceNotFoundException, MBeanException,
170: ReflectionException {
171: this .parentRepository = (UnifiedLoaderRepository3) server
172: .getAttribute(parentName, "Instance");
173: init();
174: }
175:
176: /**
177: * Initialisation
178: */
179: private void init() {
180: // Include a class loader with a parent to the system class loader
181: ClassLoader loader = RepositoryClassLoader.class
182: .getClassLoader();
183: RepositoryClassLoader ucl = null;
184: if (loader instanceof RepositoryClassLoader)
185: ucl = (RepositoryClassLoader) loader;
186: else
187: ucl = new UnifiedClassLoader3(null, null,
188: HeirarchicalLoaderRepository3.this );
189: packageClassLoader = new PkgClassLoader(ucl, 3);
190: }
191:
192: // Public --------------------------------------------------------
193:
194: public RepositoryClassLoader newClassLoader(final URL url,
195: boolean addToRepository) throws Exception {
196: UnifiedClassLoader3 ucl = null;
197: if (java2ParentDelegation == false)
198: ucl = new UnifiedClassLoader3(url, null,
199: new NoParentClassLoader(), this );
200: else
201: ucl = new UnifiedClassLoader3(url, null, this );
202:
203: if (addToRepository) {
204: this .addClassLoader(ucl);
205: }
206: return ucl;
207: }
208:
209: public RepositoryClassLoader newClassLoader(final URL url,
210: final URL origURL, boolean addToRepository)
211: throws Exception {
212: UnifiedClassLoader3 ucl = null;
213: if (java2ParentDelegation == false)
214: ucl = new UnifiedClassLoader3(url, origURL,
215: new NoParentClassLoader(), this );
216: else
217: ucl = new UnifiedClassLoader3(url, origURL, this );
218:
219: if (addToRepository) {
220: this .addClassLoader(ucl);
221: }
222: return ucl;
223: }
224:
225: /** Get the use parent first flag. This indicates whether the parent
226: * repository is consulted first for resource and class loading or if the
227: * HeirchicalLoaderRepository is consulted first.
228: *
229: * @return true if the parent repository is consulted first, false if the
230: * HeirchicalLoaderRepository is consulted first.
231: */
232: public boolean getUseParentFirst() {
233: return java2ParentDelegation;
234: }
235:
236: /** Set the use parent first flag. This indicates whether the parent
237: * repository is consulted first for resource and class loading or if the
238: * HeirchicalLoaderRepository is consulted first.
239: *
240: * @param flag true if the parent repository is consulted first, false if the
241: * HeirchicalLoaderRepository is consulted first.
242: */
243: public void setUseParentFirst(boolean flag) {
244: java2ParentDelegation = flag;
245: }
246:
247: /** Load a class using the repository class loaders.
248: *
249: * @param name The name of the class
250: * @param resolve an obsolete unused parameter from ClassLoader.loadClass
251: * @param scl The asking class loader
252: * @return The loaded class
253: * @throws ClassNotFoundException If the class could not be found.
254: */
255: public Class loadClass(String name, boolean resolve, ClassLoader scl)
256: throws ClassNotFoundException {
257: Class foundClass = null;
258:
259: if (java2ParentDelegation == true) {
260: try {
261: // Try the parent repository first
262: foundClass = parentRepository.loadClass(name, resolve,
263: scl);
264: } catch (ClassNotFoundException e) {
265: // Next try our repository
266: if (foundClass == null)
267: foundClass = super .loadClass(name, resolve, scl);
268: }
269: } else {
270: try {
271: // Try this repository first
272: foundClass = super .loadClass(name, resolve, scl);
273: } catch (ClassNotFoundException e) {
274: // Next try our parent repository
275: if (foundClass == null)
276: foundClass = parentRepository.loadClass(name,
277: resolve, scl);
278: }
279: }
280:
281: if (foundClass != null)
282: return foundClass;
283:
284: /* If we reach here, all of the classloaders currently in the VM don't
285: know about the class
286: */
287: throw new ClassNotFoundException(name);
288: }
289:
290: /** Override getCachedClass to return the parent repository cached class
291: * if java2ParentDelegation=true, followed by this repository's cached
292: * value. Else, if java2ParentDelegation=false, only check this repository's
293: * cache to attempt to load the class from the child repository before
294: * going to the parent cache.
295: *
296: * @param classname
297: * @return the cached class if found, null otherwise
298: */
299: public Class getCachedClass(String classname) {
300: Class clazz = null;
301: if (java2ParentDelegation == true) {
302: // Try the parent repository
303: clazz = parentRepository.getCachedClass(classname);
304: // Next try our parent repository
305: if (clazz == null)
306: clazz = super .getCachedClass(classname);
307: } else {
308: // Try this repository
309: clazz = super .getCachedClass(classname);
310: }
311: return clazz;
312: }
313:
314: /** Find a resource from this repository. This first looks to this
315: * repository and then the parent repository.
316: * @param name The name of the resource
317: * @param scl The asking class loader
318: * @return An URL for reading the resource, or <code>null</code> if the
319: * resource could not be found.
320: */
321: public URL getResource(String name, ClassLoader scl) {
322: URL resource = null;
323:
324: if (java2ParentDelegation == true) {
325: /* Try our parent repository. This cannot use the getResource method
326: because we do not want the parent repository to load the resource via
327: our scoped class loader
328: */
329: resource = getParentResource(name, scl);
330: // Next try this repository
331: if (resource == null)
332: resource = super .getResource(name, scl);
333: } else {
334: // Try this repository
335: resource = super .getResource(name, scl);
336: // Next try our parent repository
337: if (resource == null) {
338: /* Try our parent repository. This cannot use the getResource method
339: because we do not want the parent repository to load the resource via
340: our scoped class loader
341: */
342: resource = getParentResource(name, scl);
343: }
344: }
345:
346: return resource;
347: }
348:
349: /** Find all resource URLs for the given name. This is entails an
350: * exhuastive search of this and the parent repository and is an expensive
351: * operation.
352: *
353: * @param name the resource name
354: * @param cl the requesting class loader
355: * @param urls a list into which the located resource URLs will be placed
356: */
357: public void getResources(String name, ClassLoader cl, List urls) {
358: if (java2ParentDelegation == true) {
359: // Get the parent repository resources
360: parentRepository.getResources(name, cl, urls);
361: // Next get this repositories resources
362: super .getResources(name, cl, urls);
363: } else {
364: // Get this repositories resources
365: super .getResources(name, cl, urls);
366: // Next get the parent repository resources
367: parentRepository.getResources(name, cl, urls);
368: }
369: }
370:
371: /** Obtain a listing of the URLs for all UnifiedClassLoaders associated with
372: *the repository
373: */
374: public URL[] getURLs() {
375: URL[] ourURLs = super .getURLs();
376: URL[] parentURLs = parentRepository.getURLs();
377: int size = ourURLs.length + parentURLs.length;
378: URL[] urls = new URL[size];
379: System.arraycopy(ourURLs, 0, urls, 0, ourURLs.length);
380: System.arraycopy(parentURLs, 0, urls, ourURLs.length,
381: parentURLs.length);
382: return urls;
383: }
384:
385: /** Called by LoadMgr to locate a previously loaded class. This looks
386: * first to this repository and then the parent repository.
387: *@return the cached class if found, null otherwise
388: */
389: public Class loadClassFromCache(String name) {
390: Class foundClass = null;
391:
392: if (java2ParentDelegation == true) {
393: // Try this repository
394: foundClass = parentRepository.loadClassFromCache(name);
395: // Next try our parent repository
396: if (foundClass == null)
397: foundClass = super .loadClassFromCache(name);
398: } else {
399: // Try this repository
400: foundClass = super .loadClassFromCache(name);
401: /* We do not try the parent repository cache as this does not allow
402: the child repository to override classes in the parent
403: */
404: }
405: return foundClass;
406: }
407:
408: /** Called by LoadMgr to obtain all class loaders. This returns a set of
409: * PkgClassLoader with the HeirarchicalLoaderRepository3 ordered ahead of
410: * the parent repository pkg class loaders
411: *@return Set<PkgClassLoader>
412: */
413: public Set getPackageClassLoaders(String name) {
414: Set pkgSet = super .getPackageClassLoaders(name);
415: Set parentPkgSet = parentRepository
416: .getPackageClassLoaders(name);
417: GetClassLoadersAction action = new GetClassLoadersAction(name,
418: pkgSet, parentPkgSet);
419: Set theSet = (Set) AccessController.doPrivileged(action);
420: return theSet;
421:
422: }
423:
424: public int compare(LoaderRepository lr) {
425: if (lr == this )
426: return 0;
427: return reverseCompare(lr);
428: }
429:
430: protected int reverseCompare(LoaderRepository lr) {
431: // If it is not our parent we don't care
432: if (lr != parentRepository)
433: return 0;
434:
435: // The order depends upon the delegation model
436: if (java2ParentDelegation)
437: return +1;
438: else
439: return -1;
440: }
441:
442: /** A subset of the functionality found in getResource(String, ClassLoader),
443: * but this version queries the parentRepository and does not use the scl
444: * to avoid leaking class loaders across scoped.
445: *
446: * @param name - the resource name
447: * @param scl - the requesting class loader
448: * @return the resource URL if found, null otherwise
449: */
450: private URL getParentResource(String name, ClassLoader scl) {
451: // Not found in classloader, ask the global cache
452: URL resource = parentRepository
453: .getResourceFromGlobalCache(name);
454:
455: // The cache has it, we are done
456: if (resource != null)
457: return resource;
458:
459: // Not visible in global cache, iterate on all classloaders
460: resource = parentRepository
461: .getResourceFromRepository(name, scl);
462:
463: return resource;
464: }
465:
466: private class GetClassLoadersAction implements PrivilegedAction {
467: private String name;
468: Set pkgSet;
469: Set parentPkgSet;
470:
471: GetClassLoadersAction(String name, Set pkgSet, Set parentPkgSet) {
472: this .name = name;
473: this .pkgSet = pkgSet;
474: this .parentPkgSet = parentPkgSet;
475: }
476:
477: public Object run() {
478: // Build a set of PkgClassLoader
479: Set theSet = ClassLoaderUtils.newPackageSet();
480: if (pkgSet != null) {
481: Iterator iter = pkgSet.iterator();
482: while (iter.hasNext()) {
483: RepositoryClassLoader ucl = (RepositoryClassLoader) iter
484: .next();
485: PkgClassLoader pkgUcl = new PkgClassLoader(ucl, 0);
486: theSet.add(pkgUcl);
487: }
488: }
489:
490: if (java2ParentDelegation == false) {
491: Class cacheClass = parentRepository
492: .loadClassFromCache(name);
493: if (cacheClass != null) {
494: RepositoryClassLoader ucl = new CacheClassLoader(
495: cacheClass,
496: HeirarchicalLoaderRepository3.this );
497: PkgClassLoader pkgUcl = new PkgClassLoader(ucl, 1);
498: theSet.add(pkgUcl);
499: }
500: }
501:
502: if (parentPkgSet != null) {
503: Iterator iter = parentPkgSet.iterator();
504: while (iter.hasNext()) {
505: RepositoryClassLoader ucl = (RepositoryClassLoader) iter
506: .next();
507: PkgClassLoader pkgUcl = new PkgClassLoader(ucl, 2);
508: theSet.add(pkgUcl);
509: }
510: }
511:
512: if (java2ParentDelegation == false) {
513: theSet.add(packageClassLoader);
514: }
515:
516: return theSet;
517: }
518: }
519:
520: }
|