--- /home/tromey/gnu/Nightly/classpath/classpath/java/net/URLClassLoader.java 2004-11-17 02:24:08.000000000 -0700 +++ java/net/URLClassLoader.java 2004-11-25 02:16:36.000000000 -0700 @@ -54,11 +54,15 @@ 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; + /** * A secure class loader that can load classes and resources from @@ -142,9 +146,10 @@ private final Vector urls = new Vector(); /** - * Store pre-parsed information for each url into this vector - * each element is a URL loader, corresponding to the URL of - * the same index in "urls" + * 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(); @@ -187,9 +192,25 @@ 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(baseURL, null); + this.noCertCodeSource = new CodeSource(overrideURL, null); + } + + /** + * Returns a Class loaded by this + * URLLoader, or null 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; } /** @@ -208,6 +229,11 @@ { return null; } + + Vector getClassPath() + { + return null; + } } /** @@ -277,6 +303,10 @@ 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 + + SoURLLoader soURLLoader; + public JarURLLoader(URLClassLoader classloader, URL baseURL) { super(classloader, baseURL); @@ -289,25 +319,87 @@ sb.append("!/"); String jarURL = sb.toString(); + this.soURLLoader = null; + this.classPath = null; URL baseJarURL = null; JarFile jarfile = null; try - { - baseJarURL = - new URL(null, jarURL, classloader.getURLStreamHandler("jar")); - - jarfile = - ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); - } + { + baseJarURL + = new URL(null, jarURL, classloader.getURLStreamHandler("jar")); + jarfile + = ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + if (jarfile != null) + { + String fileName = baseURL.getFile(); + if (fileName != null) + { + File f = new File(fileName); + String libDirName = f.getCanonicalFile().getParent() + + File.separator + "GCJLIBS"; + File libDir = new File(libDirName); + if (libDir != null && (libDir.isDirectory())) + { + File soFile = new File (libDirName + + File.separator + f.getName() + + ".so"); + if (soFile != null && soFile.isFile()) + this.soURLLoader + = new SoURLLoader (classloader, soFile.toURL(), + baseURL); + } + } + + 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, + System.getProperty ("path.separator", ":")); + + 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 */ + /* ignored */ } this.baseJarURL = baseJarURL; this.jarfile = jarfile; } + Class getClass(String className) + { + if (soURLLoader != null) + return soURLLoader.getClass(className); + return null; + } + /** get resource with the name "name" in the jar url */ Resource getResource(String name) { @@ -324,6 +416,11 @@ return null; } + public String toString () + { + return "jarfile " + jarfile.getName(); + } + Manifest getManifest() { try @@ -335,6 +432,11 @@ return null; } } + + Vector getClassPath() + { + return classPath; + } } static final class JarURLResource extends Resource @@ -359,11 +461,7 @@ 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(); + return entry.getCertificates(); } URL getURL() @@ -468,6 +566,68 @@ } /** + * A SoURLLoader is a type of URLLoader + * that loads classes and resources from a shared library. + */ + final static class SoURLLoader extends URLLoader + { + SharedLibHelper helper; + + SoURLLoader(URLClassLoader classloader, URL url) + { + this(classloader, url, url); + } + + SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL) + { + super(classloader, url, overrideURL); + helper = SharedLibHelper.findHelper(classloader, url.getFile(), + noCertCodeSource); + } + + Class getClass(String className) + { + return helper.findClass(className); + } + + Resource getResource(String name) + { + URL url = helper.findResource(name); + if (url == null) + return null; + return new SoResource(this, name, url); + } + } + + final static class SoResource extends Resource + { + SoResource(SoURLLoader loader, String name, URL url) + { + super(loader, name); + this.url = url; + } + + InputStream getInputStream() throws IOException + { + URLConnection conn = url.openConnection(); + return conn.getInputStream(); + } + + public int getLength() + { + // FIXME we could find this by asking the core object. + return -1; + } + + public URL getURL () + { + return url; + } + + final URL url; + } + + /** * A FileURLLoader is a type of URLLoader * only loading from file url. */ @@ -511,6 +671,11 @@ return (int) file.length(); } + public String toString () + { + return "file " +file.getAbsolutePath(); + } + public URL getURL() { try @@ -552,6 +717,25 @@ } /** + * Private constructor used by the static + * newInstance(URL[]) method. Creates an + * URLClassLoader without any URLs + * yet. This is used to bypass the normal security check for + * creating classloaders, but remembers the security context which + * will be used when defining classes. The URLs to + * load from must be added by the newInstance() method + * in the security context of the caller. + * + * @param securityContext the security context of the unprivileged code. + */ + private URLClassLoader(AccessControlContext securityContext) + { + super(); + this.factory = null; + this.securityContext = securityContext; + } + + /** * Creates a URLClassLoader that gets classes from the supplied * URLs. * To determine if this classloader may be created the constructor of @@ -644,6 +828,7 @@ */ protected void addURL(URL newUrl) { + urls.add(newUrl); addURLImpl(newUrl); } @@ -663,7 +848,9 @@ String protocol = newUrl.getProtocol(); // Check that it is not a directory - if (! (file.endsWith("/") || file.endsWith(File.separator))) + if ("gcjlib".equals(protocol)) + loader = new SoURLLoader(this, newUrl); + else if (! (file.endsWith("/") || file.endsWith(File.separator))) loader = new JarURLLoader(this, newUrl); else if ("file".equals(protocol)) loader = new FileURLLoader(this, newUrl); @@ -674,8 +861,21 @@ urlloaders.put(newUrl, loader); } - urls.add(newUrl); - urlinfos.add(loader); + urlinfos.add(loader); + + Vector extraUrls = loader.getClassPath(); + if (extraUrls != null) + { + Iterator it = extraUrls.iterator(); + while (it.hasNext()) + { + URL url = (URL)it.next(); + URLLoader extraLoader = (URLLoader) urlloaders.get(url); + if (! urlinfos.contains (extraLoader)) + addURLImpl(url); + } + } + } } @@ -686,7 +886,7 @@ private void addURLs(URL[] newUrls) { for (int i = 0; i < newUrls.length; i++) - addURLImpl(newUrls[i]); + addURL(newUrls[i]); } /** @@ -743,7 +943,20 @@ { // Just try to find the resource by the (almost) same name String resourceName = className.replace('.', '/') + ".class"; - Resource resource = findURLResource(resourceName); + 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 " + urls); @@ -753,43 +966,36 @@ { 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(); + 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; @@ -815,10 +1021,9 @@ // And finally construct the class! SecurityManager sm = System.getSecurityManager(); - Class result = null; if (sm != null && securityContext != null) { - result = (Class)AccessController.doPrivileged + return (Class)AccessController.doPrivileged (new PrivilegedAction() { public Object run() @@ -830,10 +1035,7 @@ }, securityContext); } else - result = defineClass(className, classData, 0, classData.length, source); - - super.setSigners(result, resource.getCertificates()); - return result; + return defineClass(className, classData, 0, classData.length, source); } catch (IOException ioe) { @@ -850,7 +1052,7 @@ */ private Resource findURLResource(String resourceName) { - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i); @@ -921,7 +1123,7 @@ throws IOException { Vector resources = new Vector(); - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i);