urlclassloader.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 1,066 行 · 第 1/3 页

JAVA
1,066
字号
  {
    Attributes attr = manifest.getMainAttributes();
    String specTitle =
      attr.getValue(Attributes.Name.SPECIFICATION_TITLE); 
    String specVersion =
      attr.getValue(Attributes.Name.SPECIFICATION_VERSION); 
    String specVendor =
      attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); 
    String implTitle =
      attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); 
    String implVersion =
      attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); 
    String implVendor =
      attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);

    // Look if the Manifest indicates that this package is sealed
    // XXX - most likely not completely correct!
    // Shouldn't we also check the sealed attribute of the complete jar?
    // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled
    // But how do we get that jar manifest here?
    String sealed = attr.getValue(Attributes.Name.SEALED);
    if ("false".equals(sealed))
    {
      // make sure that the URL is null so the package is not sealed
      url = null;
    }

    return definePackage(name, specTitle, specVersion, specVendor,
			 implTitle, implVersion, implVendor, url);
  }

  /**
   * Finds (the first) class by name from one of the locations. The locations
   * are searched in the order they were added to the URLClassLoader.
   *
   * @param className the classname to find
   * @exception ClassNotFoundException when the class could not be found or
   * loaded
   * @return a Class object representing the found class
   */
  protected Class findClass(final String className)
    throws ClassNotFoundException
  {
    // Just try to find the resource by the (almost) same name
    String resourceName = className.replace('.', '/') + ".class";
    Resource resource = findURLResource(resourceName);
    if (resource == null)
      throw new ClassNotFoundException(className + " not found in " + urls);

    // Try to read the class data, create the CodeSource, Package and
    // construct the class (and watch out for those nasty IOExceptions)
    try
      {
	byte [] data;
	InputStream in = resource.getInputStream();
	int length = resource.getLength();
	if (length != -1)
	  {
	    // We know the length of the data.
	    // Just try to read it in all at once
	    data = new byte[length];
	    int pos = 0;
	    while(length - pos > 0)
	      {
		int len = in.read(data, pos, length - pos);
		if (len == -1)
		  throw new EOFException("Not enough data reading from: "
					 + in);
		pos += len;
	      }
	  }
	else
	  {
	    // We don't know the data length.
	    // Have to read it in chunks.
	    ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
	    byte b[] = new byte[4096];
	    int l = 0;
	    while (l != -1)
	      {
		l = in.read(b);
		if (l != -1)
		  out.write(b, 0, l);
	      }
	    data = out.toByteArray();
	  }
	final byte[] classData = data;

	// Now get the CodeSource
	final CodeSource source = resource.getCodeSource();
	
	// Find out package name
	String packageName = null;
	int lastDot = className.lastIndexOf('.');
	if (lastDot != -1)
	  packageName = className.substring(0, lastDot);
	
	if (packageName != null && getPackage(packageName) == null)
	  {
	    // define the package
	    Manifest manifest = resource.loader.getManifest();
	    if (manifest == null)
	      definePackage(packageName,
			    null, null, null, null, null, null, null);
	    else
	      definePackage(packageName, manifest, resource.loader.baseURL);
	  }
	
	// And finally construct the class!
	SecurityManager sm = System.getSecurityManager();
	if (sm != null && securityContext != null)
	  {
	    return (Class)AccessController.doPrivileged
	      (new PrivilegedAction()
		{
		  public Object run()
		  {
		    return defineClass(className, classData,
				       0, classData.length,
				       source);
		  }
		}, securityContext);
	  }
	else
	  return defineClass(className, classData,
			     0, classData.length,
			     source);
      }
    catch (IOException ioe)
      {
	throw new ClassNotFoundException(className, ioe);
      }
  }

  /**
   * Finds the first occurrence of a resource that can be found. The locations
   * are searched in the order they were added to the URLClassLoader.
   *
   * @param resourceName the resource name to look for
   * @return the URLResource for the resource if found, null otherwise
   */
  private Resource findURLResource(String resourceName)
  {
    int max = urls.size();
    for (int i = 0; i < max; i++)
      {
	URLLoader loader = (URLLoader)urlinfos.elementAt(i);
	if (loader == null)
	  continue;
	
	Resource resource = loader.getResource(resourceName);
	if (resource != null)
	  return resource;
      }
    return null;
  }

  /**
   * Finds the first occurrence of a resource that can be found.
   *
   * @param resourceName the resource name to look for
   * @return the URL if found, null otherwise
   */
  public URL findResource(String resourceName)
  {
    Resource resource = findURLResource(resourceName);
    if (resource != null)
      return resource.getURL();
    
    // Resource not found
    return null;
  }

  /**
   * If the URLStreamHandlerFactory has been set this return the appropriate
   * URLStreamHandler for the given protocol, if not set returns null.
   *
   * @param protocol the protocol for which we need a URLStreamHandler
   * @return the appropriate URLStreamHandler or null
   */
  URLStreamHandler getURLStreamHandler(String protocol)
  {
    if (factory == null)
      return null;

    URLStreamHandler handler;
    synchronized (factoryCache)
      {
	// check if there're handler for the same protocol in cache
	HashMap cache = (HashMap)factoryCache.get(factory);
	handler = (URLStreamHandler)cache.get(protocol);
	if(handler == null)
	  {
	    // add it to cache
	    handler = factory.createURLStreamHandler(protocol);
	    cache.put(protocol, handler);
	  }
      }
    return handler;
  }

  /**
   * Finds all the resources with a particular name from all the locations.
   *
   * @exception IOException when an error occurs accessing one of the
   * locations
   * @param resourceName the name of the resource to lookup
   * @return a (possible empty) enumeration of URLs where the resource can be
   * found
   */
  public Enumeration findResources(String resourceName) throws IOException
  {
    Vector resources = new Vector();
    int max = urls.size();
    for (int i = 0; i < max; i++)
      {
	URLLoader loader = (URLLoader)urlinfos.elementAt(i);
	Resource resource = loader.getResource(resourceName);
	if (resource != null)
	  resources.add(resource.getURL());
      }
    return resources.elements();
  }

  /**
   * Returns the permissions needed to access a particular code
   * source.  These permissions includes those returned by
   * <code>SecureClassLoader.getPermissions()</code> and the actual
   * permissions to access the objects referenced by the URL of the
   * code source.  The extra permissions added depend on the protocol
   * and file portion of the URL in the code source. If the URL has
   * the "file" protocol ends with a '/' character then it must be a
   * directory and a file Permission to read everything in that
   * directory and all subdirectories is added. If the URL had the
   * "file" protocol and doesn't end with a '/' character then it must
   * be a normal file and a file permission to read that file is
   * added. If the <code>URL</code> has any other protocol then a
   * socket permission to connect and accept connections from the host
   * portion of the URL is added.
   *
   * @param source The codesource that needs the permissions to be accessed
   * @return the collection of permissions needed to access the code resource
   * @see java.security.SecureClassLoader#getPermissions()
   */
  protected PermissionCollection getPermissions(CodeSource source)
  {
    // XXX - This implementation does exactly as the Javadoc describes.
    // But maybe we should/could use URLConnection.getPermissions()?

    // First get the permissions that would normally be granted
    PermissionCollection permissions = super.getPermissions(source);
        
    // Now add the any extra permissions depending on the URL location
    URL url = source.getLocation();
    String protocol = url.getProtocol();
    if (protocol.equals("file"))
      {
	String file = url.getFile();
	// If the file end in / it must be an directory
	if (file.endsWith("/") || file.endsWith(File.separator))
	  {
	    // Grant permission to read everything in that directory and
	    // all subdirectories
	    permissions.add(new FilePermission(file + "-", "read"));
	  }
	else
	  {
	    // It is a 'normal' file
	    // Grant permission to access that file
	    permissions.add(new FilePermission(file, "read"));
	  }
      }
    else
      {
	// Grant permission to connect to and accept connections from host
	String host = url.getHost();
	if (host != null)
	  permissions.add(new SocketPermission(host, "connect,accept"));
      }

    return permissions;
  }
    
  /**
   * Returns all the locations that this class loader currently uses the
   * resolve classes and resource. This includes both the initially supplied
   * URLs as any URLs added later by the loader.
   * @return All the currently used URLs
   */
  public URL[] getURLs()
  {
    return (URL[]) urls.toArray(new URL[urls.size()]);
  }

  /**
   * Creates a new instance of a <code>URLClassLoader</code> that gets
   * classes from the supplied <code>URL</code>s. This class loader
   * will have as parent the standard system class loader.
   *
   * @param urls the initial URLs used to resolve classes and
   * resources
   *
   * @exception SecurityException when the calling code does not have
   * permission to access the given <code>URL</code>s
   */
  public static URLClassLoader newInstance(URL urls[])
    throws SecurityException
  {
    return newInstance(urls, null);
  }

  /**
   * Creates a new instance of a <code>URLClassLoader</code> that gets
   * classes from the supplied <code>URL</code>s and with the supplied
   * loader as parent class loader.
   *
   * @param urls the initial URLs used to resolve classes and
   * resources
   * @param parent the parent class loader
   *
   * @exception SecurityException when the calling code does not have
   * permission to access the given <code>URL</code>s
   */
  public static URLClassLoader newInstance(URL urls[],
					   final ClassLoader parent)
    throws SecurityException
  {
    SecurityManager sm = System.getSecurityManager();
    if (sm == null)
      return new URLClassLoader(urls, parent);
    else
      {
	final Object securityContext = sm.getSecurityContext();
	// XXX - What to do with anything else then an AccessControlContext?
	if (!(securityContext instanceof AccessControlContext))
	  throw new SecurityException
	    ("securityContext must be AccessControlContext: "
	     + securityContext);
	
	URLClassLoader loader =
	  (URLClassLoader)AccessController.doPrivileged(new PrivilegedAction()
	    {
	      public Object run()
	      {
		return new URLClassLoader
		  (parent, (AccessControlContext)securityContext);
	      }
	    });
	loader.addURLs(urls);
	return loader;
      }
  }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?