Source Code Cross Referenced for UnifiedLoaderRepository3.java in  » EJB-Server-JBoss-4.2.1 » jmx » org » jboss » mx » loading » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » EJB Server JBoss 4.2.1 » jmx » org.jboss.mx.loading 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.MalformedURLException;
025:        import java.net.URL;
026:        import java.net.URLClassLoader;
027:        import java.util.ArrayList;
028:        import java.util.HashMap;
029:        import java.util.HashSet;
030:        import java.util.Iterator;
031:        import java.util.List;
032:        import java.util.Enumeration;
033:        import java.util.Map;
034:        import java.util.Set;
035:        import java.io.IOException;
036:
037:        import javax.management.ListenerNotFoundException;
038:        import javax.management.MBeanNotificationInfo;
039:        import javax.management.Notification;
040:        import javax.management.NotificationEmitter;
041:        import javax.management.NotificationFilter;
042:        import javax.management.NotificationListener;
043:        import javax.management.MBeanRegistration;
044:        import javax.management.ObjectName;
045:        import javax.management.MBeanServer;
046:        import javax.management.loading.MLet;
047:
048:        import org.jboss.logging.Logger;
049:        import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
050:
051:        import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
052:        import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet;
053:
054:        /** A repository of class loaders that form a flat namespace of classes
055:         * and resources. This version uses UnifiedClassLoader3 instances. Class
056:         * and resource loading is synchronized by the acquiring the monitor to the
057:         * associated repository structure monitor. See the variable javadoc comments
058:         * for what monitor is used to access a given structure.
059:         *
060:         * @author  <a href="mailto:scott.stark@jboss.org">Scott Stark</a>.
061:         * @author  <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
062:         * @version $Revision: 57200 $
063:         * just a hint... xdoclet not really used
064:         * @jmx.name="JMImplementation:service=UnifiedLoaderRepository,name=Default"
065:         */
066:        public class UnifiedLoaderRepository3 extends LoaderRepository
067:                implements  MBeanRegistration, NotificationEmitter,
068:                UnifiedLoaderRepository3MBean {
069:            // Static --------------------------------------------------------
070:            private static final Logger log = Logger
071:                    .getLogger(UnifiedLoaderRepository3.class);
072:            /** Used to provide a relative ordering of UCLs based on the order in
073:             * which they are added to the repository */
074:            private static int addedCount;
075:
076:            // Attributes ----------------------------------------------------
077:
078:            /** HashSet<UCL> of classloaders in the repository.
079:             * Access synchronized via this.classLoaders monitor.
080:             */
081:            private CopyOnWriteArraySet classLoaders = new CopyOnWriteArraySet();
082:            /** HashSet<UCL> of class loaders in the repository that have a dynamic
083:             * URL associated with them. Such a class loader is added to every package
084:             * class loader set in #getPackageClassLoaders(String).
085:             */
086:            private HashSet dynamicClassLoaders = new HashSet();
087:            /** A HashMap<ClassLoader, UCL> of foreign (non-UCL) classloaders that
088:             * have been added to the repository as the key and the value the UCL
089:             * actually used by the ULR.
090:             * Access synchronized via this.classLoaders monitor.
091:             */
092:            private HashMap nonUCLClassLoader = new HashMap();
093:
094:            /** A HashSet<URL> used to check for duplicate URLs. Previously this was handled
095:             by the UCL.equals, but this caused problems with Class.forName(String,
096:             boolean, ClassLoader) caching.
097:             Access synchronized via this.classLoaders monitor.
098:             */
099:            private HashSet classLoaderURLs = new HashSet();
100:
101:            /** The loaded classes cache, HashMap<String, Class>.
102:             * Access synchronized via this.classes monitor.
103:             */
104:            private ConcurrentReaderHashMap classes = new ConcurrentReaderHashMap();
105:
106:            /** HashMap<UCL, HashSet<String>> class loaders to the set of class names
107:             * loaded via the UCL.
108:             * Access synchronized via this.classes monitor.
109:             */
110:            private HashMap loaderToClassesMap = new HashMap();
111:
112:            /** HashMap<UCL, HashMap<String, URL>> class loaders to the set of
113:             * resource names they looked up.
114:             * Access synchronized via this.loaderToResourcesMap monitor.
115:             */
116:            private HashMap loaderToResourcesMap = new HashMap();
117:
118:            /** HashMap<String, ResourceInfo(URL, UCL)> of global resources not unique
119:             * to a UCL
120:             * Access synchronized via this.loaderToResourcesMap monitor.
121:             */
122:            private HashMap globalResources = new HashMap();
123:
124:            /** A HashMap<String, Set<UCL>> of package names to the set of
125:             * ClassLoaders which have classes in the package.
126:             * Access synchronized via this.packagesMap monitor.
127:             */
128:            private ConcurrentReaderHashMap packagesMap = new ConcurrentReaderHashMap();
129:
130:            /** A HashMap<UCL, String[]> of class loaders to the array of pckages names
131:             * they serve
132:             * Access synchronized via this.packagesMap monitor.
133:             */
134:            private HashMap loaderToPackagesMap = new HashMap();
135:
136:            /**
137:             * The sequenceNumber used to number notifications.
138:             */
139:            private long sequenceNumber = 0;
140:
141:            /**
142:             * We delegate our notification sending to a support object.
143:             */
144:            private final JBossNotificationBroadcasterSupport broadcaster = new JBossNotificationBroadcasterSupport();
145:
146:            /**
147:             * The NotificationInfo we emit.
148:             */
149:            private MBeanNotificationInfo[] info;
150:
151:            // Public --------------------------------------------------------
152:
153:            public RepositoryClassLoader newClassLoader(final URL url,
154:                    boolean addToRepository) throws Exception {
155:                UnifiedClassLoader3 ucl = new UnifiedClassLoader3(url, null,
156:                        this );
157:                if (addToRepository)
158:                    this .registerClassLoader(ucl);
159:                return ucl;
160:            }
161:
162:            public RepositoryClassLoader newClassLoader(final URL url,
163:                    final URL origURL, boolean addToRepository)
164:                    throws Exception {
165:                UnifiedClassLoader3 ucl = new UnifiedClassLoader3(url, origURL,
166:                        this );
167:                if (addToRepository)
168:                    this .registerClassLoader(ucl);
169:                return ucl;
170:            }
171:
172:            public int getCacheSize() {
173:                return classes.size();
174:            }
175:
176:            public int getClassLoadersSize() {
177:                return classLoaders.size();
178:            }
179:
180:            public void flush() {
181:                synchronized (classes) {
182:                    classes.clear();
183:                }
184:            }
185:
186:            public Class getCachedClass(String classname) {
187:                return (Class) classes.get(classname);
188:            }
189:
190:            /** Unlike other implementations of LoaderRepository, this method does
191:             * nothing but ask the UnifiedClassLoader3 to load the class as UCL3s
192:             * do not use this method.
193:             */
194:            public Class loadClass(String name, boolean resolve, ClassLoader cl)
195:                    throws ClassNotFoundException {
196:                RepositoryClassLoader rcl = getRepositoryClassLoader(cl, name);
197:                return rcl.loadClass(name, resolve);
198:            }
199:
200:            /** Called by LoadMgr to obtain all class loaders for the given className
201:             * @return Set<UnifiedClassLoader3>, may be null
202:             */
203:            public Set getPackageClassLoaders(String className) {
204:                String pkgName = ClassLoaderUtils.getPackageName(className);
205:                Set pkgSet = (Set) packagesMap.get(pkgName);
206:                if (dynamicClassLoaders.size() > 0) {
207:                    if (pkgSet == null)
208:                        pkgSet = ClassLoaderUtils.newPackageSet();
209:                    pkgSet.addAll(dynamicClassLoaders);
210:                }
211:                return pkgSet;
212:            }
213:
214:            private String getResourcePackageName(String rsrcName) {
215:                int index = rsrcName.lastIndexOf('/');
216:                String pkgName = rsrcName;
217:                if (index > 0)
218:                    pkgName = rsrcName.substring(0, index);
219:                return pkgName.replace('/', '.');
220:            }
221:
222:            /** Lookup a Class from the repository cache.
223:             * @param name the fully qualified class name
224:             * @return the cached Class if found, null otherwise
225:             */
226:            public Class loadClassFromCache(String name) {
227:                Class cls = null;
228:                synchronized (classes) {
229:                    cls = (Class) classes.get(name);
230:                }
231:                return cls;
232:            }
233:
234:            /** Add a Class to the repository cache.
235:             * @param name the fully qualified class name
236:             * @param cls the Class instance
237:             * @param cl the repository UCL
238:             */
239:            public void cacheLoadedClass(String name, Class cls, ClassLoader cl) {
240:                synchronized (classes) {
241:                    // Update the global cache
242:                    Object prevClass = classes.put(name, cls);
243:                    if (log.isTraceEnabled()) {
244:                        log.trace("cacheLoadedClass, classname: " + name
245:                                + ", class: " + cls + ", ucl: " + cl
246:                                + ", prevClass: " + prevClass);
247:                    }
248:
249:                    // Update the cache for this classloader
250:                    // This is used to cycling classloaders
251:                    HashSet loadedClasses = (HashSet) loaderToClassesMap
252:                            .get(cl);
253:                    if (loadedClasses == null) {
254:                        loadedClasses = new HashSet();
255:                        loaderToClassesMap.put(cl, loadedClasses);
256:                    }
257:                    loadedClasses.add(name);
258:                }
259:            }
260:
261:            Class loadClassFromClassLoader(String name, boolean resolve,
262:                    RepositoryClassLoader cl) {
263:                try {
264:                    Class cls = cl.loadClassLocally(name, resolve);
265:                    cacheLoadedClass(name, cls, cl);
266:                    return cls;
267:                } catch (ClassNotFoundException x) {
268:                    // The class is not visible by the calling classloader
269:                }
270:                return null;
271:            }
272:
273:            /**
274:             * Loads a resource following the Unified ClassLoader architecture
275:             */
276:            public URL getResource(String name, ClassLoader cl) {
277:                // getResource() calls are not synchronized on the classloader from JDK code.
278:                // First ask the cache (of the calling classloader)
279:                URL resource = getResourceFromCache(name, cl);
280:
281:                // The resource was already loaded by the calling classloader, we're done
282:                if (resource != null)
283:                    return resource;
284:
285:                // Not found in cache, ask the calling classloader
286:                resource = getResourceFromClassLoader(name, cl);
287:
288:                // The calling classloader sees the resource, we're done
289:                if (resource != null)
290:                    return resource;
291:
292:                // Not found in classloader, ask the global cache
293:                resource = getResourceFromGlobalCache(name);
294:
295:                // The cache has it, we are done
296:                if (resource != null)
297:                    return resource;
298:
299:                // Not visible in global cache, iterate on all classloaders
300:                resource = getResourceFromRepository(name, cl);
301:
302:                // Some other classloader sees the resource, we're done
303:                if (resource != null)
304:                    return resource;
305:
306:                // This resource is not visible
307:                return null;
308:            }
309:
310:            /** Find all resource URLs for the given name. This is entails an
311:             * exhuastive search of the repository and is an expensive operation.
312:             *
313:             * @param name the resource name
314:             * @param cl the requesting class loader
315:             * @param urls a list into which the located resource URLs will be placed
316:             */
317:            public void getResources(String name, ClassLoader cl, List urls) {
318:                // Go through all class loaders
319:                Iterator iter = classLoaders.iterator();
320:                while (iter.hasNext() == true) {
321:                    ClassLoader nextCL = (ClassLoader) iter.next();
322:                    if (nextCL instanceof  RepositoryClassLoader) {
323:                        RepositoryClassLoader ucl = (RepositoryClassLoader) nextCL;
324:                        try {
325:                            Enumeration resURLs = ucl
326:                                    .findResourcesLocally(name);
327:                            while (resURLs.hasMoreElements()) {
328:                                Object res = resURLs.nextElement();
329:                                urls.add(res);
330:                            }
331:                        } catch (IOException ignore) {
332:                        }
333:                    }
334:                }
335:            }
336:
337:            /** As opposed to classes, resource are not looked up in a global cache,
338:             * since it is possible that 2 classloaders have the same resource name
339:             * (ejb-jar.xml), a global cache will overwrite. Instead we look in the
340:             * classloader's cache that we mantain to cycle the classloaders
341:             * @param name the resource name
342:             * @param cl the repository classloader
343:             * @return the resource URL if found, null otherwise
344:             */
345:            private URL getResourceFromCache(String name, ClassLoader cl) {
346:                URL resource = null;
347:                synchronized (loaderToResourcesMap) {
348:                    if (loaderToResourcesMap.containsKey(cl)) {
349:                        HashMap resources = (HashMap) loaderToResourcesMap
350:                                .get(cl);
351:                        resource = (URL) resources.get(name);
352:                    }
353:                }
354:                return resource;
355:            }
356:
357:            private URL getResourceFromClassLoader(String name, ClassLoader cl) {
358:                URL resource = null;
359:                if (cl instanceof  RepositoryClassLoader) {
360:                    RepositoryClassLoader ucl = (RepositoryClassLoader) cl;
361:                    resource = ucl.getResourceLocally(name);
362:                    cacheLoadedResource(name, resource, cl);
363:                }
364:                return resource;
365:            }
366:
367:            /** Check for a resource in the global cache
368:             * Synchronizes access to globalResources using the loaderToResourcesMap monitor
369:             * @param name
370:             * @return
371:             */
372:            protected URL getResourceFromGlobalCache(String name) {
373:                ResourceInfo ri = null;
374:                synchronized (loaderToResourcesMap) {
375:                    ri = (ResourceInfo) globalResources.get(name);
376:                }
377:                URL resource = null;
378:                if (ri != null)
379:                    resource = ri.url;
380:                return resource;
381:            }
382:
383:            protected URL getResourceFromRepository(String name, ClassLoader cl) {
384:                // Get the set of class loaders from the packages map
385:                String pkgName = getResourcePackageName(name);
386:                Iterator i = null;
387:                Set pkgSet = (Set) this .packagesMap.get(pkgName);
388:                if (pkgSet != null) {
389:                    i = pkgSet.iterator();
390:                }
391:                if (i == null) {
392:                    // If no pkg match was found just go through all class loaders
393:                    i = classLoaders.iterator();
394:                }
395:
396:                URL url = null;
397:                while (i.hasNext() == true) {
398:                    ClassLoader classloader = (ClassLoader) i.next();
399:                    if (classloader.equals(cl)) {
400:                        continue;
401:                    }
402:
403:                    if (classloader instanceof  RepositoryClassLoader) {
404:                        url = ((RepositoryClassLoader) classloader)
405:                                .getResourceLocally(name);
406:                        if (url != null) {
407:                            cacheLoadedResource(name, url, classloader);
408:                            cacheGlobalResource(name, url, classloader);
409:                            break;
410:                        } else {
411:                            // Do nothing, go on with next classloader
412:                        }
413:                    }
414:                }
415:                return url;
416:            }
417:
418:            /** Update the loaderToResourcesMap
419:             * @param name the resource name
420:             * @param url the resource URL
421:             * @param cl the UCL
422:             */
423:            private void cacheLoadedResource(String name, URL url,
424:                    ClassLoader cl) {
425:                // Update the cache for this classloader only
426:                // This is used for cycling classloaders
427:                synchronized (loaderToResourcesMap) {
428:                    HashMap resources = (HashMap) loaderToResourcesMap.get(cl);
429:                    if (resources == null) {
430:                        resources = new HashMap();
431:                        loaderToResourcesMap.put(cl, resources);
432:                    }
433:                    resources.put(name, url);
434:                }
435:            }
436:
437:            /** Update cache of resources looked up via one UCL, buf found in another UCL
438:             * @param name the resource name
439:             * @param url the resource URL
440:             * @param cl the UCL
441:             */
442:            private void cacheGlobalResource(String name, URL url,
443:                    ClassLoader cl) {
444:                synchronized (loaderToResourcesMap) {
445:                    globalResources.put(name, new ResourceInfo(url, cl));
446:                }
447:            }
448:
449:            /** This is a utility method a listing of the URL for all UnifiedClassLoaders
450:             * associated with the repository. It is never called in response to
451:             * class or resource loading.
452:             */
453:            public URL[] getURLs() {
454:                HashSet classpath = new HashSet();
455:                Set tmp = classLoaders;
456:                for (Iterator iter = tmp.iterator(); iter.hasNext();) {
457:                    Object obj = iter.next();
458:                    if (obj instanceof  RepositoryClassLoader) {
459:                        RepositoryClassLoader cl = (RepositoryClassLoader) obj;
460:                        URL[] urls = cl.getClasspath();
461:                        int length = urls != null ? urls.length : 0;
462:                        for (int u = 0; u < length; u++) {
463:                            URL path = urls[u];
464:                            classpath.add(path);
465:                        }
466:                    }
467:                } // for all ClassLoaders
468:
469:                URL[] cp = new URL[classpath.size()];
470:                classpath.toArray(cp);
471:                return cp;
472:            }
473:
474:            /** A utility method that iterates over all repository class loaders and
475:             * display the class information for every UCL that contains the given
476:             * className
477:             */
478:            public String displayClassInfo(String className) {
479:                /* We have to find the class as a resource as we don't want to invoke
480:                loadClass(name) and cause the side-effect of loading new classes.
481:                 */
482:                String classRsrcName = className.replace('.', '/') + ".class";
483:
484:                int count = 0;
485:                Class loadedClass = this .loadClassFromCache(className);
486:                StringBuffer results = new StringBuffer(className
487:                        + " Information\n");
488:                if (loadedClass != null) {
489:                    results.append("Repository cache version:");
490:                    ClassLoaderUtils.displayClassInfo(loadedClass, results);
491:                } else {
492:                    results.append("Not loaded in repository cache\n");
493:                }
494:                Set tmp = classLoaders;
495:                for (Iterator iter = tmp.iterator(); iter.hasNext();) {
496:                    URLClassLoader cl = (URLClassLoader) iter.next();
497:                    URL classURL = cl.findResource(classRsrcName);
498:                    if (classURL != null) {
499:                        results.append("\n\n### Instance" + count
500:                                + " found in UCL: " + cl + "\n");
501:                        count++;
502:                    }
503:                }
504:
505:                // Also look to the parent class loaders of the TCL
506:                ClassLoader tcl = Thread.currentThread()
507:                        .getContextClassLoader();
508:                URLClassLoader[] stack = ClassLoaderUtils
509:                        .getClassLoaderStack(tcl);
510:                for (int s = 0; s < stack.length; s++) {
511:                    URLClassLoader cl = stack[s];
512:                    URL classURL = cl.findResource(classRsrcName);
513:                    if (classURL != null) {
514:                        results.append("\n\n### Instance" + count
515:                                + " via UCL: " + cl + "\n");
516:                        count++;
517:                    }
518:                }
519:
520:                return results.toString();
521:            }
522:
523:            // LoaderRepository overrides ------------------------------------
524:
525:            /** First tries to load from any UCL in the ULR, and if the
526:             * class is not found, next tries the current thread context
527:             * class loader.
528:             * @param className - the class to load
529:             */
530:            public Class loadClass(String className)
531:                    throws ClassNotFoundException {
532:                // Try to load from a UCL in the ULR first
533:                ClassLoader scl = Thread.currentThread()
534:                        .getContextClassLoader();
535:                ClassLoader ucl = null;
536:                if (classLoaders.size() > 0)
537:                    ucl = (ClassLoader) this .classLoaders.iterator().next();
538:                try {
539:                    if (ucl != null)
540:                        return loadClass(className, false, ucl);
541:                } catch (ClassNotFoundException ignore) {
542:                    // go on and try the next loader
543:                }
544:
545:                try {
546:                    // If there is no class try the TCL
547:                    return scl.loadClass(className);
548:                } catch (ClassNotFoundException e) {
549:                    // go on and try the next loader
550:                }
551:
552:                // at last try a native
553:                Class clazz = getNativeClassForName(className);
554:                if (clazz != null)
555:                    return clazz;
556:
557:                throw new ClassNotFoundException(className);
558:            }
559:
560:            /**
561:             * Loads a class from the repository, excluding the given
562:             * classloader.
563:             *
564:             * @param loader the classloader to exclude
565:             * @param className the class to load
566:             * @return the found class
567:             * @exception ClassNotFoundException when there is no such class
568:             */
569:            public Class loadClassWithout(ClassLoader loader, String className)
570:                    throws ClassNotFoundException {
571:                throw new ClassNotFoundException("NYI");
572:            }
573:
574:            /**
575:             * Loads a class from the repository, using the classloaders that were
576:             * registered before the given classloader.
577:             *
578:             * @param stop      consult all the classloaders registered before this one
579:             *                  in an attempt to load a class
580:             * @param className name of the class to load
581:             * @return loaded class instance
582:             * @throws ClassNotFoundException if none of the consulted classloaders were
583:             *                                able to load the requested class
584:             */
585:            public Class loadClassBefore(ClassLoader stop, String className)
586:                    throws ClassNotFoundException {
587:                RepositoryClassLoader stopAt = getRepositoryClassLoader(stop,
588:                        className);
589:                return stopAt.loadClassBefore(className);
590:            }
591:
592:            /**
593:             * Get any wrapping classloader for the passed classloader
594:             * 
595:             * @param cl the wrapped classloader
596:             * @return the wrapping classloader or null if not wrapped
597:             */
598:            public RepositoryClassLoader getWrappingClassLoader(ClassLoader cl) {
599:                synchronized (classLoaders) {
600:                    return (RepositoryClassLoader) nonUCLClassLoader.get(cl);
601:                }
602:            }
603:
604:            /** Add a class loader to the repository.
605:             */
606:            public void addClassLoader(ClassLoader loader) {
607:                // if you come to us as UCL we send you straight to the orbit
608:                if (loader instanceof  RepositoryClassLoader)
609:                    addRepositoryClassLoader((RepositoryClassLoader) loader);
610:                else if (loader instanceof  MLet) {
611:                    addMLetClassLoader((MLet) loader);
612:                } else if (loader instanceof  URLClassLoader) {
613:                    addURLClassLoader((URLClassLoader) loader);
614:                } else {
615:                    log.warn("Tried to add non-URLClassLoader.  Ignored");
616:                } // end of else
617:            }
618:
619:            public boolean addClassLoaderURL(ClassLoader cl, URL url) {
620:                RepositoryClassLoader ucl = (RepositoryClassLoader) cl;
621:                boolean added = false;
622:                synchronized (classLoaders) {
623:                    // Strip any query parameter
624:                    String query = url.getQuery();
625:                    if (query != null) {
626:                        String ext = url.toExternalForm();
627:                        String ext2 = ext.substring(0, ext.length()
628:                                - query.length() - 1);
629:                        try {
630:                            url = new URL(ext2);
631:                        } catch (MalformedURLException e) {
632:                            log.warn("Failed to strip query from: " + url, e);
633:                        }
634:                    }
635:
636:                    // See if the URL is associated with a class loader
637:                    if (classLoaderURLs.contains(url) == false) {
638:                        updatePackageMap(ucl, url);
639:                        classLoaderURLs.add(url);
640:                        added = true;
641:                        // Check for a dynamic URL
642:                        if (query != null && query.indexOf("dynamic=true") >= 0)
643:                            dynamicClassLoaders.add(ucl);
644:                    }
645:                }
646:                return added;
647:            }
648:
649:            /** Add a UCL to the repository.
650:             * This sychronizes on classLoaders.
651:             * @param cl
652:             */
653:            private void addRepositoryClassLoader(RepositoryClassLoader cl) {
654:                cl.setRepository(this );
655:                // See if this URL already exists
656:                URL url = cl.getURL();
657:                boolean added = false;
658:                synchronized (classLoaders) {
659:                    boolean exists = false;
660:                    if (cl instanceof  UnifiedClassLoader)
661:                        exists = classLoaderURLs.contains(url);
662:                    // If already present will not be added
663:                    if (!exists) {
664:                        if (url != null)
665:                            classLoaderURLs.add(url);
666:                        added = classLoaders.add(cl);
667:                    }
668:                    if (added) {
669:                        log.debug("Adding " + cl);
670:                        addedCount++;
671:                        cl.setAddedOrder(addedCount);
672:                        updatePackageMap(cl);
673:                    } else {
674:                        log.debug("Skipping duplicate " + cl);
675:                    }
676:                }
677:            }
678:
679:            private void addMLetClassLoader(MLet loader) {
680:                MLetRepositoryClassLoader rcl = new MLetRepositoryClassLoader(
681:                        loader);
682:                synchronized (classLoaders) {
683:                    nonUCLClassLoader.put(loader, rcl);
684:                }
685:                addRepositoryClassLoader(rcl);
686:            }
687:
688:            private void addURLClassLoader(URLClassLoader loader) {
689:                URL[] urls = loader.getURLs();
690:                int count = urls != null && urls.length > 0 ? urls.length : 0;
691:                URL origURL = count > 0 ? urls[0] : null;
692:                UnifiedClassLoader3 ucl3 = new UnifiedClassLoader3(origURL,
693:                        origURL, this );
694:                addRepositoryClassLoader(ucl3);
695:                synchronized (classLoaders) {
696:                    nonUCLClassLoader.put(loader, ucl3);
697:                }
698:                for (int i = 1; i < count; i++) {
699:                    this .addClassLoaderURL(ucl3, urls[i]);
700:                }
701:            }
702:
703:            /** Walk through the class loader URL to see what packages it is capable
704:             of handling
705:             */
706:            private void updatePackageMap(RepositoryClassLoader cl) {
707:                try {
708:                    String[] pkgNames = ClassLoaderUtils.updatePackageMap(cl,
709:                            packagesMap);
710:                    loaderToPackagesMap.put(cl, pkgNames);
711:                } catch (Exception e) {
712:                    if (log.isTraceEnabled())
713:                        log.trace("Failed to update pkgs for cl=" + cl, e);
714:                    else
715:                        log.debug("Failed to update pkgs for cl=" + cl, e);
716:                }
717:            }
718:
719:            /** Walk through the new URL to update the packages the ClassLoader is
720:             * capable of handling
721:             */
722:            private void updatePackageMap(RepositoryClassLoader cl, URL url) {
723:                try {
724:                    String[] prevPkgNames = (String[]) loaderToPackagesMap
725:                            .get(cl);
726:                    String[] pkgNames = ClassLoaderUtils.updatePackageMap(cl,
727:                            packagesMap, url, prevPkgNames);
728:                    loaderToPackagesMap.put(cl, pkgNames);
729:                } catch (Exception e) {
730:                    if (log.isTraceEnabled())
731:                        log.trace("Failed to update pkgs for cl=" + cl, e);
732:                    else
733:                        log.debug("Failed to update pkgs for cl=" + cl, e);
734:                }
735:            }
736:
737:            /** Remove the class loader from the repository. This synchronizes on the
738:             * this.classLoaders
739:             */
740:            public void removeClassLoader(ClassLoader loader) {
741:                ArrayList removeNotifications = new ArrayList();
742:                ClassLoader cl = loader;
743:                synchronized (classLoaders) {
744:                    if ((loader instanceof  RepositoryClassLoader) == false) {
745:                        cl = (ClassLoader) nonUCLClassLoader.remove(loader);
746:                    }
747:                    if (cl instanceof  RepositoryClassLoader) {
748:                        RepositoryClassLoader ucl = (RepositoryClassLoader) cl;
749:                        if (getTranslator() != null)
750:                            getTranslator().unregisterClassLoader(ucl);
751:                        URL[] urls = ucl.getClasspath();
752:                        for (int u = 0; u < urls.length; u++)
753:                            classLoaderURLs.remove(urls[u]);
754:                    }
755:                    boolean dynamic = dynamicClassLoaders.remove(cl);
756:                    boolean removed = classLoaders.remove(cl);
757:                    log.debug("UnifiedLoaderRepository removed(" + removed
758:                            + ") " + cl);
759:
760:                    // Take care also of the cycling mapping for classes
761:                    HashSet loadedClasses = null;
762:                    boolean hasLoadedClasses = false;
763:                    synchronized (classes) {
764:                        hasLoadedClasses = loaderToClassesMap.containsKey(cl);
765:                        if (hasLoadedClasses)
766:                            loadedClasses = (HashSet) loaderToClassesMap
767:                                    .remove(cl);
768:                        // This classloader has loaded at least one class
769:                        if (loadedClasses != null) {
770:                            // Notify that classes are about to be removed
771:                            for (Iterator iter = loadedClasses.iterator(); iter
772:                                    .hasNext();) {
773:                                String className = (String) iter.next();
774:                                Notification n = new Notification(
775:                                        CLASS_REMOVED, this ,
776:                                        getNextSequenceNumber(), className);
777:                                removeNotifications.add(n);
778:                            }
779:
780:                            // Remove the classes from the global cache
781:                            for (Iterator i = loadedClasses.iterator(); i
782:                                    .hasNext();) {
783:                                String cls = (String) i.next();
784:                                this .classes.remove(cls);
785:                            }
786:                        }
787:                    }
788:
789:                    // Take care also of the cycling mapping for resources
790:                    synchronized (loaderToResourcesMap) {
791:                        if (loaderToResourcesMap.containsKey(cl)) {
792:                            HashMap resources = (HashMap) loaderToResourcesMap
793:                                    .remove(cl);
794:
795:                            // Remove the resources from the global cache that are from this classloader
796:                            if (resources != null) {
797:                                for (Iterator i = resources.keySet().iterator(); i
798:                                        .hasNext();) {
799:                                    String name = (String) i.next();
800:                                    ResourceInfo ri = (ResourceInfo) globalResources
801:                                            .get(name);
802:                                    if (ri != null && ri.cl == cl)
803:                                        globalResources.remove(name);
804:                                }
805:                            }
806:                        }
807:                    }
808:
809:                    // Clean up the package name to class loader mapping
810:                    if (dynamic == false) {
811:                        String[] pkgNames = (String[]) loaderToPackagesMap
812:                                .remove(cl);
813:                        int length = pkgNames != null ? pkgNames.length : 0;
814:                        for (int p = 0; p < length; p++) {
815:                            String pkgName = pkgNames[p];
816:                            Set pkgSet = (Set) packagesMap.get(pkgName);
817:                            if (pkgSet != null) {
818:                                pkgSet.remove(cl);
819:                                if (pkgSet.isEmpty())
820:                                    packagesMap.remove(pkgName);
821:                            }
822:                        }
823:                    } else {
824:                        // A dynamic classloader could end up in any package set
825:                        loaderToPackagesMap.remove(cl);
826:                        for (Iterator i = packagesMap.entrySet().iterator(); i
827:                                .hasNext();) {
828:                            Map.Entry entry = (Map.Entry) i.next();
829:                            Set pkgSet = (Set) entry.getValue();
830:                            pkgSet.remove(cl);
831:                            if (pkgSet.isEmpty())
832:                                i.remove();
833:                        }
834:                    }
835:                }
836:
837:                // Send the class removal notfications outside of the synchronized block
838:                for (int n = 0; n < removeNotifications.size(); n++) {
839:                    Notification msg = (Notification) removeNotifications
840:                            .get(n);
841:                    broadcaster.sendNotification(msg);
842:                }
843:
844:                Notification msg = new Notification(CLASSLOADER_REMOVED, this ,
845:                        getNextSequenceNumber());
846:                msg.setUserData(cl);
847:                broadcaster.sendNotification(msg);
848:            }
849:
850:            /**
851:             * This method provides an mbean-accessible way to add a
852:             * UnifiedClassloader, and sends a notification when it is added.
853:             *
854:             * @param ucl an <code>UnifiedClassLoader</code> value
855:             * @return a <code>LoaderRepository</code> value
856:             *
857:             * @jmx.managed-operation
858:             */
859:            public LoaderRepository registerClassLoader(
860:                    RepositoryClassLoader ucl) {
861:                addClassLoader(ucl);
862:                Notification msg = new Notification(CLASSLOADER_ADDED, this ,
863:                        getNextSequenceNumber());
864:                msg.setUserData(ucl);
865:                broadcaster.sendNotification(msg);
866:
867:                return this ;
868:            }
869:
870:            /**
871:             * @jmx.managed-operation
872:             */
873:            public LoaderRepository getInstance() {
874:                return this ;
875:            }
876:
877:            // implementation of javax.management.NotificationBroadcaster interface
878:
879:            /**
880:             * addNotificationListener delegates to the broadcaster object we hold.
881:             *
882:             * @param listener a <code>NotificationListener</code> value
883:             * @param filter a <code>NotificationFilter</code> value
884:             * @param handback an <code>Object</code> value
885:             * @exception IllegalArgumentException if an error occurs
886:             */
887:            public void addNotificationListener(NotificationListener listener,
888:                    NotificationFilter filter, Object handback)
889:                    throws IllegalArgumentException {
890:                broadcaster.addNotificationListener(listener, filter, handback);
891:            }
892:
893:            /**
894:             *
895:             * @return <description>
896:             */
897:            public MBeanNotificationInfo[] getNotificationInfo() {
898:                if (info == null) {
899:                    info = new MBeanNotificationInfo[] {
900:                            new MBeanNotificationInfo(
901:                                    new String[] { "CLASSLOADER_ADDED" },
902:                                    "javax.management.Notification",
903:                                    "Notification that a classloader has been added to the extensible classloader"),
904:                            new MBeanNotificationInfo(
905:                                    new String[] { "CLASS_REMOVED" },
906:                                    "javax.management.Notification",
907:                                    "Notification that a class has been removed from the extensible classloader")
908:
909:                    };
910:                }
911:                return info;
912:            }
913:
914:            /**
915:             * removeNotificationListener delegates to our broadcaster object
916:             *
917:             * @param listener a <code>NotificationListener</code> value
918:             * @exception ListenerNotFoundException if an error occurs
919:             */
920:            public void removeNotificationListener(NotificationListener listener)
921:                    throws ListenerNotFoundException {
922:                broadcaster.removeNotificationListener(listener);
923:            }
924:
925:            public void removeNotificationListener(
926:                    NotificationListener listener, NotificationFilter filter,
927:                    Object handback) throws ListenerNotFoundException {
928:                broadcaster.removeNotificationListener(listener, filter,
929:                        handback);
930:            }
931:
932:            // MBeanRegistration
933:            public ObjectName preRegister(MBeanServer server, ObjectName name)
934:                    throws Exception {
935:                return name;
936:            }
937:
938:            public void postRegister(Boolean registrationDone) {
939:            }
940:
941:            public void preDeregister() throws Exception {
942:            }
943:
944:            public void postDeregister() {
945:                log.debug("postDeregister, clearing all references");
946:                classLoaders.clear();
947:                dynamicClassLoaders.clear();
948:                nonUCLClassLoader.clear();
949:                classLoaderURLs.clear();
950:                classes.clear();
951:                loaderToClassesMap.clear();
952:                loaderToResourcesMap.clear();
953:                globalResources.clear();
954:                packagesMap.clear();
955:                loaderToPackagesMap.clear();
956:            }
957:
958:            private synchronized long getNextSequenceNumber() {
959:                return sequenceNumber++;
960:            }
961:
962:            private RepositoryClassLoader getRepositoryClassLoader(
963:                    ClassLoader cl, String name) throws ClassNotFoundException {
964:                if (cl instanceof  RepositoryClassLoader)
965:                    return (RepositoryClassLoader) cl;
966:                else {
967:                    RepositoryClassLoader rcl = getWrappingClassLoader(cl);
968:                    if (rcl == null)
969:                        throw new ClassNotFoundException("Class not found "
970:                                + name + " (Unknown classloader " + cl + ")");
971:                    return rcl;
972:                }
973:            }
974:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.