--- /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);