📄 urlclassloader.java
字号:
private void addURLs(URL[] newUrls) { for (int i = 0; i < newUrls.length; i++) { urls.add(newUrls[i]); addURLImpl(newUrls[i]); } } /** * Look in both Attributes for a given value. The first Attributes * object, if not null, has precedence. */ private String getAttributeValue(Attributes.Name name, Attributes first, Attributes second) { String result = null; if (first != null) result = first.getValue(name); if (result == null) result = second.getValue(name); return result; } /** * Defines a Package based on the given name and the supplied manifest * information. The manifest indicates the title, version and * vendor information of the specification and implementation and whether the * package is sealed. If the Manifest indicates that the package is sealed * then the Package will be sealed with respect to the supplied URL. * * @param name The name of the package * @param manifest The manifest describing the specification, * implementation and sealing details of the package * @param url the code source url to seal the package * @return the defined Package * @throws IllegalArgumentException If this package name already exists * in this class loader */ protected Package definePackage(String name, Manifest manifest, URL url) throws IllegalArgumentException { // Compute the name of the package as it may appear in the // Manifest. StringBuffer xform = new StringBuffer(name); for (int i = xform.length () - 1; i >= 0; --i) if (xform.charAt(i) == '.') xform.setCharAt(i, '/'); xform.append('/'); String xformName = xform.toString(); Attributes entryAttr = manifest.getAttributes(xformName); Attributes attr = manifest.getMainAttributes(); String specTitle = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE, entryAttr, attr); String specVersion = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION, entryAttr, attr); String specVendor = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR, entryAttr, attr); String implTitle = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE, entryAttr, attr); String implVersion = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION, entryAttr, attr); String implVendor = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR, entryAttr, attr); // 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, specVendor, specVersion, implTitle, implVendor, implVersion, 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"; int max = urlinfos.size(); Resource resource = null; for (int i = 0; i < max && resource == null; i++) { URLLoader loader = (URLLoader)urlinfos.elementAt(i); if (loader == null) continue; Class k = loader.getClass(className); if (k != null) return k; resource = loader.getResource(resourceName); } if (resource == null) throw new ClassNotFoundException(className + " not found in " + this); // 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(); try { 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(); } } finally { in.close(); } 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(); Class result = null; if (sm != null && securityContext != null) { result = (Class)AccessController.doPrivileged (new PrivilegedAction() { public Object run() { return defineClass(className, classData, 0, classData.length, source); } }, securityContext); } else result = defineClass(className, classData, 0, classData.length, source); // Avoid NullPointerExceptions. Certificate[] resourceCertificates = resource.getCertificates(); if(resourceCertificates != null) super.setSigners(result, resourceCertificates); return result; } catch (IOException ioe) { ClassNotFoundException cnfe; cnfe = new ClassNotFoundException(className + " not found in " + this); cnfe.initCause(ioe); throw cnfe; } } // Cached String representation of this URLClassLoader private String thisString; /** * Returns a String representation of this URLClassLoader giving the * actual Class name, the URLs that are searched and the parent * ClassLoader. */ public String toString() { synchronized (this) { if (thisString == null) { StringBuffer sb = new StringBuffer(); sb.append(this.getClass().getName()); sb.append("{urls=[" ); URL[] thisURLs = getURLs(); for (int i = 0; i < thisURLs.length; i++) { sb.append(thisURLs[i]); if (i < thisURLs.length - 1) sb.append(','); } sb.append(']'); sb.append(", parent="); sb.append(getParent()); sb.append('}'); thisString = sb.toString(); } return thisString; } } /** * 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 = urlinfos.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. * * @param resourceName the name of the resource to lookup * @return a (possible empty) enumeration of URLs where the resource can be * found * @exception IOException when an error occurs accessing one of the * locations */ public Enumeration findResources(String resourceName) throws IOException { Vector resources = new Vector(); int max = urlinfos.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(CodeSource) */ 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 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 * * @return the 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) 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 * * @return the 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -