001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi;
023:
024: import java.io.File;
025: import java.io.FilePermission;
026: import java.io.IOException;
027: import java.lang.ref.WeakReference;
028: import java.lang.reflect.Modifier;
029: import java.lang.reflect.Proxy;
030: import java.net.MalformedURLException;
031: import java.net.SocketPermission;
032: import java.net.URL;
033: import java.net.URLClassLoader;
034: import java.rmi.server.LoaderHandler;
035: import java.rmi.server.RMIClassLoaderSpi;
036: import java.security.AccessControlContext;
037: import java.security.AccessController;
038: import java.security.CodeSource;
039: import java.security.Permission;
040: import java.security.PermissionCollection;
041: import java.security.Permissions;
042: import java.security.Policy;
043: import java.security.PrivilegedAction;
044: import java.security.ProtectionDomain;
045: import java.security.cert.Certificate;
046: import java.util.Arrays;
047: import java.util.Enumeration;
048: import java.util.HashMap;
049: import java.util.Map;
050: import java.util.StringTokenizer;
051: import org.apache.harmony.rmi.common.GetStringPropAction;
052: import org.apache.harmony.rmi.common.RMILog;
053: import org.apache.harmony.rmi.common.RMIProperties;
054: import org.apache.harmony.rmi.internal.nls.Messages;
055:
056: /**
057: * Default implementation of RMIClassLoaderSpi.
058: *
059: * @author Mikhail A. Markov
060: * @version $Revision: 1.1.2.2 $
061: */
062: public class DefaultRMIClassLoaderSpi extends RMIClassLoaderSpi
063: implements LoaderHandler {
064:
065: // value of codebase property
066: private static String userCodeBase;
067:
068: // table holding list of URLLoader-s
069: private static final Map<TableKey, WeakReference<URLLoader>> urlLoaders = new HashMap<TableKey, WeakReference<URLLoader>>();
070:
071: static {
072: String codebaseVal = (String) AccessController
073: .doPrivileged(new GetStringPropAction(
074: RMIProperties.CODEBASE_PROP));
075: userCodeBase = (codebaseVal == null || codebaseVal.trim()
076: .length() == 0) ? null : codebaseVal.trim();
077: }
078:
079: // Logger where to write loader messages.
080: private static final RMILog loaderLog = RMILog.getLoaderLog();
081:
082: /**
083: * Constructs DefaultRMIClassLoaderSpi.
084: */
085: public DefaultRMIClassLoaderSpi() {
086: }
087:
088: /**
089: * @see RMIClassLoaderSpi.loadProxyClass(String, String[], ClassLoader)
090: */
091: public Class loadProxyClass(String codebase, String[] interf,
092: ClassLoader defaultLoader) throws MalformedURLException,
093: ClassNotFoundException {
094: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
095: // rmi.log.25=Loading proxy class: interf=[{0}], codebase="{1}", defaultLoader={2}
096: loaderLog.log(RMILog.VERBOSE, Messages.getString(
097: "rmi.log.25", //$NON-NLS-1$
098: new Object[] { Arrays.asList(interf),
099: ((codebase == null) ? "" : codebase), //$NON-NLS-1$
100: defaultLoader }));
101: }
102: Class[] interfCl = new Class[interf.length];
103: ClassLoader codebaseLoader = null;
104: Exception ex = null;
105: stringToURLs(codebase);
106:
107: try {
108: codebaseLoader = getClassLoader1(codebase);
109: } catch (SecurityException se) {
110: if (loaderLog.isLoggable(RMILog.BRIEF)) {
111: // rmi.log.26=Could not obtain classloader for codebase "{0}" (access denied).
112: loaderLog.log(RMILog.BRIEF, Messages.getString(
113: "rmi.log.26", //$NON-NLS-1$
114: ((codebase == null) ? "" : codebase))); //$NON-NLS-1$
115: }
116: ex = se;
117: }
118: boolean failed = false;
119:
120: // try to resolve all interfaces
121: if (defaultLoader != null) {
122: for (int i = 0; i < interf.length; ++i) {
123: try {
124: interfCl[i] = Class.forName(interf[i], false,
125: defaultLoader);
126: } catch (Exception ex1) {
127: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
128: // rmi.log.27=Unable to load interface {0} via default loader {1}:{2}
129: loaderLog
130: .log(
131: RMILog.VERBOSE,
132: Messages
133: .getString(
134: "rmi.log.27", new Object[] { interf[i], //$NON-NLS-1$
135: defaultLoader,
136: ex1 }));
137: }
138: failed = true;
139: }
140: }
141: }
142:
143: if (failed || (defaultLoader == null)) {
144: if (ex != null) {
145: ClassLoader curLoader = Thread.currentThread()
146: .getContextClassLoader();
147:
148: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
149: // rmi.log.28=Trying thread context classloader ({0}).
150: loaderLog.log(RMILog.VERBOSE, Messages.getString(
151: "rmi.log.28", curLoader)); //$NON-NLS-1$
152: }
153: codebaseLoader = curLoader;
154:
155: }
156:
157: for (int i = 0; i < interf.length; ++i) {
158: try {
159: interfCl[i] = Class.forName(interf[i], false,
160: codebaseLoader);
161: } catch (Exception ex1) {
162: if (loaderLog.isLoggable(RMILog.BRIEF)) {
163: // rmi.log.29=Unable to load interface {0} via {1}
164: loaderLog
165: .log(
166: RMILog.BRIEF,
167: Messages
168: .getString(
169: "rmi.log.29", interf[i], codebaseLoader)); //$NON-NLS-1$
170: }
171:
172: if (ex != null) {
173: // rmi.log.2A=Could not load proxy class (access to loader for codebase "{0}" denied).
174: String msg = Messages.getString("rmi.log.2A", //$NON-NLS-1$
175: ((codebase == null) ? "" : codebase)); //$NON-NLS-1$
176:
177: if (loaderLog.isLoggable(RMILog.BRIEF)) {
178: loaderLog.log(RMILog.BRIEF, msg);
179: }
180: throw new ClassNotFoundException(msg, ex);
181: } else {
182: // rmi.25=Unable to load proxy class
183: throw new ClassNotFoundException(Messages
184: .getString("rmi.25"), ex1); //$NON-NLS-1$
185: }
186: }
187: }
188: }
189:
190: // successfully loaded all interfaces
191: boolean allPublic = true;
192: ClassLoader interfLoader = null;
193: boolean sameLoader = true;
194:
195: // check if all interfaces are public
196: for (int i = 0; i < interfCl.length; ++i) {
197: if (!Modifier.isPublic(interfCl[i].getModifiers())) {
198: allPublic = false;
199: ClassLoader loader = interfCl[i].getClassLoader();
200:
201: if (interfLoader == null) {
202: interfLoader = loader;
203: } else if (!interfLoader.equals(loader)) {
204: if (loaderLog.isLoggable(RMILog.BRIEF)) {
205: // rmi.log.2B=Non-public interface {0} is loaded by another loader ({1}) then others ({2})
206: loaderLog.log(RMILog.BRIEF, Messages.getString(
207: "rmi.log.2B", //$NON-NLS-1$
208: new Object[] { interfCl[i], loader,
209: interfLoader }));
210: }
211: sameLoader = false;
212: }
213: }
214: }
215:
216: if (allPublic) {
217: // all interfaces are public
218: Class proxyCl = null;
219:
220: try {
221: proxyCl = Proxy.getProxyClass(codebaseLoader, interfCl);
222:
223: if (loaderLog.isLoggable(RMILog.BRIEF)) {
224: // rmi.log.2C=Loaded proxy class {0} via {1}
225: loaderLog.log(RMILog.BRIEF, Messages.getString(
226: "rmi.log.2C", //$NON-NLS-1$
227: proxyCl, codebaseLoader));
228: }
229: } catch (IllegalArgumentException iae) {
230: try {
231: proxyCl = Proxy.getProxyClass(defaultLoader,
232: interfCl);
233:
234: if (loaderLog.isLoggable(RMILog.BRIEF)) {
235: // rmi.log.2C=Loaded proxy class {0} via {1}
236: loaderLog.log(RMILog.BRIEF, Messages.getString(
237: "rmi.log.2C", //$NON-NLS-1$
238: proxyCl, defaultLoader));
239: }
240: } catch (IllegalArgumentException iae1) {
241: if (loaderLog.isLoggable(RMILog.BRIEF)) {
242: // rmi.log.2D=Unable to load proxy class via both loaders ({0}, {1})
243: loaderLog.log(RMILog.BRIEF, Messages.getString(
244: "rmi.log.2D", //$NON-NLS-1$
245: codebaseLoader, defaultLoader));
246: }
247: // rmi.25=Unable to load proxy class
248: throw new ClassNotFoundException(Messages
249: .getString("rmi.25"), iae1); //$NON-NLS-1$
250: }
251: }
252: return proxyCl;
253: }
254:
255: // there are non-public interfaces
256: if (sameLoader) {
257: // they are defined in the same ClassLoader
258: Class proxyCl = Proxy.getProxyClass(interfLoader, interfCl);
259:
260: if (loaderLog.isLoggable(RMILog.BRIEF)) {
261: // rmi.log.2C=Loaded proxy class {0} via {1}
262: loaderLog.log(RMILog.BRIEF, Messages.getString(
263: "rmi.log.2C", //$NON-NLS-1$
264: proxyCl, interfLoader));
265: }
266: return proxyCl;
267: }
268: // rmi.25=Unable to load proxy class
269: throw new LinkageError(Messages.getString("rmi.25")); //$NON-NLS-1$
270: }
271:
272: /**
273: * @see RMIClassLoaderSpi.loadClass(String, String, ClassLoader)
274: */
275: public Class loadClass(String codebase, String name,
276: ClassLoader defaultLoader) throws MalformedURLException,
277: ClassNotFoundException {
278: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
279: // rmi.log.2E=Loading class: name="{0}", codebase="{1}", defaultLoader={2}
280: loaderLog.log(RMILog.VERBOSE, Messages.getString(
281: "rmi.log.2E", //$NON-NLS-1$
282: new Object[] { name,
283: ((codebase == null) ? "" : codebase), //$NON-NLS-1$
284: defaultLoader }));
285: }
286: stringToURLs(codebase);
287:
288: try {
289: if (defaultLoader != null) {
290: Class c = Class.forName(name, false, defaultLoader);
291:
292: if (loaderLog.isLoggable(RMILog.BRIEF)) {
293: // rmi.log.2F=Loaded class: {0} via default loader: {1}
294: loaderLog.log(RMILog.BRIEF, Messages.getString(
295: "rmi.log.2F", //$NON-NLS-1$
296: name, defaultLoader));
297: }
298: return c;
299: }
300: } catch (ClassNotFoundException cnfe) {
301: // we ignore this exception and proceed
302: }
303: ClassLoader codebaseLoader = null;
304: Exception ex = null;
305:
306: try {
307: codebaseLoader = getClassLoader1(codebase);
308: } catch (SecurityException se) {
309: if (loaderLog.isLoggable(RMILog.BRIEF)) {
310: loaderLog.log(RMILog.BRIEF, Messages.getString(
311: "rmi.log.30", //$NON-NLS-1$
312: ((codebase == null) ? "" : codebase))); //$NON-NLS-1$
313: }
314: ex = se;
315: }
316: Class c;
317:
318: if (ex != null) {
319: ClassLoader curLoader = Thread.currentThread()
320: .getContextClassLoader();
321:
322: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
323: // rmi.log.31=Trying thread context classloader ({0}).
324: loaderLog.log(RMILog.VERBOSE, Messages.getString(
325: "rmi.log.31", curLoader)); //$NON-NLS-1$
326: }
327:
328: try {
329: c = Class.forName(name, false, curLoader);
330: } catch (ClassNotFoundException cnfe1) {
331: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
332: // rmi.log.32=Could not load class {0} via thread context classloader (access to codebase loader is denied).
333: loaderLog.log(RMILog.VERBOSE, Messages.getString(
334: "rmi.log.32", name)); //$NON-NLS-1$
335: }
336: // rmi.94=Could not load class {0}(access to loader for codebase "{1}" denied).
337: throw new ClassNotFoundException(Messages.getString(
338: "rmi.94", //$NON-NLS-1$
339: name, ((codebase == null) ? "" : codebase)), ex);//$NON-NLS-1$
340:
341: }
342:
343: if (loaderLog.isLoggable(RMILog.BRIEF)) {
344: // rmi.log.34=Loaded class: {0} via thread context classloader.
345: loaderLog.log(RMILog.BRIEF, Messages.getString(
346: "rmi.log.34", name)); //$NON-NLS-1$
347: }
348: } else {
349: c = Class.forName(name, false, codebaseLoader);
350:
351: if (loaderLog.isLoggable(RMILog.VERBOSE)) {
352: // rmi.log.35=Loaded class: {0} via {1}
353: loaderLog.log(RMILog.VERBOSE, Messages.getString(
354: "rmi.log.35", //$NON-NLS-1$
355: name, codebaseLoader));
356: }
357: }
358: return c;
359: }
360:
361: /**
362: * @see RMIClassLoaderSpi.getClassAnnotation(Class)
363: */
364: public String getClassAnnotation(Class cl) {
365: ClassLoader loader = cl.getClassLoader();
366: ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
367:
368: if (loader == systemLoader
369: || (systemLoader != null && loader == systemLoader
370: .getParent())) {
371: return userCodeBase;
372: }
373:
374: if (loader instanceof URLLoader) {
375: return ((URLLoader) loader).getAnnotations();
376: } else if (loader instanceof URLClassLoader) {
377: URL[] urls = ((URLClassLoader) loader).getURLs();
378: String annot = urlsToCodebase(urls);
379:
380: if (annot == null) {
381: return userCodeBase;
382: }
383: SecurityManager mgr = System.getSecurityManager();
384:
385: if (mgr != null) {
386: try {
387: for (int i = 0; i < urls.length; ++i) {
388: Permission p = urls[i].openConnection()
389: .getPermission();
390:
391: if (p != null) {
392: mgr.checkPermission(p);
393: }
394: }
395: } catch (SecurityException se) {
396: return userCodeBase;
397: } catch (IOException ioe) {
398: return userCodeBase;
399: }
400: }
401: return annot;
402: } else {
403: return userCodeBase;
404: }
405: }
406:
407: /**
408: * @see RMIClassLoaderSpi.getClassLoader(String)
409: */
410: public ClassLoader getClassLoader(String codebase)
411: throws MalformedURLException {
412: stringToURLs(codebase);
413: SecurityManager mgr = System.getSecurityManager();
414:
415: if (mgr == null) {
416: return Thread.currentThread().getContextClassLoader();
417: }
418: mgr.checkPermission(new RuntimePermission("getClassLoader")); //$NON-NLS-1$
419: return getClassLoader1(codebase);
420: }
421:
422: /**
423: * @see LoaderHandler.loadClass(String)
424: */
425: public Class loadClass(String name) throws MalformedURLException,
426: ClassNotFoundException {
427: return loadClass(null, name, null);
428: }
429:
430: /**
431: * @see LoaderHandler.loadClass(URL, String)
432: */
433: public Class loadClass(URL codebase, String name)
434: throws MalformedURLException, ClassNotFoundException {
435: return loadClass(codebase.toExternalForm(), name, null);
436: }
437:
438: /**
439: * Always returns null.
440: * This method came from LoaderHandler class and not used.
441: *
442: * @see LoaderHandler.getSecurityContext(ClassLoader)
443: */
444: public Object getSecurityContext(ClassLoader loader) {
445: return null;
446: }
447:
448: /*
449: * Finds loader in classloaders table. Returns it as a result if it's not
450: * null, otherwise creates URLLoader, adds it to the table and returns it
451: * as a result. Checks permission on found/created loader.
452: *
453: * @param codebase list of URLs separated by spaces
454: *
455: * @return ClassLoader found/created
456: *
457: * @throws MalformedURLException if the method was unable to parse one of
458: * provided URLs
459: */
460: private static ClassLoader getClassLoader1(String codebase)
461: throws MalformedURLException {
462: SecurityManager mgr = System.getSecurityManager();
463: ClassLoader parentLoader = Thread.currentThread()
464: .getContextClassLoader();
465:
466: if (mgr == null) {
467: return parentLoader;
468: }
469:
470: if (codebase == null) {
471: if (userCodeBase != null) {
472: codebase = userCodeBase;
473: } else {
474: return parentLoader;
475: }
476: }
477: URLLoader loader = getClassLoaderNoCheck(parentLoader, codebase);
478:
479: if (loader != null) {
480: loader.checkPermissions();
481: }
482: return loader;
483: }
484:
485: /*
486: * Finds URLLoader in classloaders table. Returns it as a result if it's not
487: * null, otherwise creates URLLoader, adds it to the table and returns it
488: * as a result. Does not check permission on found/created loader.
489: *
490: * @param parentLoader parent classloader
491: * @param codebase list of URLs separated by spaces
492: *
493: * @return URLLoader found/created
494: *
495: * @throws MalformedURLException if the method was unable to parse one of
496: * provided URLs
497: */
498: private static URLLoader getClassLoaderNoCheck(
499: ClassLoader parentLoader, String codebase)
500: throws MalformedURLException {
501: TableKey key = new TableKey(parentLoader, codebase);
502: URLLoader loader = null;
503:
504: synchronized (urlLoaders) {
505: if (urlLoaders.containsKey(key)) {
506: loader = urlLoaders.get(key).get();
507:
508: if (loader == null) {
509: urlLoaders.remove(key);
510: } else {
511: return loader;
512: }
513: }
514: AccessControlContext ctx = createLoaderACC(key.getURLs());
515:
516: // PrivilegedAction for URLLoader creation
517: class CreateLoaderAction implements
518: PrivilegedAction<URLLoader> {
519: URL[] urls;
520: ClassLoader parentLoader;
521:
522: public CreateLoaderAction(URL[] urls,
523: ClassLoader parentLoader) {
524: this .urls = urls;
525: this .parentLoader = parentLoader;
526: }
527:
528: public URLLoader run() {
529: return new URLLoader(urls, parentLoader);
530: }
531: }
532: loader = AccessController
533: .doPrivileged(new CreateLoaderAction(key.getURLs(),
534: parentLoader), ctx);
535: urlLoaders.put(key, new WeakReference<URLLoader>(loader));
536: return loader;
537: }
538: }
539:
540: /*
541: * Creates and returns AccessControlContext required to create
542: * URLClassLoader (i.e. context containing permissions sufficient
543: * to create URLClassLoader).
544: *
545: * @param urls list of URLs permissions for which should be granted in
546: * created ACC
547: *
548: * @return AccessControlContext required to create URLClassLoader passing
549: * specified URLs to it's constructor
550: */
551: private static AccessControlContext createLoaderACC(URL[] urls) {
552: // get existing permissions from the installed policy
553: PermissionCollection perms = (PermissionCollection) AccessController
554: .doPrivileged(new PrivilegedAction() {
555: public Object run() {
556: CodeSource cs = new CodeSource(null,
557: (Certificate[]) null);
558: Policy policy = Policy.getPolicy();
559:
560: if (policy != null) {
561: return policy.getPermissions(cs);
562: }
563: return new Permissions();
564: }
565: });
566:
567: // add permissions for URLs
568: addURLsPerms(urls, perms, true);
569:
570: // grant permission for ClassLoader creation
571: perms.add(new RuntimePermission("createClassLoader")); //$NON-NLS-1$
572:
573: // create AccessControlContext from created Permissions
574: ProtectionDomain[] domains;
575:
576: if (urls.length == 0) {
577: domains = new ProtectionDomain[] { new ProtectionDomain(
578: new CodeSource(null, (Certificate[]) null), perms) };
579: } else {
580: domains = new ProtectionDomain[urls.length];
581:
582: for (int i = 0; i < urls.length; ++i) {
583: domains[i] = new ProtectionDomain(new CodeSource(
584: urls[i], (Certificate[]) null), perms);
585: }
586: }
587: return new AccessControlContext(domains);
588: }
589:
590: /*
591: * Adds Permissions required to access provided list of URLs to specified
592: * PermissionCollection and returns this collection as a result.
593: *
594: * @param urls list of URLs for which Permissions should be added
595: * @param perms PermissionCollection where permissions should be added
596: * @param forACC if true then this method was called for creating loader's
597: * AccessControlContext and additional SocketPermission should be
598: * added in case if url is not "file:///"
599: *
600: * @return updated Permissioncollection as a result
601: */
602: private static PermissionCollection addURLsPerms(URL[] urls,
603: PermissionCollection perms, boolean forACC) {
604: for (int i = 0; i < urls.length; ++i) {
605: Permission perm = null;
606:
607: try {
608: perm = urls[i].openConnection().getPermission();
609: } catch (IOException ioe) {
610: continue;
611: }
612:
613: if (perm == null) {
614: continue;
615: }
616:
617: if (perm instanceof FilePermission) {
618: /*
619: * For proper handling of codebases like: file:///c:/tmp/,
620: * where tmp is a directory, we should add '-' symbol to allow
621: * the classloader to read this directory and all subdirectories
622: * if the classes with packages are in this directory unpacked
623: * (not in .jar file).
624: */
625: String str = perm.getName();
626: int idx = str.lastIndexOf(File.separatorChar);
627:
628: if (!str.endsWith(File.separator)) {
629: perms.add(perm);
630: } else {
631: perms.add(new FilePermission(str + "-", "read")); //$NON-NLS-1$ //$NON-NLS-2$
632: }
633: } else {
634: perms.add(perm);
635:
636: if (forACC) {
637: /*
638: * This method was called in 'createLoaderACC()' method
639: * for loader's AccessControlContext creation and additional
640: * SocketPermission allowing connecting to url's host and
641: * accepting connections from it should be added.
642: */
643: String host = urls[i].getHost();
644:
645: if (host != null) {
646: perms.add(new SocketPermission(host,
647: "connect, accept")); //$NON-NLS-1$
648: }
649: }
650: }
651: }
652: return perms;
653: }
654:
655: /*
656: * Converts string representation of urls to array of URLs.
657: *
658: * @param list list of urls separated by spaces
659: *
660: * @return array of URLs from specified list
661: */
662: private static URL[] stringToURLs(String list)
663: throws MalformedURLException {
664: if (list == null) {
665: return null;
666: }
667: StringTokenizer tok = new StringTokenizer(list);
668: URL[] urls = new URL[tok.countTokens()];
669:
670: for (int i = 0; i < urls.length; ++i) {
671: urls[i] = new URL(tok.nextToken());
672: }
673: return urls;
674: }
675:
676: /*
677: * Converts list of URLs to a string, where URLs are separated by spaces.
678: *
679: * @param list of URLs to be converted
680: *
681: * @return string containing specified URLs separated by spaces
682: */
683: private static String urlsToCodebase(URL[] urls) {
684: if (urls == null || urls.length == 0) {
685: return null;
686: }
687: String str = ""; //$NON-NLS-1$
688:
689: for (int i = 0; i < urls.length - 1; ++i) {
690: str += urls[i].toExternalForm() + " "; //$NON-NLS-1$
691: }
692: return str + urls[urls.length - 1].toExternalForm();
693: }
694:
695: /*
696: * This class is a subclass of URLClassLoader. It contains annotations for
697: * classes and also permissions to be checked if requested.
698: */
699: private static class URLLoader extends URLClassLoader {
700: // annotations for classes
701: private String annot;
702:
703: // permissions to be checked if requested
704: private Permissions perms;
705:
706: /*
707: * Constructs URLLoader from list of URLs and parent ClassLoader.
708: *
709: * @param urls list of URLs
710: * @param parent parent ClassLoader
711: */
712: URLLoader(URL[] urls, ClassLoader parent) {
713: super (urls, parent);
714: perms = new Permissions();
715: addURLsPerms(urls, perms, false);
716: annot = urlsToCodebase(urls);
717: }
718:
719: /*
720: * Returns annotations for classes.
721: *
722: * @return annotations for classes
723: */
724: String getAnnotations() {
725: return annot;
726: }
727:
728: /*
729: * Checks permissions contained in this loader if SecurityManager
730: * installed is not null. The method will throw SecurityException
731: * (as SecurityManager does) if one of the permissions is not granted.
732: */
733: void checkPermissions() {
734: SecurityManager mgr = System.getSecurityManager();
735:
736: if (mgr != null) {
737: for (Enumeration en = perms.elements(); en
738: .hasMoreElements(); mgr
739: .checkPermission((Permission) en.nextElement())) {
740: }
741: }
742: }
743:
744: /**
745: * Returns string representation of this loader.
746: *
747: * @return string representation of this loader
748: */
749: public String toString() {
750: return getClass().getName() + "[annot:\"" + annot + "\"]"; //$NON-NLS-1$ //$NON-NLS-2$
751: }
752: }
753:
754: /*
755: * Class representing key for storing classloaders in a Map. It consists
756: * of a pair: loader/URL[].
757: */
758: private static class TableKey {
759: private ClassLoader loader;
760: private URL[] urls;
761: private int hashCode;
762:
763: /*
764: * Constructs TableKey from string representation of the list of URLs.
765: *
766: * @param loader ClassLoader
767: * @param codebase String represented codebase list
768: * separated by <space>
769: */
770: TableKey(ClassLoader loader, String codebase)
771: throws MalformedURLException {
772: this (loader, stringToURLs(codebase));
773: }
774:
775: /*
776: * Constructs TableKey from the specified array of URLs.
777: *
778: * @param loader ClassLoader
779: * @param urls array of URLs
780: */
781: TableKey(ClassLoader loader, URL[] urls) {
782: this .loader = loader;
783: this .urls = urls;
784:
785: // calculate hashCode
786: hashCode = (loader == null) ? 0 : loader.hashCode();
787:
788: for (int i = 0; i < urls.length; ++i) {
789: hashCode ^= urls[i].hashCode();
790: }
791: }
792:
793: /*
794: * Returns ClassLoader contained in this TableKey.
795: *
796: * @return ClassLoader contained in this TableKey
797: */
798: ClassLoader getLoader() {
799: return loader;
800: }
801:
802: /*
803: * Returns list of URLs contained in this TableKey.
804: *
805: * @return list of URLs contained in this TableKey
806: */
807: public URL[] getURLs() {
808: return urls;
809: }
810:
811: /**
812: * Compares this object with another one. Returns true if the object for
813: * comparison is an instance of TableKey and they contained the same
814: * loader and urls fields.
815: *
816: * @param obj object for comparison
817: *
818: * @return true if object specified is equal to this TableKey and false
819: * otherwise
820: */
821: public boolean equals(Object obj) {
822: if (!(obj instanceof TableKey)) {
823: return false;
824: }
825: TableKey key = (TableKey) obj;
826:
827: if (hashCode() != key.hashCode()) {
828: return false;
829: }
830: return ((loader != null) ? loader.equals(key.loader)
831: : (key.loader == null))
832: && ((urls != null) ? Arrays.equals(urls, key.urls)
833: : (key.urls == null));
834: }
835:
836: /**
837: * Returns hash code for this TableKey.
838: *
839: * @return hash code for this TableKey
840: */
841: public int hashCode() {
842: return hashCode;
843: }
844: }
845: }
|