Frames | No Frames |
1: /* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs 2: Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 3: Free Software Foundation, Inc. 4: 5: This file is part of GNU Classpath. 6: 7: GNU Classpath is free software; you can redistribute it and/or modify 8: it under the terms of the GNU General Public License as published by 9: the Free Software Foundation; either version 2, or (at your option) 10: any later version. 11: 12: GNU Classpath is distributed in the hope that it will be useful, but 13: WITHOUT ANY WARRANTY; without even the implied warranty of 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15: General Public License for more details. 16: 17: You should have received a copy of the GNU General Public License 18: along with GNU Classpath; see the file COPYING. If not, write to the 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20: 02110-1301 USA. 21: 22: Linking this library statically or dynamically with other modules is 23: making a combined work based on this library. Thus, the terms and 24: conditions of the GNU General Public License cover the whole 25: combination. 26: 27: As a special exception, the copyright holders of this library give you 28: permission to link this library with independent modules to produce an 29: executable, regardless of the license terms of these independent 30: modules, and to copy and distribute the resulting executable under 31: terms of your choice, provided that you also meet, for each linked 32: independent module, the terms and conditions of the license of that 33: module. An independent module is a module which is not derived from 34: or based on this library. If you modify this library, you may extend 35: this exception to your version of the library, but you are not 36: obligated to do so. If you do not wish to do so, delete this 37: exception statement from your version. */ 38: 39: 40: package java.net; 41: 42: import gnu.java.lang.CPStringBuilder; 43: 44: import gnu.java.net.loader.FileURLLoader; 45: import gnu.java.net.loader.JarURLLoader; 46: import gnu.java.net.loader.RemoteURLLoader; 47: import gnu.java.net.loader.Resource; 48: import gnu.java.net.loader.URLLoader; 49: import gnu.java.net.loader.URLStreamHandlerCache; 50: 51: import java.io.ByteArrayOutputStream; 52: import java.io.EOFException; 53: import java.io.File; 54: import java.io.FilePermission; 55: import java.io.IOException; 56: import java.io.InputStream; 57: import java.lang.reflect.Constructor; 58: import java.lang.reflect.InvocationTargetException; 59: import java.security.AccessControlContext; 60: import java.security.AccessController; 61: import java.security.CodeSource; 62: import java.security.PermissionCollection; 63: import java.security.PrivilegedAction; 64: import java.security.SecureClassLoader; 65: import java.security.cert.Certificate; 66: import java.util.ArrayList; 67: import java.util.Enumeration; 68: import java.util.Vector; 69: import java.util.jar.Attributes; 70: import java.util.jar.Manifest; 71: 72: 73: /** 74: * A secure class loader that can load classes and resources from 75: * multiple locations. Given an array of <code>URL</code>s this class 76: * loader will retrieve classes and resources by fetching them from 77: * possible remote locations. Each <code>URL</code> is searched in 78: * order in which it was added. If the file portion of the 79: * <code>URL</code> ends with a '/' character then it is interpreted 80: * as a base directory, otherwise it is interpreted as a jar file from 81: * which the classes/resources are resolved. 82: * 83: * <p>New instances can be created by two static 84: * <code>newInstance()</code> methods or by three public 85: * contructors. Both ways give the option to supply an initial array 86: * of <code>URL</code>s and (optionally) a parent classloader (that is 87: * different from the standard system class loader).</p> 88: * 89: * <p>Normally creating a <code>URLClassLoader</code> throws a 90: * <code>SecurityException</code> if a <code>SecurityManager</code> is 91: * installed and the <code>checkCreateClassLoader()</code> method does 92: * not return true. But the <code>newInstance()</code> methods may be 93: * used by any code as long as it has permission to acces the given 94: * <code>URL</code>s. <code>URLClassLoaders</code> created by the 95: * <code>newInstance()</code> methods also explicitly call the 96: * <code>checkPackageAccess()</code> method of 97: * <code>SecurityManager</code> if one is installed before trying to 98: * load a class. Note that only subclasses of 99: * <code>URLClassLoader</code> can add new URLs after the 100: * URLClassLoader had been created. But it is always possible to get 101: * an array of all URLs that the class loader uses to resolve classes 102: * and resources by way of the <code>getURLs()</code> method.</p> 103: * 104: * <p>Open issues: 105: * <ul> 106: * 107: * <li>Should the URLClassLoader actually add the locations found in 108: * the manifest or is this the responsibility of some other 109: * loader/(sub)class? (see <a 110: * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html"> 111: * Extension Mechanism Architecture - Bundles Extensions</a>)</li> 112: * 113: * <li>How does <code>definePackage()</code> and sealing work 114: * precisely?</li> 115: * 116: * <li>We save and use the security context (when a created by 117: * <code>newInstance()</code> but do we have to use it in more 118: * places?</li> 119: * 120: * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li> 121: * 122: * </ul> 123: * </p> 124: * 125: * @since 1.2 126: * 127: * @author Mark Wielaard (mark@klomp.org) 128: * @author Wu Gansha (gansha.wu@intel.com) 129: */ 130: public class URLClassLoader extends SecureClassLoader 131: { 132: // Class Variables 133: 134: /** 135: * A cache to store mappings between handler factory and its 136: * private protocol handler cache (also a HashMap), so we can avoid 137: * creating handlers each time the same protocol comes. 138: */ 139: private static URLStreamHandlerCache factoryCache 140: = new URLStreamHandlerCache(); 141: 142: /** 143: * The prefix for URL loaders. 144: */ 145: private static final String URL_LOADER_PREFIX = "gnu.java.net.loader.Load_"; 146: 147: // Instance variables 148: 149: /** Locations to load classes from */ 150: private final Vector<URL> urls = new Vector<URL>(); 151: 152: /** 153: * Store pre-parsed information for each url into this vector: each 154: * element is a URL loader. A jar file has its own class-path 155: * attribute which adds to the URLs that will be searched, but this 156: * does not add to the list of urls. 157: */ 158: private final Vector<URLLoader> urlinfos = new Vector<URLLoader>(); 159: 160: /** Factory used to get the protocol handlers of the URLs */ 161: private final URLStreamHandlerFactory factory; 162: 163: /** 164: * The security context when created from <code>newInstance()</code> 165: * or null when created through a normal constructor or when no 166: * <code>SecurityManager</code> was installed. 167: */ 168: private final AccessControlContext securityContext; 169: 170: // Helper classes 171: 172: /** 173: * Creates a URLClassLoader that gets classes from the supplied URLs. 174: * To determine if this classloader may be created the constructor of 175: * the super class (<code>SecureClassLoader</code>) is called first, which 176: * can throw a SecurityException. Then the supplied URLs are added 177: * in the order given to the URLClassLoader which uses these URLs to 178: * load classes and resources (after using the default parent ClassLoader). 179: * 180: * @param urls Locations that should be searched by this ClassLoader when 181: * resolving Classes or Resources. 182: * @exception SecurityException if the SecurityManager disallows the 183: * creation of a ClassLoader. 184: * @see SecureClassLoader 185: */ 186: public URLClassLoader(URL[] urls) throws SecurityException 187: { 188: super(); 189: this.factory = null; 190: this.securityContext = null; 191: addURLs(urls); 192: } 193: 194: /** 195: * Creates a <code>URLClassLoader</code> that gets classes from the supplied 196: * <code>URL</code>s. 197: * To determine if this classloader may be created the constructor of 198: * the super class (<code>SecureClassLoader</code>) is called first, which 199: * can throw a SecurityException. Then the supplied URLs are added 200: * in the order given to the URLClassLoader which uses these URLs to 201: * load classes and resources (after using the supplied parent ClassLoader). 202: * @param urls Locations that should be searched by this ClassLoader when 203: * resolving Classes or Resources. 204: * @param parent The parent class loader used before trying this class 205: * loader. 206: * @exception SecurityException if the SecurityManager disallows the 207: * creation of a ClassLoader. 208: * @exception SecurityException 209: * @see SecureClassLoader 210: */ 211: public URLClassLoader(URL[] urls, ClassLoader parent) 212: throws SecurityException 213: { 214: super(parent); 215: this.factory = null; 216: this.securityContext = null; 217: addURLs(urls); 218: } 219: 220: // Package-private to avoid a trampoline constructor. 221: /** 222: * Package-private constructor used by the static 223: * <code>newInstance(URL[])</code> method. Creates an 224: * <code>URLClassLoader</code> with the given parent but without any 225: * <code>URL</code>s yet. This is used to bypass the normal security 226: * check for creating classloaders, but remembers the security 227: * context which will be used when defining classes. The 228: * <code>URL</code>s to load from must be added by the 229: * <code>newInstance()</code> method in the security context of the 230: * caller. 231: * 232: * @param securityContext the security context of the unprivileged code. 233: */ 234: URLClassLoader(ClassLoader parent, AccessControlContext securityContext) 235: { 236: super(parent); 237: this.factory = null; 238: this.securityContext = securityContext; 239: } 240: 241: /** 242: * Creates a URLClassLoader that gets classes from the supplied URLs. 243: * To determine if this classloader may be created the constructor of 244: * the super class (<CODE>SecureClassLoader</CODE>) is called first, which 245: * can throw a SecurityException. Then the supplied URLs are added 246: * in the order given to the URLClassLoader which uses these URLs to 247: * load classes and resources (after using the supplied parent ClassLoader). 248: * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the 249: * protocol handlers of the supplied URLs. 250: * @param urls Locations that should be searched by this ClassLoader when 251: * resolving Classes or Resources. 252: * @param parent The parent class loader used before trying this class 253: * loader. 254: * @param factory Used to get the protocol handler for the URLs. 255: * @exception SecurityException if the SecurityManager disallows the 256: * creation of a ClassLoader. 257: * @exception SecurityException 258: * @see SecureClassLoader 259: */ 260: public URLClassLoader(URL[] urls, ClassLoader parent, 261: URLStreamHandlerFactory factory) 262: throws SecurityException 263: { 264: super(parent); 265: this.securityContext = null; 266: this.factory = factory; 267: // If this factory is not yet in factoryCache, add it. 268: factoryCache.add(factory); 269: addURLs(urls); 270: } 271: 272: // Methods 273: 274: /** 275: * Adds a new location to the end of the internal URL store. 276: * @param newUrl the location to add 277: */ 278: protected void addURL(URL newUrl) 279: { 280: urls.add(newUrl); 281: addURLImpl(newUrl); 282: } 283: 284: private void addURLImpl(URL newUrl) 285: { 286: synchronized (this) 287: { 288: if (newUrl == null) 289: return; // Silently ignore... 290: 291: // Reset the toString() value. 292: thisString = null; 293: 294: // Create a loader for this URL. 295: URLLoader loader = null; 296: String file = newUrl.getFile(); 297: String protocol = newUrl.getProtocol(); 298: 299: // If we have a file: URL, we want to make it absolute 300: // here, before we decide whether it is really a jar. 301: URL absoluteURL; 302: if ("file".equals (protocol)) 303: { 304: File dir = new File(file); 305: try 306: { 307: absoluteURL = dir.getCanonicalFile().toURL(); 308: } 309: catch (IOException ignore) 310: { 311: try 312: { 313: absoluteURL = dir.getAbsoluteFile().toURL(); 314: } 315: catch (MalformedURLException _) 316: { 317: // This really should not happen. 318: absoluteURL = newUrl; 319: } 320: } 321: } 322: else 323: { 324: // This doesn't hurt, and it simplifies the logic a 325: // little. 326: absoluteURL = newUrl; 327: } 328: 329: // First see if we can find a handler with the correct name. 330: try 331: { 332: Class<?> handler = Class.forName(URL_LOADER_PREFIX + protocol); 333: Class<?>[] argTypes = new Class<?>[] { URLClassLoader.class, 334: URLStreamHandlerCache.class, 335: URLStreamHandlerFactory.class, 336: URL.class, 337: URL.class }; 338: Constructor k = handler.getDeclaredConstructor(argTypes); 339: loader 340: = (URLLoader) k.newInstance(new Object[] { this, 341: factoryCache, 342: factory, 343: newUrl, 344: absoluteURL }); 345: } 346: catch (ClassNotFoundException ignore) 347: { 348: // Fall through. 349: } 350: catch (NoSuchMethodException nsme) 351: { 352: // Programming error in the class library. 353: InternalError vme 354: = new InternalError("couldn't find URLLoader constructor"); 355: vme.initCause(nsme); 356: throw vme; 357: } 358: catch (InstantiationException inste) 359: { 360: // Programming error in the class library. 361: InternalError vme 362: = new InternalError("couldn't instantiate URLLoader"); 363: vme.initCause(inste); 364: throw vme; 365: } 366: catch (InvocationTargetException ite) 367: { 368: // Programming error in the class library. 369: InternalError vme 370: = new InternalError("error instantiating URLLoader"); 371: vme.initCause(ite); 372: throw vme; 373: } 374: catch (IllegalAccessException illae) 375: { 376: // Programming error in the class library. 377: InternalError vme 378: = new InternalError("invalid access to URLLoader"); 379: vme.initCause(illae); 380: throw vme; 381: } 382: 383: if (loader == null) 384: { 385: // If it is not a directory, use the jar loader. 386: if (! (file.endsWith("/") || file.endsWith(File.separator))) 387: loader = new JarURLLoader(this, factoryCache, factory, 388: newUrl, absoluteURL); 389: else if ("file".equals(protocol)) 390: loader = new FileURLLoader(this, factoryCache, factory, 391: newUrl, absoluteURL); 392: else 393: loader = new RemoteURLLoader(this, factoryCache, factory, 394: newUrl); 395: } 396: 397: urlinfos.add(loader); 398: ArrayList<URLLoader> extra = loader.getClassPath(); 399: if (extra != null) 400: urlinfos.addAll(extra); 401: } 402: } 403: 404: /** 405: * Adds an array of new locations to the end of the internal URL 406: * store. Called from the the constructors. Should not call to the 407: * protected addURL() method since that can be overridden and 408: * subclasses are not yet in a good state at this point. 409: * jboss 4.0.3 for example depends on this. 410: * 411: * @param newUrls the locations to add 412: */ 413: private void addURLs(URL[] newUrls) 414: { 415: for (int i = 0; i < newUrls.length; i++) 416: { 417: urls.add(newUrls[i]); 418: addURLImpl(newUrls[i]); 419: } 420: } 421: 422: /** 423: * Look in both Attributes for a given value. The first Attributes 424: * object, if not null, has precedence. 425: */ 426: private String getAttributeValue(Attributes.Name name, Attributes first, 427: Attributes second) 428: { 429: String result = null; 430: if (first != null) 431: result = first.getValue(name); 432: if (result == null) 433: result = second.getValue(name); 434: return result; 435: } 436: 437: /** 438: * Defines a Package based on the given name and the supplied manifest 439: * information. The manifest indicates the title, version and 440: * vendor information of the specification and implementation and whether the 441: * package is sealed. If the Manifest indicates that the package is sealed 442: * then the Package will be sealed with respect to the supplied URL. 443: * 444: * @param name The name of the package 445: * @param manifest The manifest describing the specification, 446: * implementation and sealing details of the package 447: * @param url the code source url to seal the package 448: * @return the defined Package 449: * @throws IllegalArgumentException If this package name already exists 450: * in this class loader 451: */ 452: protected Package definePackage(String name, Manifest manifest, URL url) 453: throws IllegalArgumentException 454: { 455: // Compute the name of the package as it may appear in the 456: // Manifest. 457: CPStringBuilder xform = new CPStringBuilder(name); 458: for (int i = xform.length () - 1; i >= 0; --i) 459: if (xform.charAt(i) == '.') 460: xform.setCharAt(i, '/'); 461: xform.append('/'); 462: String xformName = xform.toString(); 463: 464: Attributes entryAttr = manifest.getAttributes(xformName); 465: Attributes attr = manifest.getMainAttributes(); 466: 467: String specTitle 468: = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE, 469: entryAttr, attr); 470: String specVersion 471: = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION, 472: entryAttr, attr); 473: String specVendor 474: = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR, 475: entryAttr, attr); 476: String implTitle 477: = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE, 478: entryAttr, attr); 479: String implVersion 480: = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION, 481: entryAttr, attr); 482: String implVendor 483: = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR, 484: entryAttr, attr); 485: 486: // Look if the Manifest indicates that this package is sealed 487: // XXX - most likely not completely correct! 488: // Shouldn't we also check the sealed attribute of the complete jar? 489: // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled 490: // But how do we get that jar manifest here? 491: String sealed = attr.getValue(Attributes.Name.SEALED); 492: if ("false".equals(sealed)) 493: // make sure that the URL is null so the package is not sealed 494: url = null; 495: 496: return definePackage(name, 497: specTitle, specVendor, specVersion, 498: implTitle, implVendor, implVersion, 499: url); 500: } 501: 502: /** 503: * Finds (the first) class by name from one of the locations. The locations 504: * are searched in the order they were added to the URLClassLoader. 505: * 506: * @param className the classname to find 507: * @exception ClassNotFoundException when the class could not be found or 508: * loaded 509: * @return a Class object representing the found class 510: */ 511: protected Class<?> findClass(final String className) 512: throws ClassNotFoundException 513: { 514: // Just try to find the resource by the (almost) same name 515: String resourceName = className.replace('.', '/') + ".class"; 516: int max = urlinfos.size(); 517: Resource resource = null; 518: for (int i = 0; i < max && resource == null; i++) 519: { 520: URLLoader loader = (URLLoader)urlinfos.elementAt(i); 521: if (loader == null) 522: continue; 523: 524: Class k = loader.getClass(className); 525: if (k != null) 526: return k; 527: 528: resource = loader.getResource(resourceName); 529: } 530: if (resource == null) 531: throw new ClassNotFoundException(className + " not found in " + this); 532: 533: // Try to read the class data, create the CodeSource, Package and 534: // construct the class (and watch out for those nasty IOExceptions) 535: try 536: { 537: byte[] data; 538: InputStream in = resource.getInputStream(); 539: try 540: { 541: int length = resource.getLength(); 542: if (length != -1) 543: { 544: // We know the length of the data. 545: // Just try to read it in all at once 546: data = new byte[length]; 547: int pos = 0; 548: while (length - pos > 0) 549: { 550: int len = in.read(data, pos, length - pos); 551: if (len == -1) 552: throw new EOFException("Not enough data reading from: " 553: + in); 554: pos += len; 555: } 556: } 557: else 558: { 559: // We don't know the data length. 560: // Have to read it in chunks. 561: ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 562: byte[] b = new byte[4096]; 563: int l = 0; 564: while (l != -1) 565: { 566: l = in.read(b); 567: if (l != -1) 568: out.write(b, 0, l); 569: } 570: data = out.toByteArray(); 571: } 572: } 573: finally 574: { 575: in.close(); 576: } 577: final byte[] classData = data; 578: 579: // Now get the CodeSource 580: final CodeSource source = resource.getCodeSource(); 581: 582: // Find out package name 583: String packageName = null; 584: int lastDot = className.lastIndexOf('.'); 585: if (lastDot != -1) 586: packageName = className.substring(0, lastDot); 587: 588: if (packageName != null && getPackage(packageName) == null) 589: { 590: // define the package 591: Manifest manifest = resource.getLoader().getManifest(); 592: if (manifest == null) 593: definePackage(packageName, null, null, null, null, null, null, 594: null); 595: else 596: definePackage(packageName, manifest, 597: resource.getLoader().getBaseURL()); 598: } 599: 600: // And finally construct the class! 601: SecurityManager sm = System.getSecurityManager(); 602: Class result = null; 603: if (sm != null && securityContext != null) 604: { 605: result = AccessController.doPrivileged 606: (new PrivilegedAction<Class>() 607: { 608: public Class run() 609: { 610: return defineClass(className, classData, 611: 0, classData.length, 612: source); 613: } 614: }, securityContext); 615: } 616: else 617: result = defineClass(className, classData, 0, classData.length, source); 618: 619: // Avoid NullPointerExceptions. 620: Certificate[] resourceCertificates = resource.getCertificates(); 621: if(resourceCertificates != null) 622: super.setSigners(result, resourceCertificates); 623: 624: return result; 625: } 626: catch (IOException ioe) 627: { 628: throw new ClassNotFoundException(className + " not found in " + this, ioe); 629: } 630: } 631: 632: // Cached String representation of this URLClassLoader 633: private String thisString; 634: 635: /** 636: * Returns a String representation of this URLClassLoader giving the 637: * actual Class name, the URLs that are searched and the parent 638: * ClassLoader. 639: */ 640: public String toString() 641: { 642: synchronized (this) 643: { 644: if (thisString == null) 645: { 646: CPStringBuilder sb = new CPStringBuilder(); 647: sb.append(this.getClass().getName()); 648: sb.append("{urls=[" ); 649: URL[] thisURLs = getURLs(); 650: for (int i = 0; i < thisURLs.length; i++) 651: { 652: sb.append(thisURLs[i]); 653: if (i < thisURLs.length - 1) 654: sb.append(','); 655: } 656: sb.append(']'); 657: sb.append(", parent="); 658: sb.append(getParent()); 659: sb.append('}'); 660: thisString = sb.toString(); 661: } 662: return thisString; 663: } 664: } 665: 666: /** 667: * Finds the first occurrence of a resource that can be found. The locations 668: * are searched in the order they were added to the URLClassLoader. 669: * 670: * @param resourceName the resource name to look for 671: * @return the URLResource for the resource if found, null otherwise 672: */ 673: private Resource findURLResource(String resourceName) 674: { 675: int max = urlinfos.size(); 676: for (int i = 0; i < max; i++) 677: { 678: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 679: if (loader == null) 680: continue; 681: 682: Resource resource = loader.getResource(resourceName); 683: if (resource != null) 684: return resource; 685: } 686: return null; 687: } 688: 689: /** 690: * Finds the first occurrence of a resource that can be found. 691: * 692: * @param resourceName the resource name to look for 693: * @return the URL if found, null otherwise 694: */ 695: public URL findResource(String resourceName) 696: { 697: Resource resource = findURLResource(resourceName); 698: if (resource != null) 699: return resource.getURL(); 700: 701: // Resource not found 702: return null; 703: } 704: 705: /** 706: * Finds all the resources with a particular name from all the locations. 707: * 708: * @param resourceName the name of the resource to lookup 709: * @return a (possible empty) enumeration of URLs where the resource can be 710: * found 711: * @exception IOException when an error occurs accessing one of the 712: * locations 713: */ 714: public Enumeration<URL> findResources(String resourceName) 715: throws IOException 716: { 717: Vector<URL> resources = new Vector<URL>(); 718: int max = urlinfos.size(); 719: for (int i = 0; i < max; i++) 720: { 721: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 722: Resource resource = loader.getResource(resourceName); 723: if (resource != null) 724: resources.add(resource.getURL()); 725: } 726: return resources.elements(); 727: } 728: 729: /** 730: * Returns the permissions needed to access a particular code 731: * source. These permissions includes those returned by 732: * <code>SecureClassLoader.getPermissions()</code> and the actual 733: * permissions to access the objects referenced by the URL of the 734: * code source. The extra permissions added depend on the protocol 735: * and file portion of the URL in the code source. If the URL has 736: * the "file" protocol ends with a '/' character then it must be a 737: * directory and a file Permission to read everything in that 738: * directory and all subdirectories is added. If the URL had the 739: * "file" protocol and doesn't end with a '/' character then it must 740: * be a normal file and a file permission to read that file is 741: * added. If the <code>URL</code> has any other protocol then a 742: * socket permission to connect and accept connections from the host 743: * portion of the URL is added. 744: * 745: * @param source The codesource that needs the permissions to be accessed 746: * @return the collection of permissions needed to access the code resource 747: * @see java.security.SecureClassLoader#getPermissions(CodeSource) 748: */ 749: protected PermissionCollection getPermissions(CodeSource source) 750: { 751: // XXX - This implementation does exactly as the Javadoc describes. 752: // But maybe we should/could use URLConnection.getPermissions()? 753: // First get the permissions that would normally be granted 754: PermissionCollection permissions = super.getPermissions(source); 755: 756: // Now add any extra permissions depending on the URL location. 757: URL url = source.getLocation(); 758: String protocol = url.getProtocol(); 759: if (protocol.equals("file")) 760: { 761: String file = url.getFile(); 762: 763: // If the file end in / it must be an directory. 764: if (file.endsWith("/") || file.endsWith(File.separator)) 765: { 766: // Grant permission to read everything in that directory and 767: // all subdirectories. 768: permissions.add(new FilePermission(file + "-", "read")); 769: } 770: else 771: { 772: // It is a 'normal' file. 773: // Grant permission to access that file. 774: permissions.add(new FilePermission(file, "read")); 775: } 776: } 777: else 778: { 779: // Grant permission to connect to and accept connections from host 780: String host = url.getHost(); 781: if (host != null) 782: permissions.add(new SocketPermission(host, "connect,accept")); 783: } 784: 785: return permissions; 786: } 787: 788: /** 789: * Returns all the locations that this class loader currently uses the 790: * resolve classes and resource. This includes both the initially supplied 791: * URLs as any URLs added later by the loader. 792: * @return All the currently used URLs 793: */ 794: public URL[] getURLs() 795: { 796: return (URL[]) urls.toArray(new URL[urls.size()]); 797: } 798: 799: /** 800: * Creates a new instance of a <code>URLClassLoader</code> that gets 801: * classes from the supplied <code>URL</code>s. This class loader 802: * will have as parent the standard system class loader. 803: * 804: * @param urls the initial URLs used to resolve classes and 805: * resources 806: * 807: * @return the class loader 808: * 809: * @exception SecurityException when the calling code does not have 810: * permission to access the given <code>URL</code>s 811: */ 812: public static URLClassLoader newInstance(URL[] urls) 813: throws SecurityException 814: { 815: return newInstance(urls, null); 816: } 817: 818: /** 819: * Creates a new instance of a <code>URLClassLoader</code> that gets 820: * classes from the supplied <code>URL</code>s and with the supplied 821: * loader as parent class loader. 822: * 823: * @param urls the initial URLs used to resolve classes and 824: * resources 825: * @param parent the parent class loader 826: * 827: * @return the class loader 828: * 829: * @exception SecurityException when the calling code does not have 830: * permission to access the given <code>URL</code>s 831: */ 832: public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent) 833: throws SecurityException 834: { 835: SecurityManager sm = System.getSecurityManager(); 836: if (sm == null) 837: return new URLClassLoader(urls, parent); 838: else 839: { 840: final Object securityContext = sm.getSecurityContext(); 841: 842: // XXX - What to do with anything else then an AccessControlContext? 843: if (! (securityContext instanceof AccessControlContext)) 844: throw new SecurityException("securityContext must be AccessControlContext: " 845: + securityContext); 846: 847: URLClassLoader loader = 848: AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() 849: { 850: public URLClassLoader run() 851: { 852: return new URLClassLoader(parent, 853: (AccessControlContext) securityContext); 854: } 855: }); 856: loader.addURLs(urls); 857: return loader; 858: } 859: } 860: }