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