GNU Classpath (0.92) | |
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 urls = new Vector(); 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 urlinfos = new Vector(); 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: addURLs(urls); 266: 267: // If this factory is still not in factoryCache, add it. 268: factoryCache.add(factory); 269: } 270: 271: // Methods 272: 273: /** 274: * Adds a new location to the end of the internal URL store. 275: * @param newUrl the location to add 276: */ 277: protected void addURL(URL newUrl) 278: { 279: urls.add(newUrl); 280: addURLImpl(newUrl); 281: } 282: 283: private void addURLImpl(URL newUrl) 284: { 285: synchronized (this) 286: { 287: if (newUrl == null) 288: return; // Silently ignore... 289: 290: // Reset the toString() value. 291: thisString = null; 292: 293: // Create a loader for this URL. 294: URLLoader loader = null; 295: String file = newUrl.getFile(); 296: String protocol = newUrl.getProtocol(); 297: 298: // If we have a file: URL, we want to make it absolute 299: // here, before we decide whether it is really a jar. 300: URL absoluteURL; 301: if ("file".equals (protocol)) 302: { 303: File dir = new File(file); 304: URL absUrl; 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 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: StringBuffer xform = new StringBuffer(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 = (Class)AccessController.doPrivileged 606: (new PrivilegedAction() 607: { 608: public Object 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: ClassNotFoundException cnfe; 629: cnfe = new ClassNotFoundException(className + " not found in " + this); 630: cnfe.initCause(ioe); 631: throw cnfe; 632: } 633: } 634: 635: // Cached String representation of this URLClassLoader 636: private String thisString; 637: 638: /** 639: * Returns a String representation of this URLClassLoader giving the 640: * actual Class name, the URLs that are searched and the parent 641: * ClassLoader. 642: */ 643: public String toString() 644: { 645: synchronized (this) 646: { 647: if (thisString == null) 648: { 649: StringBuffer sb = new StringBuffer(); 650: sb.append(this.getClass().getName()); 651: sb.append("{urls=[" ); 652: URL[] thisURLs = getURLs(); 653: for (int i = 0; i < thisURLs.length; i++) 654: { 655: sb.append(thisURLs[i]); 656: if (i < thisURLs.length - 1) 657: sb.append(','); 658: } 659: sb.append(']'); 660: sb.append(", parent="); 661: sb.append(getParent()); 662: sb.append('}'); 663: thisString = sb.toString(); 664: } 665: return thisString; 666: } 667: } 668: 669: /** 670: * Finds the first occurrence of a resource that can be found. The locations 671: * are searched in the order they were added to the URLClassLoader. 672: * 673: * @param resourceName the resource name to look for 674: * @return the URLResource for the resource if found, null otherwise 675: */ 676: private Resource findURLResource(String resourceName) 677: { 678: int max = urlinfos.size(); 679: for (int i = 0; i < max; i++) 680: { 681: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 682: if (loader == null) 683: continue; 684: 685: Resource resource = loader.getResource(resourceName); 686: if (resource != null) 687: return resource; 688: } 689: return null; 690: } 691: 692: /** 693: * Finds the first occurrence of a resource that can be found. 694: * 695: * @param resourceName the resource name to look for 696: * @return the URL if found, null otherwise 697: */ 698: public URL findResource(String resourceName) 699: { 700: Resource resource = findURLResource(resourceName); 701: if (resource != null) 702: return resource.getURL(); 703: 704: // Resource not found 705: return null; 706: } 707: 708: /** 709: * Finds all the resources with a particular name from all the locations. 710: * 711: * @param resourceName the name of the resource to lookup 712: * @return a (possible empty) enumeration of URLs where the resource can be 713: * found 714: * @exception IOException when an error occurs accessing one of the 715: * locations 716: */ 717: public Enumeration findResources(String resourceName) 718: throws IOException 719: { 720: Vector resources = new Vector(); 721: int max = urlinfos.size(); 722: for (int i = 0; i < max; i++) 723: { 724: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 725: Resource resource = loader.getResource(resourceName); 726: if (resource != null) 727: resources.add(resource.getURL()); 728: } 729: return resources.elements(); 730: } 731: 732: /** 733: * Returns the permissions needed to access a particular code 734: * source. These permissions includes those returned by 735: * <code>SecureClassLoader.getPermissions()</code> and the actual 736: * permissions to access the objects referenced by the URL of the 737: * code source. The extra permissions added depend on the protocol 738: * and file portion of the URL in the code source. If the URL has 739: * the "file" protocol ends with a '/' character then it must be a 740: * directory and a file Permission to read everything in that 741: * directory and all subdirectories is added. If the URL had the 742: * "file" protocol and doesn't end with a '/' character then it must 743: * be a normal file and a file permission to read that file is 744: * added. If the <code>URL</code> has any other protocol then a 745: * socket permission to connect and accept connections from the host 746: * portion of the URL is added. 747: * 748: * @param source The codesource that needs the permissions to be accessed 749: * @return the collection of permissions needed to access the code resource 750: * @see java.security.SecureClassLoader#getPermissions(CodeSource) 751: */ 752: protected PermissionCollection getPermissions(CodeSource source) 753: { 754: // XXX - This implementation does exactly as the Javadoc describes. 755: // But maybe we should/could use URLConnection.getPermissions()? 756: // First get the permissions that would normally be granted 757: PermissionCollection permissions = super.getPermissions(source); 758: 759: // Now add any extra permissions depending on the URL location. 760: URL url = source.getLocation(); 761: String protocol = url.getProtocol(); 762: if (protocol.equals("file")) 763: { 764: String file = url.getFile(); 765: 766: // If the file end in / it must be an directory. 767: if (file.endsWith("/") || file.endsWith(File.separator)) 768: { 769: // Grant permission to read everything in that directory and 770: // all subdirectories. 771: permissions.add(new FilePermission(file + "-", "read")); 772: } 773: else 774: { 775: // It is a 'normal' file. 776: // Grant permission to access that file. 777: permissions.add(new FilePermission(file, "read")); 778: } 779: } 780: else 781: { 782: // Grant permission to connect to and accept connections from host 783: String host = url.getHost(); 784: if (host != null) 785: permissions.add(new SocketPermission(host, "connect,accept")); 786: } 787: 788: return permissions; 789: } 790: 791: /** 792: * Returns all the locations that this class loader currently uses the 793: * resolve classes and resource. This includes both the initially supplied 794: * URLs as any URLs added later by the loader. 795: * @return All the currently used URLs 796: */ 797: public URL[] getURLs() 798: { 799: return (URL[]) urls.toArray(new URL[urls.size()]); 800: } 801: 802: /** 803: * Creates a new instance of a <code>URLClassLoader</code> that gets 804: * classes from the supplied <code>URL</code>s. This class loader 805: * will have as parent the standard system class loader. 806: * 807: * @param urls the initial URLs used to resolve classes and 808: * resources 809: * 810: * @return the class loader 811: * 812: * @exception SecurityException when the calling code does not have 813: * permission to access the given <code>URL</code>s 814: */ 815: public static URLClassLoader newInstance(URL[] urls) 816: throws SecurityException 817: { 818: return newInstance(urls, null); 819: } 820: 821: /** 822: * Creates a new instance of a <code>URLClassLoader</code> that gets 823: * classes from the supplied <code>URL</code>s and with the supplied 824: * loader as parent class loader. 825: * 826: * @param urls the initial URLs used to resolve classes and 827: * resources 828: * @param parent the parent class loader 829: * 830: * @return the class loader 831: * 832: * @exception SecurityException when the calling code does not have 833: * permission to access the given <code>URL</code>s 834: */ 835: public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent) 836: throws SecurityException 837: { 838: SecurityManager sm = System.getSecurityManager(); 839: if (sm == null) 840: return new URLClassLoader(urls, parent); 841: else 842: { 843: final Object securityContext = sm.getSecurityContext(); 844: 845: // XXX - What to do with anything else then an AccessControlContext? 846: if (! (securityContext instanceof AccessControlContext)) 847: throw new SecurityException("securityContext must be AccessControlContext: " 848: + securityContext); 849: 850: URLClassLoader loader = 851: (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() 852: { 853: public Object run() 854: { 855: return new URLClassLoader(parent, 856: (AccessControlContext) securityContext); 857: } 858: }); 859: loader.addURLs(urls); 860: return loader; 861: } 862: } 863: }
GNU Classpath (0.92) |