summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2006-05-19 20:58:58 +0000
committerTom Tromey <tromey@redhat.com>2006-05-19 20:58:58 +0000
commiteb537850a6328e1669b935f6b7241e49854a015c (patch)
tree9459d11fdf72a9116f8da940a19c8d07d2ae2b9e
parentdd1904f2bc79d6debc857c04c9a0b814b7b63a8f (diff)
downloadclasspath-eb537850a6328e1669b935f6b7241e49854a015c.tar.gz
PR classpath/27444:
* gnu/java/net/loader/URLLoader.java (getClassPath): Documented. Changed return type. * java/net/URLClassLoader.java (urlloaders): Removed. (addURLImpl): Updated. * gnu/java/net/loader/JarURLLoader.java (initialized): New field. (indexSet): Likewise. (classPath): Changed type. (JarURLLoader): New constructor. (initialize): New method. (getResource): Use index set if it exists. (getClassPath): Updated. * gnu/java/net/IndexListParser.java (IndexListParser): Avoid NPE. (prefixes): New field. (headers): Removed. (IndexListParser): Fill in prefixes. (clearAll): Clear prefixes. (getHeaders): Changed return type.
-rw-r--r--ChangeLog21
-rw-r--r--gnu/java/net/IndexListParser.java47
-rw-r--r--gnu/java/net/loader/JarURLLoader.java165
-rw-r--r--gnu/java/net/loader/URLLoader.java8
-rw-r--r--java/net/URLClassLoader.java225
5 files changed, 286 insertions, 180 deletions
diff --git a/ChangeLog b/ChangeLog
index 0cc84e3ee..480e52d44 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2006-05-19 Tom Tromey <tromey@redhat.com>
+
+ PR classpath/27444:
+ * gnu/java/net/loader/URLLoader.java (getClassPath): Documented.
+ Changed return type.
+ * java/net/URLClassLoader.java (urlloaders): Removed.
+ (addURLImpl): Updated.
+ * gnu/java/net/loader/JarURLLoader.java (initialized): New field.
+ (indexSet): Likewise.
+ (classPath): Changed type.
+ (JarURLLoader): New constructor.
+ (initialize): New method.
+ (getResource): Use index set if it exists.
+ (getClassPath): Updated.
+ * gnu/java/net/IndexListParser.java (IndexListParser): Avoid NPE.
+ (prefixes): New field.
+ (headers): Removed.
+ (IndexListParser): Fill in prefixes.
+ (clearAll): Clear prefixes.
+ (getHeaders): Changed return type.
+
2006-05-19 Audrius Meskauskas <AudriusA@Bioinformatics.org>
* javax/swing/plaf/basic/BasicTableHeaderUI.java
diff --git a/gnu/java/net/IndexListParser.java b/gnu/java/net/IndexListParser.java
index cd4ca556b..23d2aa660 100644
--- a/gnu/java/net/IndexListParser.java
+++ b/gnu/java/net/IndexListParser.java
@@ -41,7 +41,8 @@ package gnu.java.net;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
-import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.jar.JarFile;
/**
@@ -67,7 +68,9 @@ public class IndexListParser
public static final String JAR_INDEX_VERSION_KEY = "JarIndex-Version: ";
double versionNumber;
- ArrayList headers = new ArrayList();
+ // Map each jar to the prefixes defined for the jar.
+ // This is intentionally kept in insertion order.
+ LinkedHashMap prefixes = new LinkedHashMap();
/**
* Parses the given jarfile's INDEX.LIST file if it exists.
@@ -94,22 +97,33 @@ public class IndexListParser
// Blank line must be next
line = br.readLine();
- if (!line.equals(""))
+ if (! "".equals(line))
{
clearAll();
return;
}
- // May contain sections
- line = br.readLine();
- while (line != null)
+ // May contain sections.
+ while ((line = br.readLine()) != null)
{
- headers.add(new URL(baseURL, line));
+ URL jarURL = new URL(baseURL, line);
+ HashSet values = new HashSet();
- // Skip all names in the section
- while (! (line = br.readLine()).equals(""));
- line = br.readLine();
+ // Read the names in the section.
+ while ((line = br.readLine()) != null)
+ {
+ // Stop at section boundary.
+ if ("".equals(line))
+ break;
+ values.add(line.trim());
+ }
+ prefixes.put(jarURL, values);
+ // Might have seen an early EOF.
+ if (line == null)
+ break;
}
+
+ br.close();
}
// else INDEX.LIST does not exist
}
@@ -125,7 +139,7 @@ public class IndexListParser
void clearAll()
{
versionNumber = 0;
- headers.clear();
+ prefixes = null;
}
/**
@@ -149,12 +163,15 @@ public class IndexListParser
}
/**
- * Gets the array list of all the headers found in the file.
+ * Gets the map of all the headers found in the file.
+ * The keys in the map are URLs of jars. The values in the map
+ * are Sets of package prefixes (and top-level file names), as
+ * specifed in INDEX.LIST.
*
- * @return an array list of all the headers.
+ * @return an map of all the headers, or null if no INDEX.LIST was found
*/
- public ArrayList getHeaders()
+ public LinkedHashMap getHeaders()
{
- return headers;
+ return prefixes;
}
}
diff --git a/gnu/java/net/loader/JarURLLoader.java b/gnu/java/net/loader/JarURLLoader.java
index e07b87b0d..130c6fc95 100644
--- a/gnu/java/net/loader/JarURLLoader.java
+++ b/gnu/java/net/loader/JarURLLoader.java
@@ -4,12 +4,15 @@ import gnu.java.net.IndexListParser;
import java.io.IOException;
import java.net.JarURLConnection;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Set;
import java.util.StringTokenizer;
-import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -21,26 +24,62 @@ import java.util.jar.Manifest;
*/
public 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
+ // True if we've initialized -- i.e., tried open the jar file.
+ boolean initialized;
+ // The jar file for this url.
+ JarFile jarfile;
+ // Base jar: url for all resources loaded from jar.
+ final URL baseJarURL;
+ // The "Class-Path" attribute of this Jar's manifest.
+ ArrayList classPath;
+ // If not null, a mapping from INDEX.LIST for this jar only.
+ // This is a set of all prefixes and top-level files that
+ // ought to be available in this jar.
+ Set indexSet;
- Vector classPath; // The "Class-Path" attribute of this Jar's manifest
+ // This constructor is used internally. It purposely does not open
+ // the jar file -- it defers this until later. This allows us to
+ // implement INDEX.LIST lazy-loading semantics.
+ private JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
+ URLStreamHandlerFactory factory,
+ URL baseURL, URL absoluteUrl,
+ Set indexSet)
+ {
+ super(classloader, cache, factory, baseURL, absoluteUrl);
+ URL newBaseURL = null;
+ try
+ {
+ // Cache url prefix for all resources in this jar url.
+ String base = baseURL.toExternalForm() + "!/";
+ newBaseURL = new URL("jar", "", -1, base, cache.get(factory, "jar"));
+ }
+ catch (MalformedURLException ignore)
+ {
+ // Ignore.
+ }
+ this.baseJarURL = newBaseURL;
+ this.classPath = null;
+ this.indexSet = indexSet;
+ }
+
+ // This constructor is used by URLClassLoader. It will immediately
+ // try to read the jar file, in case we've found an index or a class-path
+ // setting. FIXME: it would be nice to defer this as well, but URLClassLoader
+ // makes this hard.
public JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache,
URLStreamHandlerFactory factory,
URL baseURL, URL absoluteUrl)
{
- super(classloader, cache, factory, baseURL, absoluteUrl);
+ this(classloader, cache, factory, baseURL, absoluteUrl, null);
+ initialize();
+ }
- this.classPath = null;
- URL baseJarURL = null;
+ private void initialize()
+ {
JarFile jarfile = null;
try
{
- // Cache url prefix for all resources in this jar url.
- String base = baseURL.toExternalForm() + "!/";
- baseJarURL = new URL("jar", "", -1, base, cache.get(factory, "jar"));
-
jarfile =
((JarURLConnection) baseJarURL.openConnection()).getJarFile();
@@ -48,30 +87,66 @@ public final class JarURLLoader extends URLLoader
Attributes attributes;
String classPathString;
- this.classPath = new Vector();
-
- ArrayList indexListHeaders = new IndexListParser(jarfile, baseJarURL, baseURL).getHeaders();
- if (indexListHeaders.size() > 0)
- this.classPath.addAll(indexListHeaders);
+ IndexListParser parser = new IndexListParser(jarfile, baseJarURL,
+ baseURL);
+ LinkedHashMap indexMap = parser.getHeaders();
+ if (indexMap != null)
+ {
+ // Note that the index also computes
+ // the resulting Class-Path -- there are jars out there
+ // where the index lists some required jars which do
+ // not appear in the Class-Path attribute in the manifest.
+ this.classPath = new ArrayList();
+ Iterator it = indexMap.entrySet().iterator();
+ while (it.hasNext())
+ {
+ LinkedHashMap.Entry entry = (LinkedHashMap.Entry) it.next();
+ URL subURL = (URL) entry.getKey();
+ Set prefixes = (Set) entry.getValue();
+ if (subURL.equals(baseURL))
+ this.indexSet = prefixes;
+ else
+ {
+ JarURLLoader subLoader = new JarURLLoader(classloader,
+ cache,
+ factory, subURL,
+ subURL,
+ prefixes);
+ // Note that we don't care if the sub-loader itself has an
+ // index or a class-path -- only the top-level jar
+ // file gets this treatment; its index should cover
+ // everything.
+ this.classPath.add(subLoader);
+ }
+ }
+ }
else if ((manifest = jarfile.getManifest()) != null
- && (attributes = manifest.getMainAttributes()) != null
- && ((classPathString
- = attributes.getValue(Attributes.Name.CLASS_PATH))
- != null))
- {
+ && (attributes = manifest.getMainAttributes()) != null
+ && ((classPathString
+ = attributes.getValue(Attributes.Name.CLASS_PATH))
+ != null))
+ {
+ this.classPath = new ArrayList();
StringTokenizer st = new StringTokenizer(classPathString, " ");
while (st.hasMoreElements ())
- {
- String e = st.nextToken ();
- try
- {
- this.classPath.add(new URL(baseURL, e));
- }
- catch (java.net.MalformedURLException xx)
- {
- // Give up
- }
- }
+ {
+ String e = st.nextToken ();
+ try
+ {
+ URL subURL = new URL(baseURL, e);
+ JarURLLoader subLoader = new JarURLLoader(classloader,
+ cache, factory,
+ subURL, subURL);
+ this.classPath.add(subLoader);
+ ArrayList extra = subLoader.getClassPath();
+ if (extra != null)
+ this.classPath.addAll(extra);
+ }
+ catch (java.net.MalformedURLException xx)
+ {
+ // Give up
+ }
+ }
}
}
catch (IOException ioe)
@@ -79,18 +154,34 @@ public final class JarURLLoader extends URLLoader
/* ignored */
}
- this.baseJarURL = baseJarURL;
this.jarfile = jarfile;
+ this.initialized = true;
}
/** get resource with the name "name" in the jar url */
public Resource getResource(String name)
{
- if (jarfile == null)
- return null;
-
if (name.startsWith("/"))
name = name.substring(1);
+ if (indexSet != null)
+ {
+ // Trust the index.
+ String basename = name;
+ int offset = basename.lastIndexOf('/');
+ if (offset != -1)
+ basename = basename.substring(0, offset);
+ if (! indexSet.contains(basename))
+ return null;
+ // FIXME: if the index claim to hold the resource, and jar file
+ // doesn't have it, we're supposed to throw an exception. However,
+ // in our model this is tricky to implement, as another URLLoader from
+ // the same top-level jar may have an overlapping index entry.
+ }
+
+ if (! initialized)
+ initialize();
+ if (jarfile == null)
+ return null;
JarEntry je = jarfile.getJarEntry(name);
if (je != null)
@@ -111,7 +202,7 @@ public final class JarURLLoader extends URLLoader
}
}
- public Vector getClassPath()
+ public ArrayList getClassPath()
{
return classPath;
}
diff --git a/gnu/java/net/loader/URLLoader.java b/gnu/java/net/loader/URLLoader.java
index 1415f3f79..d073c5429 100644
--- a/gnu/java/net/loader/URLLoader.java
+++ b/gnu/java/net/loader/URLLoader.java
@@ -42,7 +42,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandlerFactory;
import java.security.CodeSource;
-import java.util.Vector;
+import java.util.ArrayList;
import java.util.jar.Manifest;
/**
@@ -136,7 +136,11 @@ public abstract class URLLoader
return null;
}
- public Vector getClassPath()
+ /**
+ * Return a list of new URLLoader objects representing any
+ * class path entries added by this container.
+ */
+ public ArrayList getClassPath()
{
return null;
}
diff --git a/java/net/URLClassLoader.java b/java/net/URLClassLoader.java
index 34d8af067..403f7485c 100644
--- a/java/net/URLClassLoader.java
+++ b/java/net/URLClassLoader.java
@@ -61,9 +61,8 @@ import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.SecureClassLoader;
import java.security.cert.Certificate;
+import java.util.ArrayList;
import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.Vector;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
@@ -131,14 +130,6 @@ 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
* creating handlers each time the same protocol comes.
@@ -299,132 +290,114 @@ public class URLClassLoader extends SecureClassLoader
// Reset the toString() value.
thisString = null;
- // Check global cache to see if there're already url loader
- // for this url.
- URLLoader loader = (URLLoader) urlloaders.get(newUrl);
- if (loader == null)
- {
- String file = newUrl.getFile();
- String protocol = newUrl.getProtocol();
-
- // If we have a file: URL, we want to make it absolute
- // here, before we decide whether it is really a jar.
- URL absoluteURL;
- if ("file".equals (protocol))
- {
- File dir = new File(file);
- URL absUrl;
- try
- {
- absoluteURL = dir.getCanonicalFile().toURL();
- }
- catch (IOException ignore)
- {
- try
- {
- absoluteURL = dir.getAbsoluteFile().toURL();
- }
- catch (MalformedURLException _)
- {
- // This really should not happen.
- absoluteURL = newUrl;
- }
- }
- }
- else
- {
- // This doesn't hurt, and it simplifies the logic a
- // little.
- absoluteURL = newUrl;
- }
+ // Create a loader for this URL.
+ URLLoader loader = null;
+ String file = newUrl.getFile();
+ String protocol = newUrl.getProtocol();
- // First see if we can find a handler with the correct name.
+ // If we have a file: URL, we want to make it absolute
+ // here, before we decide whether it is really a jar.
+ URL absoluteURL;
+ if ("file".equals (protocol))
+ {
+ File dir = new File(file);
+ URL absUrl;
try
{
- Class handler = Class.forName(URL_LOADER_PREFIX + protocol);
- Class[] argTypes = new Class[] { URLClassLoader.class,
- URLStreamHandlerCache.class,
- URLStreamHandlerFactory.class,
- URL.class,
- URL.class };
- Constructor k = handler.getDeclaredConstructor(argTypes);
- loader
- = (URLLoader) k.newInstance(new Object[] { this,
- factoryCache,
- factory,
- newUrl,
- absoluteURL });
- }
- catch (ClassNotFoundException ignore)
- {
- // Fall through.
- }
- catch (NoSuchMethodException nsme)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("couldn't find URLLoader constructor");
- vme.initCause(nsme);
- throw vme;
- }
- catch (InstantiationException inste)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("couldn't instantiate URLLoader");
- vme.initCause(inste);
- throw vme;
- }
- catch (InvocationTargetException ite)
- {
- // Programming error in the class library.
- InternalError vme
- = new InternalError("error instantiating URLLoader");
- vme.initCause(ite);
- throw vme;
+ absoluteURL = dir.getCanonicalFile().toURL();
}
- catch (IllegalAccessException illae)
+ catch (IOException ignore)
{
- // Programming error in the class library.
- InternalError vme
- = new InternalError("invalid access to URLLoader");
- vme.initCause(illae);
- throw vme;
- }
-
- if (loader == null)
- {
- // If it is not a directory, use the jar loader.
- if (! (file.endsWith("/") || file.endsWith(File.separator)))
- loader = new JarURLLoader(this, factoryCache, factory,
- newUrl, absoluteURL);
- else if ("file".equals(protocol))
- loader = new FileURLLoader(this, factoryCache, factory,
- newUrl, absoluteURL);
- else
- loader = new RemoteURLLoader(this, factoryCache, factory,
- newUrl);
+ try
+ {
+ absoluteURL = dir.getAbsoluteFile().toURL();
+ }
+ catch (MalformedURLException _)
+ {
+ // This really should not happen.
+ absoluteURL = newUrl;
+ }
}
-
- // Cache it.
- urlloaders.put(newUrl, loader);
+ }
+ else
+ {
+ // This doesn't hurt, and it simplifies the logic a
+ // little.
+ absoluteURL = newUrl;
}
- urlinfos.add(loader);
+ // First see if we can find a handler with the correct name.
+ try
+ {
+ Class handler = Class.forName(URL_LOADER_PREFIX + protocol);
+ Class[] argTypes = new Class[] { URLClassLoader.class,
+ URLStreamHandlerCache.class,
+ URLStreamHandlerFactory.class,
+ URL.class,
+ URL.class };
+ Constructor k = handler.getDeclaredConstructor(argTypes);
+ loader
+ = (URLLoader) k.newInstance(new Object[] { this,
+ factoryCache,
+ factory,
+ newUrl,
+ absoluteURL });
+ }
+ catch (ClassNotFoundException ignore)
+ {
+ // Fall through.
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ // Programming error in the class library.
+ InternalError vme
+ = new InternalError("couldn't find URLLoader constructor");
+ vme.initCause(nsme);
+ throw vme;
+ }
+ catch (InstantiationException inste)
+ {
+ // Programming error in the class library.
+ InternalError vme
+ = new InternalError("couldn't instantiate URLLoader");
+ vme.initCause(inste);
+ throw vme;
+ }
+ catch (InvocationTargetException ite)
+ {
+ // Programming error in the class library.
+ InternalError vme
+ = new InternalError("error instantiating URLLoader");
+ vme.initCause(ite);
+ throw vme;
+ }
+ catch (IllegalAccessException illae)
+ {
+ // Programming error in the class library.
+ InternalError vme
+ = new InternalError("invalid access to URLLoader");
+ vme.initCause(illae);
+ throw vme;
+ }
- 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);
- }
- }
+ if (loader == null)
+ {
+ // If it is not a directory, use the jar loader.
+ if (! (file.endsWith("/") || file.endsWith(File.separator)))
+ loader = new JarURLLoader(this, factoryCache, factory,
+ newUrl, absoluteURL);
+ else if ("file".equals(protocol))
+ loader = new FileURLLoader(this, factoryCache, factory,
+ newUrl, absoluteURL);
+ else
+ loader = new RemoteURLLoader(this, factoryCache, factory,
+ newUrl);
+ }
+ urlinfos.add(loader);
+ ArrayList extra = loader.getClassPath();
+ if (extra != null)
+ urlinfos.addAll(extra);
}
}