📄 urlclassloader.java
字号:
/* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.This file is part of GNU Classpath.GNU Classpath is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU Classpath is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Classpath; see the file COPYING. If not, write to theFree Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301 USA.Linking this library statically or dynamically with other modules ismaking a combined work based on this library. Thus, the terms andconditions of the GNU General Public License cover the wholecombination.As a special exception, the copyright holders of this library give youpermission to link this library with independent modules to produce anexecutable, regardless of the license terms of these independentmodules, and to copy and distribute the resulting executable underterms of your choice, provided that you also meet, for each linkedindependent module, the terms and conditions of the license of thatmodule. An independent module is a module which is not derived fromor based on this library. If you modify this library, you may extendthis exception to your version of the library, but you are notobligated to do so. If you do not wish to do so, delete thisexception statement from your version. */package java.net;import java.io.ByteArrayOutputStream;import java.io.EOFException;import java.io.File;import java.io.FileInputStream;import java.io.FilePermission;import java.io.IOException;import java.io.InputStream;import java.security.AccessControlContext;import java.security.AccessController;import java.security.CodeSource;import java.security.PermissionCollection;import java.security.PrivilegedAction;import java.security.SecureClassLoader;import java.security.cert.Certificate;import java.util.Enumeration;import java.util.HashMap;import java.util.Iterator;import java.util.StringTokenizer;import java.util.Vector;import java.util.jar.Attributes;import java.util.jar.JarEntry;import java.util.jar.JarFile;import java.util.jar.Manifest;import gnu.gcj.runtime.SharedLibHelper;import gnu.gcj.Core;import gnu.java.net.protocol.core.CoreInputStream;/** * A secure class loader that can load classes and resources from * multiple locations. Given an array of <code>URL</code>s this class * loader will retrieve classes and resources by fetching them from * possible remote locations. Each <code>URL</code> is searched in * order in which it was added. If the file portion of the * <code>URL</code> ends with a '/' character then it is interpreted * as a base directory, otherwise it is interpreted as a jar file from * which the classes/resources are resolved. * * <p>New instances can be created by two static * <code>newInstance()</code> methods or by three public * contructors. Both ways give the option to supply an initial array * of <code>URL</code>s and (optionally) a parent classloader (that is * different from the standard system class loader).</p> * * <p>Normally creating a <code>URLClassLoader</code> throws a * <code>SecurityException</code> if a <code>SecurityManager</code> is * installed and the <code>checkCreateClassLoader()</code> method does * not return true. But the <code>newInstance()</code> methods may be * used by any code as long as it has permission to acces the given * <code>URL</code>s. <code>URLClassLoaders</code> created by the * <code>newInstance()</code> methods also explicitly call the * <code>checkPackageAccess()</code> method of * <code>SecurityManager</code> if one is installed before trying to * load a class. Note that only subclasses of * <code>URLClassLoader</code> can add new URLs after the * URLClassLoader had been created. But it is always possible to get * an array of all URLs that the class loader uses to resolve classes * and resources by way of the <code>getURLs()</code> method.</p> * * <p>Open issues: * <ul> * * <li>Should the URLClassLoader actually add the locations found in * the manifest or is this the responsibility of some other * loader/(sub)class? (see <a * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html"> * Extension Mechanism Architecture - Bundles Extensions</a>)</li> * * <li>How does <code>definePackage()</code> and sealing work * precisely?</li> * * <li>We save and use the security context (when a created by * <code>newInstance()</code> but do we have to use it in more * places?</li> * * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li> * * </ul> * </p> * * @since 1.2 * * @author Mark Wielaard (mark@klomp.org) * @author Wu Gansha (gansha.wu@intel.com) */public class URLClassLoader extends SecureClassLoader{ // Class Variables /** * A global cache to store mappings between URLLoader and URL, * so we can avoid do all the homework each time the same URL * comes. * XXX - Keeps these loaders forever which prevents garbage collection. */ private static HashMap urlloaders = new HashMap(); /** * A cache to store mappings between handler factory and its * private protocol handler cache (also a HashMap), so we can avoid * create handlers each time the same protocol comes. */ private static HashMap factoryCache = new HashMap(5); // Instance variables /** Locations to load classes from */ private final Vector urls = new Vector(); /** * Store pre-parsed information for each url into this vector: each * element is a URL loader. A jar file has its own class-path * attribute which adds to the URLs that will be searched, but this * does not add to the list of urls. */ private final Vector urlinfos = new Vector(); /** Factory used to get the protocol handlers of the URLs */ private final URLStreamHandlerFactory factory; /** * The security context when created from <code>newInstance()</code> * or null when created through a normal constructor or when no * <code>SecurityManager</code> was installed. */ private final AccessControlContext securityContext; // Helper classes /** * A <code>URLLoader</code> contains all logic to load resources from a * given base <code>URL</code>. */ abstract static class URLLoader { /** * Our classloader to get info from if needed. */ final URLClassLoader classloader; /** * The base URL from which all resources are loaded. */ final URL baseURL; /** * A <code>CodeSource</code> without any associated certificates. * It is common for classes to not have certificates associated * with them. If they come from the same <code>URLLoader</code> * then it is safe to share the associated <code>CodeSource</code> * between them since <code>CodeSource</code> is immutable. */ final CodeSource noCertCodeSource; URLLoader(URLClassLoader classloader, URL baseURL) { this(classloader, baseURL, baseURL); } URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) { this.classloader = classloader; this.baseURL = baseURL; this.noCertCodeSource = new CodeSource(overrideURL, null); } /** * Returns a <code>Class</code> loaded by this * <code>URLLoader</code>, or <code>null</code> when this loader * either can't load the class or doesn't know how to load classes * at all. */ Class getClass(String className) { return null; } /** * Returns a <code>Resource</code> loaded by this * <code>URLLoader</code>, or <code>null</code> when no * <code>Resource</code> with the given name exists. */ abstract Resource getResource(String s); /** * Returns the <code>Manifest</code> associated with the * <code>Resource</code>s loaded by this <code>URLLoader</code> or * <code>null</code> there is no such <code>Manifest</code>. */ Manifest getManifest() { return null; } Vector getClassPath() { return null; } } /** * A <code>Resource</code> represents a resource in some * <code>URLLoader</code>. It also contains all information (e.g., * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and * <code>InputStream</code>) that is necessary for loading resources * and creating classes from a <code>URL</code>. */ abstract static class Resource { final URLLoader loader; Resource(URLLoader loader) { this.loader = loader; } /** * Returns the non-null <code>CodeSource</code> associated with * this resource. */ CodeSource getCodeSource() { Certificate[] certs = getCertificates(); if (certs == null) return loader.noCertCodeSource; else return new CodeSource(loader.baseURL, certs); } /** * Returns <code>Certificates</code> associated with this * resource, or null when there are none. */ Certificate[] getCertificates() { return null; } /** * Return a <code>URL</code> that can be used to access this resource. */ abstract URL getURL(); /** * Returns the size of this <code>Resource</code> in bytes or * <code>-1</code> when unknown. */ abstract int getLength(); /** * Returns the non-null <code>InputStream</code> through which * this resource can be loaded. */ abstract InputStream getInputStream() throws IOException; } /** * A <code>JarURLLoader</code> is a type of <code>URLLoader</code> * only loading from jar url. */ static final class JarURLLoader extends URLLoader { final JarFile jarfile; // The jar file for this url final URL baseJarURL; // Base jar: url for all resources loaded from jar Vector classPath; // The "Class-Path" attribute of this Jar's manifest public JarURLLoader(URLClassLoader classloader, URL baseURL, URL absoluteUrl) { super(classloader, baseURL, absoluteUrl); // Cache url prefix for all resources in this jar url. String external = baseURL.toExternalForm(); StringBuffer sb = new StringBuffer(external.length() + 6); sb.append("jar:"); sb.append(external); sb.append("!/"); String jarURL = sb.toString(); this.classPath = null; URL baseJarURL = null; JarFile jarfile = null; try { baseJarURL = new URL(null, jarURL, classloader.getURLStreamHandler("jar")); jarfile = ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); Manifest manifest; Attributes attributes; String classPathString; if ((manifest = jarfile.getManifest()) != null && (attributes = manifest.getMainAttributes()) != null && ((classPathString = attributes.getValue(Attributes.Name.CLASS_PATH)) != null)) { this.classPath = new Vector(); StringTokenizer st = new StringTokenizer(classPathString, " "); while (st.hasMoreElements ()) { String e = st.nextToken (); try { URL url = new URL(baseURL, e); this.classPath.add(url); } catch (java.net.MalformedURLException xx) { // Give up } } } } catch (IOException ioe) { /* ignored */ } this.baseJarURL = baseJarURL; this.jarfile = jarfile; } /** get resource with the name "name" in the jar url */ Resource getResource(String name) { if (jarfile == null) return null; if (name.startsWith("/")) name = name.substring(1); JarEntry je = jarfile.getJarEntry(name); if (je != null) return new JarURLResource(this, name, je); else return null; } Manifest getManifest() { try { return (jarfile == null) ? null : jarfile.getManifest(); } catch (IOException ioe) { return null; } } Vector getClassPath() { return classPath; } } static final class JarURLResource extends Resource { private final JarEntry entry; private final String name; JarURLResource(JarURLLoader loader, String name, JarEntry entry) { super(loader); this.entry = entry; this.name = name; } InputStream getInputStream() throws IOException { return ((JarURLLoader) loader).jarfile.getInputStream(entry); } int getLength() { return (int) entry.getSize(); } Certificate[] getCertificates() { // We have to get the entry from the jar file again, because the // certificates will not be available until the entire entry has // been read. return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) .getCertificates(); } URL getURL() { try { return new URL(((JarURLLoader) loader).baseJarURL, name, loader.classloader.getURLStreamHandler("jar")); } catch (MalformedURLException e) { InternalError ie = new InternalError(); ie.initCause(e); throw ie; } } } /** * Loader for remote directories. */ static final class RemoteURLLoader extends URLLoader { private final String protocol; RemoteURLLoader(URLClassLoader classloader, URL url) { super(classloader, url); protocol = url.getProtocol(); } /** * Get a remote resource. * Returns null if no such resource exists. */ Resource getResource(String name) { try { URL url = new URL(baseURL, name, classloader.getURLStreamHandler(protocol)); URLConnection connection = url.openConnection(); // Open the connection and check the stream // just to be sure it exists. int length = connection.getContentLength(); InputStream stream = connection.getInputStream(); // We can do some extra checking if it is a http request if (connection instanceof HttpURLConnection)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -