GNU Classpath (0.95) | |
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: 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: try 305: { 306: absoluteURL = dir.getCanonicalFile().toURL(); 307: } 308: catch (IOException ignore) 309: { 310: try 311: { 312: absoluteURL = dir.getAbsoluteFile().toURL(); 313: } 314: catch (MalformedURLException _) 315: { 316: // This really should not happen. 317: absoluteURL = newUrl; 318: } 319: } 320: } 321: else 322: { 323: // This doesn't hurt, and it simplifies the logic a 324: // little. 325: absoluteURL = newUrl; 326: } 327: 328: // First see if we can find a handler with the correct name. 329: try 330: { 331: Class<?> handler = Class.forName(URL_LOADER_PREFIX + protocol); 332: Class<?>[] argTypes = new Class<?>[] { URLClassLoader.class, 333: URLStreamHandlerCache.class, 334: URLStreamHandlerFactory.class, 335: URL.class, 336: URL.class }; 337: Constructor k = handler.getDeclaredConstructor(argTypes); 338: loader 339: = (URLLoader) k.newInstance(new Object[] { this, 340: factoryCache, 341: factory, 342: newUrl, 343: absoluteURL }); 344: } 345: catch (ClassNotFoundException ignore) 346: { 347: // Fall through. 348: } 349: catch (NoSuchMethodException nsme) 350: { 351: // Programming error in the class library. 352: InternalError vme 353: = new InternalError("couldn't find URLLoader constructor"); 354: vme.initCause(nsme); 355: throw vme; 356: } 357: catch (InstantiationException inste) 358: { 359: // Programming error in the class library. 360: InternalError vme 361: = new InternalError("couldn't instantiate URLLoader"); 362: vme.initCause(inste); 363: throw vme; 364: } 365: catch (InvocationTargetException ite) 366: { 367: // Programming error in the class library. 368: InternalError vme 369: = new InternalError("error instantiating URLLoader"); 370: vme.initCause(ite); 371: throw vme; 372: } 373: catch (IllegalAccessException illae) 374: { 375: // Programming error in the class library. 376: InternalError vme 377: = new InternalError("invalid access to URLLoader"); 378: vme.initCause(illae); 379: throw vme; 380: } 381: 382: if (loader == null) 383: { 384: // If it is not a directory, use the jar loader. 385: if (! (file.endsWith("/") || file.endsWith(File.separator))) 386: loader = new JarURLLoader(this, factoryCache, factory, 387: newUrl, absoluteURL); 388: else if ("file".equals(protocol)) 389: loader = new FileURLLoader(this, factoryCache, factory, 390: newUrl, absoluteURL); 391: else 392: loader = new RemoteURLLoader(this, factoryCache, factory, 393: newUrl); 394: } 395: 396: urlinfos.add(loader); 397: ArrayList<URLLoader> extra = loader.getClassPath(); 398: if (extra != null) 399: urlinfos.addAll(extra); 400: } 401: } 402: 403: /** 404: * Adds an array of new locations to the end of the internal URL 405: * store. Called from the the constructors. Should not call to the 406: * protected addURL() method since that can be overridden and 407: * subclasses are not yet in a good state at this point. 408: * jboss 4.0.3 for example depends on this. 409: * 410: * @param newUrls the locations to add 411: */ 412: private void addURLs(URL[] newUrls) 413: { 414: for (int i = 0; i < newUrls.length; i++) 415: { 416: urls.add(newUrls[i]); 417: addURLImpl(newUrls[i]); 418: } 419: } 420: 421: /** 422: * Look in both Attributes for a given value. The first Attributes 423: * object, if not null, has precedence. 424: */ 425: private String getAttributeValue(Attributes.Name name, Attributes first, 426: Attributes second) 427: { 428: String result = null; 429: if (first != null) 430: result = first.getValue(name); 431: if (result == null) 432: result = second.getValue(name); 433: return result; 434: } 435: 436: /** 437: * Defines a Package based on the given name and the supplied manifest 438: * information. The manifest indicates the title, version and 439: * vendor information of the specification and implementation and whether the 440: * package is sealed. If the Manifest indicates that the package is sealed 441: * then the Package will be sealed with respect to the supplied URL. 442: * 443: * @param name The name of the package 444: * @param manifest The manifest describing the specification, 445: * implementation and sealing details of the package 446: * @param url the code source url to seal the package 447: * @return the defined Package 448: * @throws IllegalArgumentException If this package name already exists 449: * in this class loader 450: */ 451: protected Package definePackage(String name, Manifest manifest, URL url) 452: throws IllegalArgumentException 453: { 454: // Compute the name of the package as it may appear in the 455: // Manifest. 456: StringBuffer xform = new StringBuffer(name); 457: for (int i = xform.length () - 1; i >= 0; --i) 458: if (xform.charAt(i) == '.') 459: xform.setCharAt(i, '/'); 460: xform.append('/'); 461: String xformName = xform.toString(); 462: 463: Attributes entryAttr = manifest.getAttributes(xformName); 464: Attributes attr = manifest.getMainAttributes(); 465: 466: String specTitle 467: = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE, 468: entryAttr, attr); 469: String specVersion 470: = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION, 471: entryAttr, attr); 472: String specVendor 473: = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR, 474: entryAttr, attr); 475: String implTitle 476: = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE, 477: entryAttr, attr); 478: String implVersion 479: = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION, 480: entryAttr, attr); 481: String implVendor 482: = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR, 483: entryAttr, attr); 484: 485: // Look if the Manifest indicates that this package is sealed 486: // XXX - most likely not completely correct! 487: // Shouldn't we also check the sealed attribute of the complete jar? 488: // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled 489: // But how do we get that jar manifest here? 490: String sealed = attr.getValue(Attributes.Name.SEALED); 491: if ("false".equals(sealed)) 492: // make sure that the URL is null so the package is not sealed 493: url = null; 494: 495: return definePackage(name, 496: specTitle, specVendor, specVersion, 497: implTitle, implVendor, implVersion, 498: url); 499: } 500: 501: /** 502: * Finds (the first) class by name from one of the locations. The locations 503: * are searched in the order they were added to the URLClassLoader. 504: * 505: * @param className the classname to find 506: * @exception ClassNotFoundException when the class could not be found or 507: * loaded 508: * @return a Class object representing the found class 509: */ 510: protected Class<?> findClass(final String className) 511: throws ClassNotFoundException 512: { 513: // Just try to find the resource by the (almost) same name 514: String resourceName = className.replace('.', '/') + ".class"; 515: int max = urlinfos.size(); 516: Resource resource = null; 517: for (int i = 0; i < max && resource == null; i++) 518: { 519: URLLoader loader = (URLLoader)urlinfos.elementAt(i); 520: if (loader == null) 521: continue; 522: 523: Class k = loader.getClass(className); 524: if (k != null) 525: return k; 526: 527: resource = loader.getResource(resourceName); 528: } 529: if (resource == null) 530: throw new ClassNotFoundException(className + " not found in " + this); 531: 532: // Try to read the class data, create the CodeSource, Package and 533: // construct the class (and watch out for those nasty IOExceptions) 534: try 535: { 536: byte[] data; 537: InputStream in = resource.getInputStream(); 538: try 539: { 540: int length = resource.getLength(); 541: if (length != -1) 542: { 543: // We know the length of the data. 544: // Just try to read it in all at once 545: data = new byte[length]; 546: int pos = 0; 547: while (length - pos > 0) 548: { 549: int len = in.read(data, pos, length - pos); 550: if (len == -1) 551: throw new EOFException("Not enough data reading from: " 552: + in); 553: pos += len; 554: } 555: } 556: else 557: { 558: // We don't know the data length. 559: // Have to read it in chunks. 560: ByteArrayOutputStream out = new ByteArrayOutputStream(4096); 561: byte[] b = new byte[4096]; 562: int l = 0; 563: while (l != -1) 564: { 565: l = in.read(b); 566: if (l != -1) 567: out.write(b, 0, l); 568: } 569: data = out.toByteArray(); 570: } 571: } 572: finally 573: { 574: in.close(); 575: } 576: final byte[] classData = data; 577: 578: // Now get the CodeSource 579: final CodeSource source = resource.getCodeSource(); 580: 581: // Find out package name 582: String packageName = null; 583: int lastDot = className.lastIndexOf('.'); 584: if (lastDot != -1) 585: packageName = className.substring(0, lastDot); 586: 587: if (packageName != null && getPackage(packageName) == null) 588: { 589: // define the package 590: Manifest manifest = resource.getLoader().getManifest(); 591: if (manifest == null) 592: definePackage(packageName, null, null, null, null, null, null, 593: null); 594: else 595: definePackage(packageName, manifest, 596: resource.getLoader().getBaseURL()); 597: } 598: 599: // And finally construct the class! 600: SecurityManager sm = System.getSecurityManager(); 601: Class result = null; 602: if (sm != null && securityContext != null) 603: { 604: result = AccessController.doPrivileged 605: (new PrivilegedAction<Class>() 606: { 607: public Class run() 608: { 609: return defineClass(className, classData, 610: 0, classData.length, 611: source); 612: } 613: }, securityContext); 614: } 615: else 616: result = defineClass(className, classData, 0, classData.length, source); 617: 618: // Avoid NullPointerExceptions. 619: Certificate[] resourceCertificates = resource.getCertificates(); 620: if(resourceCertificates != null) 621: super.setSigners(result, resourceCertificates); 622: 623: return result; 624: } 625: catch (IOException ioe) 626: { 627: ClassNotFoundException cnfe; 628: cnfe = new ClassNotFoundException(className + " not found in " + this); 629: cnfe.initCause(ioe); 630: throw cnfe; 631: } 632: } 633: 634: // Cached String representation of this URLClassLoader 635: private String thisString; 636: 637: /** 638: * Returns a String representation of this URLClassLoader giving the 639: * actual Class name, the URLs that are searched and the parent 640: * ClassLoader. 641: */ 642: public String toString() 643: { 644: synchronized (this) 645: { 646: if (thisString == null) 647: { 648: StringBuffer sb = new StringBuffer(); 649: sb.append(this.getClass().getName()); 650: sb.append("{urls=[" ); 651: URL[] thisURLs = getURLs(); 652: for (int i = 0; i < thisURLs.length; i++) 653: { 654: sb.append(thisURLs[i]); 655: if (i < thisURLs.length - 1) 656: sb.append(','); 657: } 658: sb.append(']'); 659: sb.append(", parent="); 660: sb.append(getParent()); 661: sb.append('}'); 662: thisString = sb.toString(); 663: } 664: return thisString; 665: } 666: } 667: 668: /** 669: * Finds the first occurrence of a resource that can be found. The locations 670: * are searched in the order they were added to the URLClassLoader. 671: * 672: * @param resourceName the resource name to look for 673: * @return the URLResource for the resource if found, null otherwise 674: */ 675: private Resource findURLResource(String resourceName) 676: { 677: int max = urlinfos.size(); 678: for (int i = 0; i < max; i++) 679: { 680: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 681: if (loader == null) 682: continue; 683: 684: Resource resource = loader.getResource(resourceName); 685: if (resource != null) 686: return resource; 687: } 688: return null; 689: } 690: 691: /** 692: * Finds the first occurrence of a resource that can be found. 693: * 694: * @param resourceName the resource name to look for 695: * @return the URL if found, null otherwise 696: */ 697: public URL findResource(String resourceName) 698: { 699: Resource resource = findURLResource(resourceName); 700: if (resource != null) 701: return resource.getURL(); 702: 703: // Resource not found 704: return null; 705: } 706: 707: /** 708: * Finds all the resources with a particular name from all the locations. 709: * 710: * @param resourceName the name of the resource to lookup 711: * @return a (possible empty) enumeration of URLs where the resource can be 712: * found 713: * @exception IOException when an error occurs accessing one of the 714: * locations 715: */ 716: public Enumeration<URL> findResources(String resourceName) 717: throws IOException 718: { 719: Vector<URL> resources = new Vector<URL>(); 720: int max = urlinfos.size(); 721: for (int i = 0; i < max; i++) 722: { 723: URLLoader loader = (URLLoader) urlinfos.elementAt(i); 724: Resource resource = loader.getResource(resourceName); 725: if (resource != null) 726: resources.add(resource.getURL()); 727: } 728: return resources.elements(); 729: } 730: 731: /** 732: * Returns the permissions needed to access a particular code 733: * source. These permissions includes those returned by 734: * <code>SecureClassLoader.getPermissions()</code> and the actual 735: * permissions to access the objects referenced by the URL of the 736: * code source. The extra permissions added depend on the protocol 737: * and file portion of the URL in the code source. If the URL has 738: * the "file" protocol ends with a '/' character then it must be a 739: * directory and a file Permission to read everything in that 740: * directory and all subdirectories is added. If the URL had the 741: * "file" protocol and doesn't end with a '/' character then it must 742: * be a normal file and a file permission to read that file is 743: * added. If the <code>URL</code> has any other protocol then a 744: * socket permission to connect and accept connections from the host 745: * portion of the URL is added. 746: * 747: * @param source The codesource that needs the permissions to be accessed 748: * @return the collection of permissions needed to access the code resource 749: * @see java.security.SecureClassLoader#getPermissions(CodeSource) 750: */ 751: protected PermissionCollection getPermissions(CodeSource source) 752: { 753: // XXX - This implementation does exactly as the Javadoc describes. 754: // But maybe we should/could use URLConnection.getPermissions()? 755: // First get the permissions that would normally be granted 756: PermissionCollection permissions = super.getPermissions(source); 757: 758: // Now add any extra permissions depending on the URL location. 759: URL url = source.getLocation(); 760: String protocol = url.getProtocol(); 761: if (protocol.equals("file")) 762: { 763: String file = url.getFile(); 764: 765: // If the file end in / it must be an directory. 766: if (file.endsWith("/") || file.endsWith(File.separator)) 767: { 768: // Grant permission to read everything in that directory and 769: // all subdirectories. 770: permissions.add(new FilePermission(file + "-", "read")); 771: } 772: else 773: { 774: // It is a 'normal' file. 775: // Grant permission to access that file. 776: permissions.add(new FilePermission(file, "read")); 777: } 778: } 779: else 780: { 781: // Grant permission to connect to and accept connections from host 782: String host = url.getHost(); 783: if (host != null) 784: permissions.add(new SocketPermission(host, "connect,accept")); 785: } 786: 787: return permissions; 788: } 789: 790: /** 791: * Returns all the locations that this class loader currently uses the 792: * resolve classes and resource. This includes both the initially supplied 793: * URLs as any URLs added later by the loader. 794: * @return All the currently used URLs 795: */ 796: public URL[] getURLs() 797: { 798: return (URL[]) urls.toArray(new URL[urls.size()]); 799: } 800: 801: /** 802: * Creates a new instance of a <code>URLClassLoader</code> that gets 803: * classes from the supplied <code>URL</code>s. This class loader 804: * will have as parent the standard system class loader. 805: * 806: * @param urls the initial URLs used to resolve classes and 807: * resources 808: * 809: * @return the class loader 810: * 811: * @exception SecurityException when the calling code does not have 812: * permission to access the given <code>URL</code>s 813: */ 814: public static URLClassLoader newInstance(URL[] urls) 815: throws SecurityException 816: { 817: return newInstance(urls, null); 818: } 819: 820: /** 821: * Creates a new instance of a <code>URLClassLoader</code> that gets 822: * classes from the supplied <code>URL</code>s and with the supplied 823: * loader as parent class loader. 824: * 825: * @param urls the initial URLs used to resolve classes and 826: * resources 827: * @param parent the parent class loader 828: * 829: * @return the class loader 830: * 831: * @exception SecurityException when the calling code does not have 832: * permission to access the given <code>URL</code>s 833: */ 834: public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent) 835: throws SecurityException 836: { 837: SecurityManager sm = System.getSecurityManager(); 838: if (sm == null) 839: return new URLClassLoader(urls, parent); 840: else 841: { 842: final Object securityContext = sm.getSecurityContext(); 843: 844: // XXX - What to do with anything else then an AccessControlContext? 845: if (! (securityContext instanceof AccessControlContext)) 846: throw new SecurityException("securityContext must be AccessControlContext: " 847: + securityContext); 848: 849: URLClassLoader loader = 850: AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() 851: { 852: public URLClassLoader run() 853: { 854: return new URLClassLoader(parent, 855: (AccessControlContext) securityContext); 856: } 857: }); 858: loader.addURLs(urls); 859: return loader; 860: } 861: } 862: }
GNU Classpath (0.95) |