Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for java.net.URLClassLoader

 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: }
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /