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.io.ByteArrayOutputStream;
025: import java.io.IOException;
026: import java.io.InputStream;
027: import java.net.MalformedURLException;
028: import java.net.URL;
029: import java.net.URLClassLoader;
030: import java.security.CodeSource;
031: import java.security.PermissionCollection;
032: import java.security.Policy;
033: import java.security.ProtectionDomain;
034: import java.security.cert.Certificate;
035: import java.util.Enumeration;
036: import java.util.HashSet;
037: import java.util.Vector;
038: import java.util.Collections;
039: import java.util.Set;
040:
041: import javax.management.MalformedObjectNameException;
042: import javax.management.ObjectName;
043:
044: import org.jboss.logging.Logger;
045: import org.jboss.util.loading.Translator;
046: import org.jboss.util.collection.SoftSet;
047:
048: import EDU.oswego.cs.dl.util.concurrent.ReentrantLock;
049: import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
050:
051: /**
052: * A RepositoryClassLoader.
053: *
054: * @author <a href="adrian@jboss.com">Adrian Brock</a>
055: * @version $Revision: 60321 $
056: */
057: public abstract class RepositoryClassLoader extends URLClassLoader {
058: // Constants -----------------------------------------------------
059:
060: /** The log */
061: private static final Logger log = Logger
062: .getLogger(RepositoryClassLoader.class);
063:
064: /** The value returned by {@link #getURLs}. */
065: private static final URL[] EMPTY_URL_ARRAY = {};
066:
067: // Attributes -----------------------------------------------------
068:
069: /** Reference to the repository. */
070: protected LoaderRepository repository = null;
071: /** The location where unregister is called from */
072: protected Exception unregisterTrace;
073:
074: /** The relative order in which this class loader was added to the respository */
075: private int addedOrder;
076:
077: /** The parent classloader */
078: protected ClassLoader parent = null;
079:
080: /** Names of classes which have resulted in CNFEs in loadClassLocally */
081: private Set classBlackList = Collections
082: .synchronizedSet(new HashSet());
083: /** Names of resources that were not found in loadResourceLocally */
084: private Set resourceBlackList = Collections
085: .synchronizedSet(new HashSet());
086: /** A HashMap<String, URL> for resource found in loadResourceLocally */
087: private ConcurrentReaderHashMap resourceCache = new ConcurrentReaderHashMap();
088:
089: /** Lock */
090: protected ReentrantLock loadLock = new ReentrantLock();
091:
092: /** A debugging variable used to track the recursive depth of loadClass() */
093: private int loadClassDepth;
094:
095: // Static --------------------------------------------------------
096:
097: // Constructors --------------------------------------------------
098:
099: /**
100: * Create a new LoaderRepositoryClassLoader
101: *
102: * @param urls the urls
103: * @param parent the parent classloader
104: */
105: protected RepositoryClassLoader(URL[] urls, ClassLoader parent) {
106: super (urls, parent);
107: this .parent = parent;
108: // Check the blacklist mode
109: String mode = ClassToStringAction.getProperty(
110: "org.jboss.mx.loading.blacklistMode", null);
111: if (mode == null || mode.equalsIgnoreCase("HashSet")) {
112: classBlackList = Collections.synchronizedSet(new HashSet());
113: resourceBlackList = Collections
114: .synchronizedSet(new HashSet());
115: } else if (mode.equalsIgnoreCase("SoftSet")) {
116: classBlackList = Collections.synchronizedSet(new SoftSet());
117: resourceBlackList = Collections
118: .synchronizedSet(new SoftSet());
119: }
120: }
121:
122: // Public --------------------------------------------------------
123:
124: /**
125: * Get the ObjectName
126: *
127: * @return the object name
128: */
129: public abstract ObjectName getObjectName()
130: throws MalformedObjectNameException;
131:
132: /**
133: * Get the loader repository for this classloader
134: */
135: public LoaderRepository getLoaderRepository() {
136: return repository;
137: }
138:
139: /**
140: * Set the loader repository
141: *
142: * @param repository the repository
143: */
144: public void setRepository(LoaderRepository repository) {
145: log.debug("setRepository, repository=" + repository + ", cl="
146: + this );
147: this .repository = repository;
148: }
149:
150: /**
151: * Get the order this classloader was added to the repository
152: *
153: * @return the order
154: */
155: public int getAddedOrder() {
156: return addedOrder;
157: }
158:
159: /**
160: * Set the order this classloader was added to the repository
161: *
162: * @param addedOrder the added order
163: */
164: public void setAddedOrder(int addedOrder) {
165: this .addedOrder = addedOrder;
166: }
167:
168: /**
169: * Called to attempt to load a class from the set of URLs associated with this classloader.
170: */
171: public Class loadClassLocally(String name, boolean resolve)
172: throws ClassNotFoundException {
173: boolean trace = log.isTraceEnabled();
174: if (trace)
175: log.trace("loadClassLocally, " + this + " name=" + name);
176: if (name == null || name.length() == 0)
177: throw new ClassNotFoundException("Null or empty class name");
178:
179: Class result = null;
180: try {
181: if (isClassBlackListed(name)) {
182: if (trace)
183: log.trace("Class in blacklist, name=" + name);
184: throw new ClassNotFoundException(
185: "Class Not Found(blacklist): " + name);
186: }
187:
188: try {
189: result = super .loadClass(name, resolve);
190: return result;
191: } catch (ClassNotFoundException cnfe) {
192: addToClassBlackList(name);
193: // If this is an array class, use Class.forName to resolve it
194: if (name.charAt(0) == '[') {
195: result = Class.forName(name, true, this );
196: removeFromClassBlackList(name);
197: return result;
198: }
199: if (trace)
200: log.trace("CFNE: Adding to blacklist: " + name);
201: throw cnfe;
202: }
203: } finally {
204: if (trace) {
205: if (result != null)
206: log.trace("loadClassLocally, " + this + " name="
207: + name + " class=" + result + " cl="
208: + result.getClassLoader());
209: else
210: log.trace("loadClassLocally, " + this + " name="
211: + name + " not found");
212: }
213: }
214: }
215:
216: /**
217: * Provides the same functionality as {@link java.net.URLClassLoader#getResource}.
218: */
219: public URL getResourceLocally(String name) {
220: URL resURL = (URL) resourceCache.get(name);
221: if (resURL != null)
222: return resURL;
223: if (isResourceBlackListed(name))
224: return null;
225: resURL = super .getResource(name);
226: if (log.isTraceEnabled() == true)
227: log.trace("getResourceLocally(" + this + "), name=" + name
228: + ", resURL:" + resURL);
229: if (resURL == null)
230: addToResourceBlackList(name);
231: else
232: resourceCache.put(name, resURL);
233: return resURL;
234: }
235:
236: /**
237: * Get the URL associated with the UCL.
238: *
239: * @return the url
240: */
241: public URL getURL() {
242: URL[] urls = super .getURLs();
243: if (urls.length > 0)
244: return urls[0];
245: else
246: return null;
247: }
248:
249: public void unregister() {
250: log.debug("Unregistering cl=" + this );
251: if (repository != null)
252: repository.removeClassLoader(this );
253: clearBlackLists();
254: resourceCache.clear();
255: repository = null;
256: this .unregisterTrace = new Exception();
257: }
258:
259: /**
260: * This method simply invokes the super.getURLs() method to access the
261: * list of URLs that make up the RepositoryClassLoader classpath.
262: *
263: * @return the urls that make up the classpath
264: */
265: public URL[] getClasspath() {
266: return super .getURLs();
267: }
268:
269: /**
270: * Return all library URLs associated with this RepositoryClassLoader
271: *
272: * <p>Do not remove this method without running the WebIntegrationTestSuite
273: */
274: public URL[] getAllURLs() {
275: return repository.getURLs();
276: }
277:
278: /**
279: * Black list a class
280: *
281: * @param name the name of the class
282: */
283: public void addToClassBlackList(String name) {
284: classBlackList.add(name);
285: }
286:
287: /**
288: * Remove class from black list
289: *
290: * @param name the name of the class
291: */
292: public void removeFromClassBlackList(String name) {
293: classBlackList.remove(name);
294: }
295:
296: /**
297: * Is the class black listed?
298: *
299: * @param name the name of the class
300: * @return true when the class is black listed, false otherwise
301: */
302: public boolean isClassBlackListed(String name) {
303: return classBlackList.contains(name);
304: }
305:
306: /**
307: * Clear any class black list.
308: */
309: public void clearClassBlackList() {
310: classBlackList.clear();
311: }
312:
313: /**
314: * Black list a resource
315: *
316: * @param name the name of the resource
317: */
318: public void addToResourceBlackList(String name) {
319: resourceBlackList.add(name);
320: }
321:
322: /**
323: * Remove resource from black list
324: *
325: * @param name the name of the resource
326: */
327: public void removeFromResourceBlackList(String name) {
328: resourceBlackList.remove(name);
329: }
330:
331: /**
332: * Is the resource black listed?
333: *
334: * @param name the name of the resource
335: * @return true when the resource is black listed, false otherwise
336: */
337: public boolean isResourceBlackListed(String name) {
338: return resourceBlackList.contains(name);
339: }
340:
341: /**
342: * Clear any resource blacklist.
343: */
344: public void clearResourceBlackList() {
345: resourceBlackList.clear();
346: }
347:
348: /**
349: * Clear all blacklists
350: */
351: public void clearBlackLists() {
352: clearClassBlackList();
353: clearResourceBlackList();
354: }
355:
356: // URLClassLoader overrides --------------------------------------
357:
358: /** The only caller of this method should be the VM initiated
359: * loadClassInternal() method. This method attempts to acquire the
360: * UnifiedLoaderRepository2 lock and then asks the repository to
361: * load the class.
362: *
363: * <p>Forwards request to {@link LoaderRepository}.
364: */
365: public Class loadClass(String name, boolean resolve)
366: throws ClassNotFoundException {
367: boolean trace = log.isTraceEnabled();
368: if (trace)
369: log.trace("loadClass " + this + " name=" + name
370: + ", loadClassDepth=" + loadClassDepth);
371: Class clazz = null;
372: try {
373: if (repository != null) {
374: clazz = repository.getCachedClass(name);
375: if (clazz != null) {
376: if (log.isTraceEnabled()) {
377: StringBuffer buffer = new StringBuffer(
378: "Loaded class from cache, ");
379: ClassToStringAction.toString(clazz, buffer);
380: log.trace(buffer.toString());
381: }
382: return clazz;
383: }
384: }
385: clazz = loadClassImpl(name, resolve, Integer.MAX_VALUE);
386: return clazz;
387: } finally {
388: if (trace) {
389: if (clazz != null)
390: log.trace("loadClass " + this + " name=" + name
391: + " class=" + clazz + " cl="
392: + clazz.getClassLoader());
393: else
394: log.trace("loadClass " + this + " name=" + name
395: + " not found");
396: }
397: }
398: }
399:
400: /** The only caller of this method should be the VM initiated
401: * loadClassInternal() method. This method attempts to acquire the
402: * UnifiedLoaderRepository2 lock and then asks the repository to
403: * load the class.
404: *
405: * <p>Forwards request to {@link LoaderRepository}.
406: */
407: public Class loadClassBefore(String name)
408: throws ClassNotFoundException {
409: boolean trace = log.isTraceEnabled();
410: if (trace)
411: log.trace("loadClassBefore " + this + " name=" + name);
412: Class clazz = null;
413: try {
414: clazz = loadClassImpl(name, false, addedOrder);
415: return clazz;
416: } finally {
417: if (trace) {
418: if (clazz != null)
419: log.trace("loadClassBefore " + this + " name="
420: + name + " class=" + clazz + " cl="
421: + clazz.getClassLoader());
422: else
423: log.trace("loadClassBefore " + this + " name="
424: + name + " not found");
425: }
426: }
427: }
428:
429: public synchronized Class loadClassImpl(String name,
430: boolean resolve, int stopAt) throws ClassNotFoundException {
431: loadClassDepth++;
432: boolean trace = log.isTraceEnabled();
433:
434: if (trace)
435: log.trace("loadClassImpl, name=" + name + ", resolve="
436: + resolve);
437: if (repository == null) {
438: // If we have been undeployed we can still try locally
439: try {
440: return super .loadClass(name, resolve);
441: } catch (ClassNotFoundException ignored) {
442: }
443: String msg = "Invalid use of destroyed classloader, UCL destroyed at:";
444: throw new ClassNotFoundException(msg, this .unregisterTrace);
445: }
446:
447: /* Since loadClass can be called from loadClassInternal with the monitor
448: already held, we need to determine if there is a ClassLoadingTask
449: which requires this UCL. If there is, we release the UCL monitor
450: so that the ClassLoadingTask can use the UCL.
451: */
452: boolean acquired = attempt(1);
453: while (acquired == false) {
454: /* Another thread needs this UCL to load a class so release the
455: monitor acquired by the synchronized method. We loop until
456: we can acquire the class loading lock.
457: */
458: try {
459: if (trace)
460: log.trace("Waiting for loadClass lock");
461: this .wait();
462: } catch (InterruptedException ignore) {
463: }
464: acquired = attempt(1);
465: }
466:
467: ClassLoadingTask task = null;
468: try {
469: Thread t = Thread.currentThread();
470: // Register this thread as owning this UCL
471: if (loadLock.holds() == 1)
472: LoadMgr3.registerLoaderThread(this , t);
473:
474: // Create a class loading task and submit it to the repository
475: task = new ClassLoadingTask(name, this , t, stopAt);
476: /* Process class loading tasks needing this UCL until our task has
477: been completed by the thread owning the required UCL(s).
478: */
479: UnifiedLoaderRepository3 ulr3 = (UnifiedLoaderRepository3) repository;
480: if (LoadMgr3.beginLoadTask(task, ulr3) == false) {
481: while (task.threadTaskCount != 0) {
482: try {
483: LoadMgr3.nextTask(t, task, ulr3);
484: } catch (InterruptedException e) {
485: // Abort the load or retry?
486: break;
487: }
488: }
489: }
490: } finally {
491: // Unregister as the UCL owner to reschedule any remaining load tasks
492: if (loadLock.holds() == 1)
493: LoadMgr3.endLoadTask(task);
494: // Notify any threads waiting to use this UCL
495: this .release();
496: this .notifyAll();
497: loadClassDepth--;
498: }
499:
500: if (task.loadedClass == null) {
501: if (task.loadException instanceof ClassNotFoundException)
502: throw (ClassNotFoundException) task.loadException;
503: else if (task.loadException instanceof NoClassDefFoundError)
504: throw (NoClassDefFoundError) task.loadException;
505: else if (task.loadException != null) {
506: if (log.isTraceEnabled())
507: log.trace(
508: "Unexpected error during load of:" + name,
509: task.loadException);
510: String msg = "Unexpected error during load of: " + name
511: + ", msg=" + task.loadException.getMessage();
512: ClassNotFoundException cnfe = new ClassNotFoundException(
513: msg, task.loadException);
514: throw cnfe;
515: }
516: // Assert that loadedClass is not null
517: else
518: throw new IllegalStateException(
519: "ClassLoadingTask.loadedTask is null, name: "
520: + name);
521: }
522:
523: return task.loadedClass;
524: }
525:
526: /**
527: * Attempts to load the resource from its URL and if not found
528: * forwards to the request to {@link LoaderRepository}.
529: */
530: public URL getResource(String name) {
531: if (repository != null)
532: return repository.getResource(name, this );
533: return null;
534: }
535:
536: /** Find all resource URLs for the given name. This overrides the
537: * URLClassLoader version to look for resources in the repository.
538: *
539: * @param name the name of the resource
540: * @return Enumeration<URL>
541: * @throws java.io.IOException
542: */
543: public Enumeration findResources(String name) throws IOException {
544: Vector resURLs = new Vector();
545: if (repository == null) {
546: String msg = "Invalid use of destroyed classloader, UCL destroyed at:";
547: IOException e = new IOException(msg);
548: e.initCause(this .unregisterTrace);
549: throw e;
550: }
551: repository.getResources(name, this , resURLs);
552: return resURLs.elements();
553: }
554:
555: /**
556: * Provides the same functionality as {@link java.net.URLClassLoader#findResources}.
557: */
558: public Enumeration findResourcesLocally(String name)
559: throws IOException {
560: return super .findResources(name);
561: }
562:
563: /** Called by loadClassLocally to find the requested class within this
564: * class loaders class path.
565: *
566: * @param name the name of the class
567: * @return the resulting class
568: * @exception ClassNotFoundException if the class could not be found
569: */
570: protected Class findClass(String name)
571: throws ClassNotFoundException {
572: boolean trace = log.isTraceEnabled();
573: if (trace)
574: log.trace("findClass, name=" + name);
575: if (isClassBlackListed(name)) {
576: if (trace)
577: log.trace("Class in blacklist, name=" + name);
578: throw new ClassNotFoundException(
579: "Class Not Found(blacklist): " + name);
580: }
581:
582: Translator translator = repository.getTranslator();
583: if (translator != null) {
584: // Obtain the transformed class bytecode
585: try {
586: // Obtain the raw bytecode from the classpath
587: URL classUrl = getClassURL(name);
588: byte[] rawcode = loadByteCode(classUrl);
589: URL codeSourceUrl = getCodeSourceURL(name, classUrl);
590: ProtectionDomain pd = getProtectionDomain(codeSourceUrl);
591: byte[] bytecode = translator.transform(this , name,
592: null, pd, rawcode);
593: // If there was no transform use the raw bytecode
594: if (bytecode == null)
595: bytecode = rawcode;
596: // Define the class package and instance
597: definePackage(name);
598: return defineClass(name, bytecode, 0, bytecode.length,
599: pd);
600: } catch (ClassNotFoundException e) {
601: throw e;
602: } catch (Throwable ex) {
603: throw new ClassNotFoundException(name, ex);
604: }
605: }
606:
607: Class clazz = null;
608: try {
609: clazz = findClassLocally(name);
610: } catch (ClassNotFoundException e) {
611: if (trace)
612: log.trace("CFNE: Adding to blacklist: " + name);
613: addToClassBlackList(name);
614: throw e;
615: }
616: return clazz;
617: }
618:
619: /**
620: * Find the class
621: *
622: * @param name the name of the class
623: * @return the class
624: */
625: protected Class findClassLocally(String name)
626: throws ClassNotFoundException {
627: return super .findClass(name);
628: }
629:
630: /**
631: * Define the package for the class if not already done
632: *
633: * @todo this properly
634: * @param className the class name
635: */
636: protected void definePackage(String className) {
637: int i = className.lastIndexOf('.');
638: if (i == -1)
639: return;
640:
641: try {
642: definePackage(className.substring(0, i), null, null, null,
643: null, null, null, null);
644: } catch (IllegalArgumentException alreadyDone) {
645: }
646: }
647:
648: /** Append the given url to the URLs used for class and resource loading
649: * @param url the URL to load from
650: */
651: public void addURL(URL url) {
652: if (url == null)
653: throw new IllegalArgumentException("url cannot be null");
654:
655: if (repository.addClassLoaderURL(this , url) == true) {
656: log.debug("Added url: " + url + ", to ucl: " + this );
657: // Strip any query parameters
658: String query = url.getQuery();
659: if (query != null) {
660: String ext = url.toExternalForm();
661: String ext2 = ext.substring(0, ext.length()
662: - query.length() - 1);
663: try {
664: url = new URL(ext2);
665: } catch (MalformedURLException e) {
666: log.warn("Failed to strip query from: " + url, e);
667: }
668: }
669: super .addURL(url);
670: clearBlackLists();
671: } else if (log.isTraceEnabled()) {
672: log.trace("Ignoring duplicate url: " + url + ", for ucl: "
673: + this );
674: }
675: }
676:
677: /**
678: * Return an empty URL array to force the RMI marshalling subsystem to
679: * use the <tt>java.server.codebase</tt> property as the annotated codebase.
680: *
681: * <p>Do not remove this method without discussing it on the dev list.
682: *
683: * @return Empty URL[]
684: */
685: public URL[] getURLs() {
686: return EMPTY_URL_ARRAY;
687: }
688:
689: public Package getPackage(String name) {
690: return super .getPackage(name);
691: }
692:
693: public Package[] getPackages() {
694: return super .getPackages();
695: }
696:
697: // Object overrides ----------------------------------------------
698:
699: /**
700: * This is here to document that this must delegate to the
701: * super implementation to perform identity based equality. Using
702: * URL based equality caused conflicts with the Class.forName(String,
703: * boolean, ClassLoader).
704: */
705: public final boolean equals(Object other) {
706: return super .equals(other);
707: }
708:
709: /**
710: * This is here to document that this must delegate to the
711: * super implementation to perform identity based hashing. Using
712: * URL based hashing caused conflicts with the Class.forName(String,
713: * boolean, ClassLoader).
714: */
715: public final int hashCode() {
716: return super .hashCode();
717: }
718:
719: /**
720: * Returns a string representation.
721: */
722: public String toString() {
723: return super .toString() + "{ url=" + getURL() + " }";
724: }
725:
726: // Protected -----------------------------------------------------
727:
728: /** Attempt to acquire the class loading lock. This lock must be acquired
729: * before a thread enters the class loading task loop in loadClass. This
730: * method maintains any interrupted state of the calling thread.
731: *@see #loadClass(String, boolean)
732: */
733: protected boolean attempt(long waitMS) {
734: boolean acquired = false;
735: boolean trace = log.isTraceEnabled();
736: // Save and clear the interrupted state of the incoming thread
737: boolean threadWasInterrupted = Thread.interrupted();
738: try {
739: acquired = loadLock.attempt(waitMS);
740: } catch (InterruptedException e) {
741: } finally {
742: // Restore the interrupted state of the thread
743: if (threadWasInterrupted)
744: Thread.currentThread().interrupt();
745: }
746: if (trace)
747: log.trace("attempt(" + loadLock.holds() + ") was: "
748: + acquired + " for :" + this );
749: return acquired;
750: }
751:
752: /** Acquire the class loading lock. This lock must be acquired
753: * before a thread enters the class loading task loop in loadClass.
754: *@see #loadClass(String, boolean)
755: */
756: protected void acquire() {
757: // Save and clear the interrupted state of the incoming thread
758: boolean threadWasInterrupted = Thread.interrupted();
759: try {
760: loadLock.acquire();
761: } catch (InterruptedException e) {
762: } finally {
763: // Restore the interrupted state of the thread
764: if (threadWasInterrupted)
765: Thread.currentThread().interrupt();
766: }
767: if (log.isTraceEnabled())
768: log
769: .trace("acquired(" + loadLock.holds() + ") for :"
770: + this );
771: }
772:
773: /** Release the class loading lock previous acquired through the acquire
774: * method.
775: */
776: protected void release() {
777: if (log.isTraceEnabled())
778: log.trace("release(" + loadLock.holds() + ") for :" + this );
779: loadLock.release();
780: if (log.isTraceEnabled())
781: log.trace("released, holds: " + loadLock.holds());
782: }
783:
784: /** Obtain the bytecode for the indicated class from this class loaders
785: * classpath.
786: *
787: * @param classname
788: * @return the bytecode array if found
789: * @exception ClassNotFoundException - if the class resource could not
790: * be found
791: */
792: protected byte[] loadByteCode(String classname)
793: throws ClassNotFoundException, IOException {
794: byte[] bytecode = null;
795: URL classURL = getClassURL(classname);
796:
797: // Load the class bytecode
798: InputStream is = null;
799: try {
800: is = classURL.openStream();
801: ByteArrayOutputStream baos = new ByteArrayOutputStream();
802: byte[] tmp = new byte[1024];
803: int read = 0;
804: while ((read = is.read(tmp)) > 0) {
805: baos.write(tmp, 0, read);
806: }
807: bytecode = baos.toByteArray();
808: } finally {
809: if (is != null)
810: is.close();
811: }
812:
813: return bytecode;
814: }
815:
816: /** Obtain the bytecode for the indicated class from this class loaders
817: * classpath.
818: *
819: * @param classURL
820: * @return the bytecode array if found
821: * @exception ClassNotFoundException - if the class resource could not
822: * be found
823: */
824: protected byte[] loadByteCode(URL classURL)
825: throws ClassNotFoundException, IOException {
826: byte[] bytecode = null;
827: // Load the class bytecode
828: InputStream is = null;
829: try {
830: is = classURL.openStream();
831: ByteArrayOutputStream baos = new ByteArrayOutputStream();
832: byte[] tmp = new byte[1024];
833: int read = 0;
834: while ((read = is.read(tmp)) > 0) {
835: baos.write(tmp, 0, read);
836: }
837: bytecode = baos.toByteArray();
838: } finally {
839: if (is != null)
840: is.close();
841: }
842:
843: return bytecode;
844: }
845:
846: /**
847: * Determine the protection domain. If we are a copy of the original
848: * deployment, use the original url as the codebase.
849: * @return the protection domain
850: * @todo certificates and principles?
851: */
852: protected ProtectionDomain getProtectionDomain(URL codesourceUrl) {
853: Certificate certs[] = null;
854: CodeSource cs = new CodeSource(codesourceUrl, certs);
855: PermissionCollection permissions = Policy.getPolicy()
856: .getPermissions(cs);
857: if (log.isTraceEnabled())
858: log.trace("getProtectionDomain, url=" + codesourceUrl
859: + " codeSource=" + cs + " permissions="
860: + permissions);
861: return new ProtectionDomain(cs, permissions);
862: }
863:
864: // Package Private -----------------------------------------------
865:
866: // Private -------------------------------------------------------
867:
868: private URL getCodeSourceURL(String classname, URL classURL)
869: throws java.net.MalformedURLException {
870: String classRsrcName = classname.replace('.', '/') + ".class";
871: String urlAsString = classURL.toString();
872: int idx = urlAsString.indexOf(classRsrcName);
873: if (idx == -1)
874: return classURL;
875: urlAsString = urlAsString.substring(0, idx);
876: return new URL(urlAsString);
877: }
878:
879: private URL getClassURL(String classname)
880: throws ClassNotFoundException {
881: String classRsrcName = classname.replace('.', '/') + ".class";
882: URL classURL = this .getResourceLocally(classRsrcName);
883: if (classURL == null) {
884: String msg = "Failed to find: " + classname
885: + " as resource: " + classRsrcName;
886: throw new ClassNotFoundException(msg);
887: }
888: return classURL;
889: }
890:
891: // Inner classes -------------------------------------------------
892: }
|