You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ap...@apache.org on 2007/05/29 08:34:31 UTC
svn commit: r542426 - in
/harmony/enhanced/classlib/trunk/modules/luni/src/main/java:
java/net/JarURLConnection.java java/net/URLClassLoader.java
org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java
Author: apetrenko
Date: Mon May 28 23:34:30 2007
New Revision: 542426
URL: http://svn.apache.org/viewvc?view=rev&rev=542426
Log:
Patch for HARMONY-3983 "[classlib][luni] Performance improvement for URLClassLoader and JarURLConnecton classes"
Modified:
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/JarURLConnection.java
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/URLClassLoader.java
harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java
Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/JarURLConnection.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/JarURLConnection.java?view=diff&rev=542426&r1=542425&r2=542426
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/JarURLConnection.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/JarURLConnection.java Mon May 28 23:34:30 2007
@@ -54,10 +54,12 @@
if ((sepIdx = file.indexOf("!/")) < 0) { //$NON-NLS-1$
throw new MalformedURLException();
}
- if (file.length() == sepIdx + 2) {
+ fileURL = new URL(url.getFile().substring(0,sepIdx)); //$NON-NLS-1$
+ sepIdx += 2;
+ if (file.length() == sepIdx) {
return;
}
- entryName = file.substring(sepIdx + 2, file.length());
+ entryName = file.substring(sepIdx, file.length());
if (null != url.getRef()) {
entryName += "#" + url.getRef(); //$NON-NLS-1$
}
@@ -149,15 +151,7 @@
* @return java.net.URL the URL of the JarFile.
*/
public URL getJarFileURL() {
- if (fileURL != null) {
- return fileURL;
- }
- try {
- return fileURL = new URL(url.getFile().substring(0,
- url.getFile().indexOf("!/"))); //$NON-NLS-1$
- } catch (MalformedURLException e) {
- return null;
- }
+ return fileURL;
}
/**
Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/URLClassLoader.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/URLClassLoader.java?view=diff&rev=542426&r1=542425&r2=542426
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/URLClassLoader.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/net/URLClassLoader.java Mon May 28 23:34:30 2007
@@ -24,6 +24,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.FileNotFoundException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
@@ -35,20 +38,13 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.ListIterator;
import java.util.Map;
-import java.util.Set;
import java.util.StringTokenizer;
-import java.util.Vector;
+import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
import org.apache.harmony.luni.util.InvalidJarIndexException;
import org.apache.harmony.luni.util.Msg;
@@ -61,28 +57,14 @@
*/
public class URLClassLoader extends SecureClassLoader {
- private static URL[] NO_PATH = new URL[0];
-
- @SuppressWarnings("unchecked")
- private static <K, V> Hashtable<K, V>[] newHashtableArray(int size) {
- return new Hashtable[size];
- }
-
- URL[] urls, orgUrls;
-
- Set<URL> invalidUrls = Collections.synchronizedSet(new HashSet<URL>());
+ ArrayList<URL> originalUrls;
- private Map<URL, JarFile> resCache =
- Collections.synchronizedMap(new IdentityHashMap<URL, JarFile>(32));
-
- private Object lock = new Object();
+ List<URL> searchList;
+ ArrayList<URLHandler> handlerList;
+ Map<URL,URLHandler> handlerMap = new HashMap<URL,URLHandler>();
private URLStreamHandlerFactory factory;
- HashMap<URL, URL[]> extensions;
-
- Hashtable<String, URL[]>[] indexes;
-
private AccessControlContext currentContext;
static class SubURLClassLoader extends URLClassLoader {
@@ -130,6 +112,487 @@
}
}
+ static class IndexFile {
+
+ private HashMap<String,ArrayList<URL>> map;
+ //private URLClassLoader host;
+
+
+ static IndexFile readIndexFile(JarFile jf, JarEntry indexEntry,URL url) {
+ BufferedReader in = null;
+ InputStream is = null;
+ try {
+ // Add mappings from resource to jar file
+ String parentURLString = getParentURL(url).toExternalForm();
+ String prefix = "jar:" //$NON-NLS-1$
+ + parentURLString + "/"; //$NON-NLS-1$
+ is = jf.getInputStream(indexEntry);
+ in = new BufferedReader(new InputStreamReader(is,"UTF8"));
+ HashMap<String, ArrayList<URL>> pre_map = new HashMap<String, ArrayList<URL>>();
+ // Ignore the 2 first lines (index version)
+ if(in.readLine()==null) return null;
+ if(in.readLine()==null) return null;
+ TOP_CYCLE: while(true) {
+ String line = in.readLine();
+ if(line==null) {
+ break;
+ }
+ URL jar = new URL(prefix+ line + "!/"); //$NON-NLS-1$
+ while(true) {
+ line = in.readLine();
+ if(line==null) {
+ break TOP_CYCLE;
+ }
+ if("".equals(line) ) {
+ break;
+ }
+ ArrayList<URL> list;
+ if(pre_map.containsKey(line)) {
+ list = pre_map.get(line);
+ } else {
+ list = new ArrayList<URL>();
+ pre_map.put(line,list);
+ }
+ list.add(jar);
+ }
+ }
+ if(!pre_map.isEmpty()){
+ return new IndexFile(pre_map);
+ }
+ } catch (MalformedURLException e) {
+ // Ignore this jar's index
+ } catch (IOException e) {
+ // Ignore this jar's index
+ }
+ finally {
+ if(in!=null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ }
+ }
+ if(is!=null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return null;
+ }
+
+ private static URL getParentURL(URL url) throws IOException {
+ URL fileURL = ((JarURLConnection) url.openConnection()).getJarFileURL();
+ String file = fileURL.getFile();
+ String parentFile = new File(file).getParent();
+ parentFile = parentFile.replace(File.separatorChar, '/');
+ if (parentFile.charAt(0) != '/') {
+ parentFile = "/" + parentFile; //$NON-NLS-1$
+ }
+ URL parentURL = new URL(fileURL.getProtocol(), fileURL
+ .getHost(), fileURL.getPort(), parentFile);
+ return parentURL;
+ }
+
+ public IndexFile(HashMap<String, ArrayList<URL>> map) {
+ this.map = map;
+ }
+
+ ArrayList<URL> get(String name){
+ return map.get(name);
+ }
+ }
+
+ class URLHandler {
+ URL url;
+ URL codeSourceUrl;
+
+ public URLHandler(URL url) {
+ this.url = url;
+ this.codeSourceUrl=url;
+ }
+
+ void findResources(String name, ArrayList<URL> resources) {
+ URL res = findResource(name);
+ if (res != null && !resources.contains(res)) {
+ resources.add(res);
+ }
+ }
+
+ Class<?> findClass(String packageName,String name, String origName) {
+ URL resURL = targetURL(url, name);
+ if(resURL !=null) {
+ try {
+ InputStream is = resURL.openStream();
+ return createClass(is,packageName,origName);
+ } catch (IOException e) {
+ }
+ }
+ return null;
+ }
+
+
+ Class<?> createClass(InputStream is, String packageName, String origName) {
+ if(is==null) {
+ return null;
+ }
+ byte[] clBuf = null;
+ try {
+ clBuf = getBytes(is);
+ } catch (IOException e) {
+ return null;
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ if (packageName != null) {
+ String packageDotName = packageName.replace('/','.');
+ Package packageObj = getPackage(packageDotName);
+ if (packageObj == null) {
+ definePackage(packageDotName, null, null,
+ null, null, null, null, null);
+ } else {
+ if (packageObj.isSealed()) {
+ throw new SecurityException(Msg
+ .getString("K004c")); //$NON-NLS-1$
+ }
+ }
+ }
+ return defineClass(origName, clBuf, 0, clBuf.length, new CodeSource(codeSourceUrl, (Certificate[])null));
+ }
+
+ URL findResource(String name) {
+ URL resURL = targetURL(url, name);
+ if (resURL!=null) {
+ try {
+ URLConnection uc = resURL.openConnection();
+ uc.getInputStream().close();
+ // HTTP can return a stream on a non-existent file
+ // So check for the return code;
+ if (!resURL.getProtocol().equals("http")) { //$NON-NLS-1$
+ return resURL;
+ }
+ int code;
+ if ((code = ((HttpURLConnection) uc).getResponseCode()) >= 200
+ && code < 300) {
+ return resURL;
+ }
+ } catch (SecurityException e) {
+ return null;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ URL targetURL(URL base, String name) {
+ try {
+ String file = base.getFile() + URIEncoderDecoder.quoteIllegal(name,
+ "/@" + URI.someLegal);
+
+ return new URL(base.getProtocol(), base.getHost(), base.getPort(),
+ file, null);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ }
+
+ }
+
+ class URLJarHandler extends URLHandler{
+ JarFile jf;
+ String prefixName;
+ IndexFile index = null;
+ Map<URL,URLHandler> subHandlers = new HashMap<URL, URLHandler>();
+
+ public URLJarHandler(URL url, URL jarURL, JarFile jf,String prefixName) {
+ super(url);
+ this.jf=jf;
+ this.prefixName=prefixName;
+ this.codeSourceUrl=jarURL;
+ JarEntry je = jf.getJarEntry("META-INF/INDEX.LIST"); //$NON-NLS-1$
+ if (je != null) {
+ index = IndexFile.readIndexFile(jf,je,url);
+ }
+ }
+
+ public URLJarHandler(URL url, URL jarURL, JarFile jf,String prefixName,IndexFile index) {
+ super(url);
+ this.jf=jf;
+ this.prefixName=prefixName;
+ this.index = index;
+ this.codeSourceUrl=jarURL;
+ }
+
+ IndexFile getIndex() {
+ return index;
+ }
+
+ void findResources(String name, ArrayList<URL> resources) {
+ URL res = findResourceInOwn(name);
+ if (res != null && !resources.contains(res)) {
+ resources.add(res);
+ }
+ if(index!=null) {
+ int pos = name.lastIndexOf("/"); //$NON-NLS-1$
+ // only keep the directory part of the resource
+ // as index.list only keeps track of directories and root files
+ String indexedName = (pos > 0) ? name.substring(0, pos) : name;
+ ArrayList<URL> urls = index.get(indexedName);
+ if(urls!=null) {
+ for(URL url : urls) {
+ URLHandler h = getSubHandler(url);
+ if(h != null) {
+ h.findResources(name,resources);
+ }
+ }
+ }
+ }
+
+ }
+
+ Class<?> findClass(String packageName,String name,String origName) {
+ String entryName = prefixName + name;
+ JarEntry entry = jf.getJarEntry(entryName);
+ if (entry != null) {
+ /**
+ * Avoid recursive load class, especially the class
+ * is an implementation class of security provider
+ * and the jar is signed.
+ */
+ try {
+ Manifest manifest = jf.getManifest();
+ return createClass(entry,manifest,packageName,origName);
+ } catch (IOException e) {
+ }
+ }
+ if(index!=null) {
+ ArrayList<URL> urls;
+ if(packageName==null) {
+ urls = index.get(name);
+ }else {
+ urls = index.get(packageName);
+ }
+ if(urls!=null) {
+ for(URL url : urls) {
+ URLHandler h = getSubHandler(url);
+ if(h != null) {
+ Class<?> res = h.findClass(packageName,name,origName);
+ if(res!=null) {
+ return res;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private Class<?> createClass(JarEntry entry, Manifest manifest, String packageName, String origName) {
+ InputStream is = null;
+ byte[] clBuf = null;
+ try {
+ is = jf.getInputStream(entry);
+ clBuf = getBytes(is);
+ } catch (IOException e) {
+ return null;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ if (packageName != null) {
+ String packageDotName = packageName.replace('/', '.');
+ Package packageObj = getPackage(packageDotName);
+ if (packageObj == null) {
+ if (manifest != null) {
+ definePackage(packageDotName, manifest,
+ codeSourceUrl);
+ } else {
+ definePackage(packageDotName, null, null,
+ null, null, null, null, null);
+ }
+ } else {
+ boolean exception = false;
+ if (manifest != null) {
+ if (isSealed(manifest, packageName + "/")) {
+ exception = !packageObj
+ .isSealed(codeSourceUrl);
+ }
+ } else {
+ exception = packageObj.isSealed();
+ }
+ if (exception) {
+ throw new SecurityException(Msg
+ .getString("K004c")); //$NON-NLS-1$
+ }
+ }
+ }
+ CodeSource codeS = new CodeSource(codeSourceUrl, entry.getCertificates());
+ return defineClass(origName, clBuf, 0, clBuf.length, codeS);
+ }
+
+ URL findResourceInOwn(String name) {
+ String entryName = prefixName + name;
+ if (jf.getEntry(entryName) != null) {
+ return targetURL(url, name);
+ }
+ return null;
+ }
+
+ URL findResource(String name) {
+ URL res = findResourceInOwn(name);
+ if(res!=null) {
+ return res;
+ }
+ if(index!=null) {
+ int pos = name.lastIndexOf("/"); //$NON-NLS-1$
+ // only keep the directory part of the resource
+ // as index.list only keeps track of directories and root files
+ String indexedName = (pos > 0) ? name.substring(0, pos) : name;
+ ArrayList<URL> urls = index.get(indexedName);
+ if(urls!=null) {
+ for(URL url : urls) {
+ URLHandler h = getSubHandler(url);
+ if(h != null) {
+ res = h.findResource(name);
+ if(res!=null) {
+ return res;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private synchronized URLHandler getSubHandler(URL url) {
+ URLHandler sub = subHandlers.get(url);
+ if(url!=null) {
+ return sub;
+ }
+ String protocol = url.getProtocol();
+ if (protocol.equals("jar")) { //$NON-NLS-1$
+ sub = createURLJarHandler(url);
+ } else if (protocol.equals("file")) { //$NON-NLS-1$
+ sub = createURLSubJarHandler(url);
+ } else {
+ sub = createURLHandler(url);
+ }
+ if(sub!=null) {
+ subHandlers.put(url,sub);
+ }
+ return sub;
+ }
+
+ private URLHandler createURLSubJarHandler(URL url) {
+ String prefixName;
+ String file = url.getFile();
+ if (url.getFile().endsWith("!/")) { //$NON-NLS-1$
+ prefixName = "";
+ } else {
+ int sepIdx = file.lastIndexOf("!/"); //$NON-NLS-1$
+ if (sepIdx == -1) {
+ // Invalid URL, don't look here again
+ return null;
+ }
+ sepIdx += 2;
+ prefixName = file.substring(sepIdx);
+ }
+ try {
+ URL jarURL = ((JarURLConnection) url
+ .openConnection()).getJarFileURL();
+ JarURLConnection juc = (JarURLConnection) new URL(
+ "jar", "", //$NON-NLS-1$ //$NON-NLS-2$
+ jarURL.toExternalForm() + "!/").openConnection(); //$NON-NLS-1$
+ JarFile jf = juc.getJarFile();
+ URLJarHandler jarH = new URLJarHandler(url,jarURL,jf,prefixName,null);
+ // TODO : to think what we should do with indexes & manifest.class file here
+ return jarH;
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+ }
+
+ class URLFileHandler extends URLHandler{
+ private String prefix;
+
+ public URLFileHandler(URL url) {
+ super(url);
+ String baseFile = url.getFile();
+ String host = url.getHost();
+ int hostLength = 0;
+ if (host != null) {
+ hostLength = host.length();
+ }
+ StringBuilder buf = new StringBuilder(2 + hostLength
+ + baseFile.length());
+ if (hostLength > 0) {
+ buf.append("//").append(host); //$NON-NLS-1$
+ }
+ // baseFile always ends with '/'
+ buf.append(baseFile);
+ prefix = buf.toString();
+ }
+
+ Class<?> findClass(String packageName,String name,String origName) {
+ String filename = prefix+name;
+ try {
+ filename = URLDecoder.decode(filename, "UTF-8"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+
+ File file = new File(filename);
+ if (file.exists()) {
+ try {
+ InputStream is = new FileInputStream(file);
+ return createClass(is,packageName,origName);
+ } catch (FileNotFoundException e) {
+ }
+ }
+ return null;
+ }
+
+ URL findResource(String name) {
+ int idx =0;
+ // Do not create a UNC path, i.e. \\host
+ while (idx<name.length() && ((name.charAt(idx)=='/') //$NON-NLS-1$
+ || (name.charAt(idx)=='\\') )) { //$NON-NLS-1$
+ idx++;
+ }
+ if(idx>0) {
+ name = name.substring(idx);
+ }
+ String filename = prefix+name;
+ try {
+ filename = URLDecoder.decode(filename, "UTF-8"); //$NON-NLS-1$
+ } catch (IllegalArgumentException e) {
+ return null;
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ if (new File(filename).exists()) {
+ return targetURL(url, name);
+ }
+ return null;
+ }
+
+ }
+
+
/**
* Constructs a new instance of this class. The newly created instance will
* have the system ClassLoader as its parent. URLs that end with "/" are
@@ -173,36 +636,13 @@
*/
protected void addURL(URL url) {
try {
- URL search = createSearchURL(url);
- urls = addURL(urls, search);
- orgUrls = addURL(orgUrls, url);
- synchronized (extensions) {
- extensions.put(search, null);
- }
+ originalUrls.add(url);
+ searchList.add(createSearchURL(url));
} catch (MalformedURLException e) {
}
}
/**
- * Returns an array with the given URL added to the given array.
- *
- * @param urlArray
- * java.net.URL[] the source array
- * @param url
- * java.net.URL the URL to be added
- * @return java.net.URL[] an array made of the given array and the new URL
- */
- URL[] addURL(URL[] urlArray, URL url) {
- URL[] newPath = new URL[urlArray.length + 1];
- System.arraycopy(urlArray, 0, newPath, 0, urlArray.length);
- newPath[urlArray.length] = url;
- Hashtable<String, URL[]>[] newIndexes = newHashtableArray(indexes.length + 1);
- System.arraycopy(indexes, 0, newIndexes, 0, indexes.length);
- indexes = newIndexes;
- return newPath;
- }
-
- /**
* Answers an enumeration of URLs that contain the specified resource.
*
* @return Enumeration the enumeration of URLs that contain the specified
@@ -217,196 +657,43 @@
if (name == null) {
return null;
}
- Vector<URL> result = AccessController.doPrivileged(
- new PrivilegedAction<Vector<URL>>() {
- public Vector<URL> run() {
- return findResources(urls, name, new Vector<URL>());
+ ArrayList<URL> result = AccessController.doPrivileged(
+ new PrivilegedAction<ArrayList<URL>>() {
+ public ArrayList<URL> run() {
+ ArrayList<URL> results = new ArrayList<URL>();
+ findResourcesImpl(name, results);
+ return results;
}
}, currentContext);
SecurityManager sm;
int length = result.size();
if (length > 0 && (sm = System.getSecurityManager()) != null) {
- Vector<URL> reduced = new Vector<URL>(length);
+ ArrayList<URL> reduced = new ArrayList<URL>(length);
for (int i = 0; i < length; i++) {
- URL url = result.elementAt(i);
+ URL url = result.get(i);
try {
sm.checkPermission(url.openConnection().getPermission());
- reduced.addElement(url);
+ reduced.add(url);
} catch (IOException e) {
} catch (SecurityException e) {
}
}
result = reduced;
}
- return result.elements();
+ return Collections.enumeration(result);
}
- /**
- * Answers a Vector of URLs among the given ones that contain the specified
- * resource.
- *
- * @return Vector the enumeration of URLs that contain the specified
- * resource.
- * @param searchURLs
- * java.net.URL[] the array to be searched
- * @param name
- * java.lang.String the name of the requested resource
- */
- Vector<URL> findResources(URL[] searchURLs, String name, Vector<URL> result) {
- boolean findInExtensions = searchURLs == urls;
- for (int i = 0; i < searchURLs.length; i++) {
- if (!invalidUrls.contains(searchURLs[i])) {
- URL[] search = new URL[] { searchURLs[i] };
- URL res = findResourceImpl(search, name);
- if (!invalidUrls.contains(search[0])) {
- if (res != null && !result.contains(res)) {
- result.addElement(res);
- }
- if (findInExtensions) {
- findInExtensions(explore(searchURLs[i], i), name, i,
- result, false);
- }
- }
+ void findResourcesImpl(String name, ArrayList<URL> result) {
+ int n = 0;
+ while(true) {
+ URLHandler handler = getHandler(n++);
+ if(handler == null) {
+ break;
}
+ handler.findResources(name,result);
}
- return result;
}
- /**
- * Answers an Object[] containing a Class, a URL, and a Vector of URLs, 2 of
- * which are null, according to the caller, which is identified by the int
- * type.
- *
- * @return Object[] a 3-element array : {Class, URL, Vector}. The non-null
- * element contains the resource(s) found, which are searched in in
- * indexes[i].
- * @param i
- * int the index of 'indexes' array to use.
- * @param name
- * String the resource to look for : either a resource or a
- * class.
- * @param resources
- * boolean indicates that a Vector of URL should be returned as
- * the non-null element in Object[].
- * @param url
- * boolean if true a URL should be returned as the non null
- * element, if false a Class should be returned.
- */
- Object findInIndex(int i, String name, Vector<URL> resources, boolean url) {
- Hashtable<String, URL[]> index = indexes[i];
- if (index != null) {
- int pos = name.lastIndexOf("/"); //$NON-NLS-1$
- // only keep the directory part of the resource
- // as index.list only keeps track of directories and root files
- String indexedName = (pos > 0) ? name.substring(0, pos) : name;
- URL[] jarURLs;
- if (resources != null) {
- jarURLs = index.get(indexedName);
- if (jarURLs != null) {
- findResources(jarURLs, name, resources);
- }
- } else if (url) {
- jarURLs = index.get(indexedName);
- if (jarURLs != null) {
- return findResourceImpl(jarURLs, name);
- }
- } else {
- String clsName = name;
- String partialName = clsName.replace('.', '/');
- int position;
- if ((position = partialName.lastIndexOf('/')) != -1) {
- String packageName = partialName.substring(0, position);
- jarURLs = index.get(packageName);
- } else {
- String className = partialName.substring(0, partialName
- .length())
- + ".class"; //$NON-NLS-1$
- jarURLs = index.get(className);
- }
- if (jarURLs != null) {
- Class<?> c = findClassImpl(jarURLs, clsName);
- // InvalidJarException is thrown when a mapping for a class
- // is not valid, i.e. we can't find the class by following
- // the mapping.
- if (c == null) {
- throw new InvalidJarIndexException();
- }
- return c;
- }
- }
- }
- return null;
- }
-
- /**
- * Answers an Object[] containing a Class, a URL, and a Vector of URLs, 2 of
- * which are null, according to the caller, which is identified by the int
- * type.
- *
- * @return Object[] a 3-element array : {Class, URL, Vector}. The non-null
- * element contains the resource(s) found, which are searched in
- * newExtensions.
- * @param newExtensions
- * URL[] the URLs to look in for.
- * @param name
- * String the resource to look for : either a resource or a
- * class.
- * @param i
- * int the index of 'indexes' array to use.
- * @param resources
- * boolean indicates that a Vector of URL should be returned as
- * the non-null element in Object[].
- * @param url
- * boolean if true a URL should be returned as the non null
- * element, if false a Class should be returned.
- */
- Object findInExtensions(URL[] newExtensions, String name, int i,
- Vector<URL> resources, boolean url) {
- if (newExtensions != null) {
- for (int k = 0; k < newExtensions.length; k++) {
- if (newExtensions[k] != null) {
- URL[] search = new URL[] { newExtensions[k] };
- if (resources != null) {
- URL res = findResourceImpl(search, name);
- if (!invalidUrls.contains(search[0])) { // the URL does
- // not exist
- if (res != null && !resources.contains(res)) {
- resources.addElement(res);
- }
- findInExtensions(explore(newExtensions[k], i),
- name, i, resources, url);
- }
- } else {
- Object result;
- if (url) {
- result = findResourceImpl(search, name);
- } else {
- result = findClassImpl(search, name);
- }
- if (result != null) {
- return result;
- }
- if (!invalidUrls.contains(search[0])) { // the URL
- // exists
- result = findInExtensions(explore(newExtensions[k],
- i), name, i, null, url);
- if (result != null) {
- return result;
- }
- }
- }
- }
- }
- } else {
- try {
- return findInIndex(i, name, resources, url);
- } catch (InvalidJarIndexException ex) {
- // Ignore misleading/wrong jar index
- return null;
- }
- }
- return null;
- }
/**
* Converts an input stream into a byte array.
@@ -415,20 +702,10 @@
* @param is
* the input stream
*/
- private static byte[] getBytes(InputStream is, boolean readAvailable)
+ private static byte[] getBytes(InputStream is)
throws IOException {
- if (readAvailable) {
- byte[] buf = new byte[is.available()];
- is.read(buf, 0, buf.length);
- is.close();
- return buf;
- }
byte[] buf = new byte[4096];
- int size = is.available();
- if (size < 1024) {
- size = 1024;
- }
- ByteArrayOutputStream bos = new ByteArrayOutputStream(size);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(4096);
int count;
while ((count = is.read(buf)) > 0) {
bos.write(buf, 0, count);
@@ -492,7 +769,7 @@
* @return java.net.URL[]
*/
public URL[] getURLs() {
- return orgUrls.clone();
+ return originalUrls.toArray(new URL[originalUrls.size()]);
}
/**
@@ -588,20 +865,16 @@
// capture the context of the thread that creates this URLClassLoader
currentContext = AccessController.getContext();
int nbUrls = searchUrls.length;
- urls = new URL[nbUrls];
- orgUrls = new URL[nbUrls];
- // Search each jar for CLASS-PATH attribute in manifest
- extensions = new HashMap<URL, URL[]>(nbUrls * 2);
+ originalUrls = new ArrayList<URL>(nbUrls);
+ handlerList = new ArrayList<URLHandler>(nbUrls);
+ searchList = Collections.synchronizedList(new ArrayList<URL>(nbUrls));
for (int i = 0; i < nbUrls; i++) {
+ originalUrls.add(searchUrls[i]);
try {
- urls[i] = createSearchURL(searchUrls[i]);
- extensions.put(urls[i], null);
+ searchList.add(createSearchURL(searchUrls[i]));
} catch (MalformedURLException e) {
}
- orgUrls[i] = searchUrls[i];
}
- // Search each jar for META-INF/INDEX.LIST
- indexes = newHashtableArray(nbUrls);
}
/**
@@ -622,7 +895,7 @@
Class<?> cls = AccessController.doPrivileged(
new PrivilegedAction<Class<?>>() {
public Class<?> run() {
- return findClassImpl(urls, clsName);
+ return findClassImpl(clsName);
}
}, currentContext);
if (cls != null) {
@@ -672,7 +945,7 @@
}
URL result = AccessController.doPrivileged(new PrivilegedAction<URL>() {
public URL run() {
- return findResourceImpl(urls, name);
+ return findResourceImpl(name);
}
}, currentContext);
SecurityManager sm;
@@ -691,161 +964,107 @@
/**
* Answers a URL among the given ones referencing the specified resource or
* null if no resource could be found.
- *
+ *
* @return URL URL for the resource.
- * @param searchList
- * java.net.URL[] the array to be searched
* @param resName
* java.lang.String the name of the requested resource
*/
- URL findResourceImpl(URL[] searchList, String resName) {
- boolean findInExtensions = searchList == urls;
- int i = 0;
- while (i < searchList.length) {
- if (searchList[i] == null) {
- // KA024=One of urls is null
+ URL findResourceImpl(String resName) {
+ int n = 0;
+ while(true) {
+ URLHandler handler = getHandler(n++);
+ if(handler == null) {
+ break;
+ }
+ URL res = handler.findResource(resName);
+ if(res!=null) {
+ return res;
+ }
+ }
+ return null;
+ }
+
+ URLHandler getHandler(int num) {
+ if(num < handlerList.size()) {
+ return handlerList.get(num);
+ }
+ makeNewHandler();
+ if(num < handlerList.size()) {
+ return handlerList.get(num);
+ }
+ return null;
+ }
+
+ private synchronized void makeNewHandler() {
+ while(!searchList.isEmpty()) {
+ URL nextCandidate = searchList.remove(0);
+ if (nextCandidate == null) { // KA024=One of urls is null
throw new NullPointerException(Msg.getString("KA024")); //$NON-NLS-1$
- } else if (!invalidUrls.contains(searchList[i])) {
- JarFile jf = null;
- try {
- URL currentUrl = searchList[i];
- String protocol = currentUrl.getProtocol();
-
- if (protocol.equals("jar")) { //$NON-NLS-1$
- jf = resCache.get(currentUrl);
- if (jf == null) {
- if (invalidUrls.contains(currentUrl)) {
- continue;
- }
- // each jf should be found only once
- // so we do this job in the synchronized block
- synchronized (lock) {
- // Check the cache again in case another thread
- // updated it while we're waiting on lock
- jf = resCache.get(currentUrl);
- if (jf == null) {
- if (invalidUrls.contains(currentUrl)) {
- continue;
- }
- /*
- * If the connection for currentUrl or resURL is
- * used, getJarFile() will throw an exception if the
- * entry doesn't exist.
- */
- URL jarURL = ((JarURLConnection) currentUrl
- .openConnection()).getJarFileURL();
- try {
- JarURLConnection juc = (JarURLConnection) new URL(
- "jar", "", //$NON-NLS-1$ //$NON-NLS-2$
- jarURL.toExternalForm() + "!/").openConnection(); //$NON-NLS-1$
- jf = juc.getJarFile();
- resCache.put(currentUrl, jf);
- } catch (IOException e) {
- // Don't look for this jar file again
- invalidUrls.add(searchList[i]);
- throw e;
- }
- }
- }
- }
- String entryName;
- if (currentUrl.getFile().endsWith("!/")) { //$NON-NLS-1$
- entryName = resName;
- } else {
- String file = currentUrl.getFile();
- int sepIdx = file.lastIndexOf("!/"); //$NON-NLS-1$
- if (sepIdx == -1) {
- // Invalid URL, don't look here again
- invalidUrls.add(searchList[i]);
- continue;
- }
- sepIdx += 2;
- entryName = new StringBuffer(file.length() - sepIdx
- + resName.length()).append(
- file.substring(sepIdx)).append(resName)
- .toString();
- }
- if (jf.getEntry(entryName) != null) {
- return targetURL(currentUrl, resName);
- }
- } else if (protocol.equals("file")) { //$NON-NLS-1$
- String baseFile = currentUrl.getFile();
- String host = currentUrl.getHost();
- int hostLength = 0;
- if (host != null) {
- hostLength = host.length();
- }
- StringBuffer buf = new StringBuffer(2 + hostLength
- + baseFile.length() + resName.length());
- if (hostLength > 0) {
- buf.append("//").append(host); //$NON-NLS-1$
- }
- // baseFile always ends with '/'
- buf.append(baseFile);
- String fixedResName = resName;
- // Do not create a UNC path, i.e. \\host
- while (fixedResName.startsWith("/") //$NON-NLS-1$
- || fixedResName.startsWith("\\")) { //$NON-NLS-1$
- fixedResName = fixedResName.substring(1);
- }
- buf.append(fixedResName);
+ }
+ if(!handlerMap.containsKey(nextCandidate)) {
+ URLHandler result;
+ String protocol = nextCandidate.getProtocol();
+ if (protocol.equals("jar")) { //$NON-NLS-1$
+ result = createURLJarHandler(nextCandidate);
+ } else if (protocol.equals("file")) { //$NON-NLS-1$
+ result = createURLFileHandler(nextCandidate);
+ } else {
+ result = createURLHandler(nextCandidate);
+ }
+ if(result!=null) {
+ handlerMap.put(nextCandidate,result);
+ handlerList.add(result);
+ return;
+ }
+ }
+ }
+ }
- String filename = buf.toString();
-
- try {
- filename = URLDecoder.decode(filename, "UTF-8"); //$NON-NLS-1$
- } catch (IllegalArgumentException e) {
- return null;
- }
+ private URLHandler createURLHandler(URL url) {
+ return new URLHandler(url);
+ }
- if (new File(filename).exists()) {
- return targetURL(currentUrl, fixedResName);
- }
- } else {
- URL resURL = targetURL(currentUrl, resName);
- URLConnection uc = resURL.openConnection();
- try {
- uc.getInputStream().close();
- } catch (SecurityException e) {
- return null;
- }
- // HTTP can return a stream on a non-existent file
- // So check for the return code;
- if (!resURL.getProtocol().equals("http")) { //$NON-NLS-1$
- return resURL;
- }
- int code;
- if ((code = ((HttpURLConnection) uc).getResponseCode()) >= 200
- && code < 300) {
- return resURL;
+ private URLHandler createURLFileHandler(URL url) {
+ return new URLFileHandler(url);
+ }
+
+ private URLHandler createURLJarHandler(URL url) {
+ String prefixName;
+ String file = url.getFile();
+ if (url.getFile().endsWith("!/")) { //$NON-NLS-1$
+ prefixName = "";
+ } else {
+ int sepIdx = file.lastIndexOf("!/"); //$NON-NLS-1$
+ if (sepIdx == -1) {
+ // Invalid URL, don't look here again
+ return null;
+ }
+ sepIdx += 2;
+ prefixName = file.substring(sepIdx);
+ }
+ try {
+ URL jarURL = ((JarURLConnection) url
+ .openConnection()).getJarFileURL();
+ JarURLConnection juc = (JarURLConnection) new URL(
+ "jar", "", //$NON-NLS-1$ //$NON-NLS-2$
+ jarURL.toExternalForm() + "!/").openConnection(); //$NON-NLS-1$
+ JarFile jf = juc.getJarFile();
+ URLJarHandler jarH = new URLJarHandler(url,jarURL,jf,prefixName);
+ if(jarH.getIndex()==null) {
+ try {
+ Manifest manifest = jf.getManifest();
+ if(manifest!=null) {
+ String classpath = manifest.getMainAttributes().getValue(
+ Attributes.Name.CLASS_PATH);
+ if(classpath!=null) {
+ searchList.addAll(0,getInternalURLs(url, classpath));
}
}
- } catch (MalformedURLException e) {
- // Keep iterating through the URL list
} catch (IOException e) {
- } catch (SecurityException e) {
- }
- if ((jf != null) && findInExtensions) {
- if (indexes[i] != null) {
- try {
- URL result = (URL) findInIndex(i, resName, null,
- true);
- if (result != null) {
- return result;
- }
- } catch (InvalidJarIndexException ex) {
- // Ignore invalid/misleading JAR index file
- }
- } else {
- URL result = (URL) findInExtensions(explore(
- searchList[i], i), resName, i, null, true);
- if (result != null) {
- return result;
- }
- }
}
}
- ++i;
+ return jarH;
+ } catch (IOException e) {
}
return null;
}
@@ -942,17 +1161,17 @@
*
* @return URL[] the URLs contained in the string classpath.
*/
- private URL[] getInternalURLs(URL root, String classpath) {
+ private ArrayList<URL> getInternalURLs(URL root, String classpath) {
// Class-path attribute is composed of space-separated values.
StringTokenizer tokenizer = new java.util.StringTokenizer(classpath);
- Vector<URL> addedURLs = new Vector<URL>();
+ ArrayList<URL> addedURLs = new ArrayList<URL>();
String file = root.getFile();
int jarIndex = file.lastIndexOf("!/") - 1; //$NON-NLS-1$
int index = file.lastIndexOf("/", jarIndex) + 1; //$NON-NLS-1$
if (index == 0) {
- index = file.lastIndexOf(
- System.getProperty("file.separator"), jarIndex) + 1; //$NON-NLS-1$
- }
+ index = file.lastIndexOf(
+ System.getProperty("file.separator"), jarIndex) + 1; //$NON-NLS-1$
+ }
file = file.substring(0, index);
String protocol = root.getProtocol();
String host = root.getHost();
@@ -963,381 +1182,40 @@
try {
URL newURL = new URL(protocol, host, port, file + element
+ "!/"); //$NON-NLS-1$
- synchronized (extensions) {
- if (!extensions.containsKey(newURL)) {
- extensions.put(newURL, null);
- addedURLs.add(newURL);
- }
- }
+ addedURLs.add(newURL);
} catch (MalformedURLException e) {
// Nothing is added
}
}
}
- URL[] newURLs = addedURLs.toArray(new URL[] {});
- return newURLs;
+ return addedURLs;
}
- /**
- * @param in
- * InputStream the stream to read lines from
- * @return List a list of String lines
- */
- private List<String> readLines(InputStream in) throws IOException {
- byte[] buff = new byte[144];
- List<String> lines = new ArrayList<String>();
- int pos = 0;
- int next;
- while ((next = in.read()) != -1) {
- if (next == '\n') {
- lines.add(new String(buff, 0, pos, "UTF8")); //$NON-NLS-1$
- pos = 0;
- continue;
- }
- if (next == '\r') {
- lines.add(new String(buff, 0, pos, "UTF8")); //$NON-NLS-1$
- pos = 0;
- if ((next = in.read()) == '\n') {
- continue;
- }
- }
- if (pos == buff.length) {
- byte[] newBuf = new byte[buff.length * 2];
- System.arraycopy(buff, 0, newBuf, 0, buff.length);
- buff = newBuf;
- }
- buff[pos++] = (byte) next;
- }
- if (pos > 0) {
- lines.add(new String(buff, 0, pos, "UTF8")); //$NON-NLS-1$
- }
- return lines;
- }
-
- private URL targetURL(URL base, String name) throws MalformedURLException {
- try {
- String file = base.getFile() + URIEncoderDecoder.quoteIllegal(name,
- "/@" + URI.someLegal);
-
- return new URL(base.getProtocol(), base.getHost(), base.getPort(),
- file, null);
- } catch (UnsupportedEncodingException e) {
- MalformedURLException e2 = new MalformedURLException(e.toString());
-
- e2.initCause(e);
- throw e2;
- }
-
- }
-
- /**
- * @param searchURLs
- * java.net.URL[] the URLs to search in
- * @param clsName
- * java.lang.String the class name to be found
- * @return Class the class found or null if not found
- */
- Class<?> findClassImpl(URL[] searchURLs, String clsName) {
- boolean readAvailable = false;
- boolean findInExtensions = searchURLs == urls;
- final String name = new StringBuffer(clsName.replace('.', '/')).append(
- ".class").toString(); //$NON-NLS-1$
- for (int i = 0; i < searchURLs.length; i++) {
- if (searchURLs[i] == null) {
- // KA024=One of urls is null
- throw new NullPointerException(Msg.getString("KA024")); //$NON-NLS-1$
- } else if (!invalidUrls.contains(searchURLs[i])) {
- Manifest manifest = null;
- InputStream is = null;
- JarEntry entry = null;
- JarFile jf = null;
- byte[] clBuf = null;
- try {
- URL thisURL = searchURLs[i];
- String protocol = thisURL.getProtocol();
- if (protocol.equals("jar")) { //$NON-NLS-1$
- jf = resCache.get(thisURL);
- if ((jf == null) && (!invalidUrls.contains(thisURL))) {
- synchronized (lock) {
- // Check the cache again in case another thread updated it
- // updated it while we're waiting on lock
- jf = resCache.get(thisURL);
- if (jf == null) {
- if (invalidUrls.contains(thisURL)) {
- continue;
- }
- // If the connection for testURL or thisURL is used,
- // getJarFile() will throw an exception if the entry
- // doesn't exist.
- URL jarURL = ((JarURLConnection) thisURL
- .openConnection()).getJarFileURL();
- try {
- JarURLConnection juc = (JarURLConnection) new URL(
- "jar", "", jarURL.toExternalForm() + "!/") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- .openConnection();
- jf = juc.getJarFile();
- resCache.put(thisURL, jf);
- } catch (IOException e) {
- // Don't look for this jar file again
- invalidUrls.add(searchURLs[i]);
- throw e;
- }
- }
- }
- }
- if (thisURL.getFile().endsWith("!/")) { //$NON-NLS-1$
- entry = jf.getJarEntry(name);
- } else {
- String file = thisURL.getFile();
- int sepIdx = file.lastIndexOf("!/"); //$NON-NLS-1$
- if (sepIdx == -1) {
- // Invalid URL, don't look here again
- invalidUrls.add(searchURLs[i]);
- continue;
- }
- sepIdx += 2;
- String entryName = new StringBuffer(file.length()
- - sepIdx + name.length()).append(
- file.substring(sepIdx)).append(name)
- .toString();
- entry = jf.getJarEntry(entryName);
- }
- if (entry != null) {
- readAvailable = true;
- is = jf.getInputStream(entry);
- /**
- * Avoid recursive load class, especially the class
- * is an implementation class of security provider
- * and the jar is signed.
- */
- Class loadedClass = findLoadedClass(clsName);
- if (null != loadedClass) {
- is.close();
- return loadedClass;
- }
- manifest = jf.getManifest();
- }
- } else if (protocol.equals("file")) { //$NON-NLS-1$
- String filename = thisURL.getFile();
- String host = thisURL.getHost();
- if (host != null && host.length() > 0) {
- filename = new StringBuffer(host.length()
- + filename.length() + name.length() + 2)
- .append("//").append(host).append(filename) //$NON-NLS-1$
- .append(name).toString();
- } else {
- filename = new StringBuffer(filename.length()
- + name.length()).append(filename).append(
- name).toString();
- }
-
- // Just return null for caller to throw
- // ClassNotFoundException.
- try {
- filename = URLDecoder.decode(filename, "UTF-8"); //$NON-NLS-1$
- } catch (IllegalArgumentException e) {
- return null;
- }
-
- File file = new File(filename);
- // Don't throw exceptions for speed
- if (file.exists()) {
- is = new FileInputStream(file);
- readAvailable = true;
- } else {
- continue;
- }
- } else {
- is = targetURL(thisURL, name).openStream();
- }
- } catch (MalformedURLException e) {
- // Keep iterating through the URL list
- } catch (IOException e) {
- }
- if (is != null) {
- URL codeSourceURL = null;
- Certificate[] certificates = null;
- CodeSource codeS = null;
- try {
- codeSourceURL = findInExtensions ? orgUrls[i]
- : ((JarURLConnection) searchURLs[i]
- .openConnection()).getJarFileURL();
- } catch (IOException e) {
- codeSourceURL = searchURLs[i];
- }
- if (is != null) {
- try {
- clBuf = getBytes(is, readAvailable);
- is.close();
- } catch (IOException e) {
- return null;
- }
- }
- if (entry != null) {
- certificates = entry.getCertificates();
- }
- // Use the original URL, not the possible jar URL
- codeS = new CodeSource(codeSourceURL, certificates);
- int dotIndex = clsName.lastIndexOf("."); //$NON-NLS-1$
- if (dotIndex != -1) {
- String packageName = clsName.substring(0, dotIndex);
- synchronized (this) {
- Package packageObj = getPackage(packageName);
- if (packageObj == null) {
- if (manifest != null) {
- definePackage(packageName, manifest,
- codeSourceURL);
- } else {
- definePackage(packageName, null, null,
- null, null, null, null, null);
- }
- } else {
- boolean exception = false;
- if (manifest != null) {
- String dirName = packageName.replace('.',
- '/')
- + "/"; //$NON-NLS-1$
- if (isSealed(manifest, dirName)) {
- exception = !packageObj
- .isSealed(codeSourceURL);
- }
- } else {
- exception = packageObj.isSealed();
- }
- if (exception) {
- throw new SecurityException(Msg
- .getString("K004c")); //$NON-NLS-1$
- }
- }
- }
- }
- return defineClass(clsName, clBuf, 0, clBuf.length, codeS);
- }
- if ((jf != null) && findInExtensions) {
- if (indexes[i] != null) {
- try {
- Class<?> c = (Class<?>) findInIndex(i, clsName,
- null, false);
- if (c != null) {
- return c;
- }
- } catch (InvalidJarIndexException ex) {
- // Ignore misleading/wrong jar index
- }
- } else {
- Class<?> c = (Class<?>) findInExtensions(explore(
- searchURLs[i], i), clsName, i, null, false);
- if (c != null) {
- return c;
- }
- }
- }
+ Class<?> findClassImpl(String className) {
+ Class loadedClass = findLoadedClass(className);
+ if (null != loadedClass) {
+ return loadedClass;
+ }
+ String partialName = className.replace('.', '/');
+ final String classFileName = new StringBuilder(partialName ).append(".class").toString(); //$NON-NLS-1$
+ String packageName = null;
+ int position = partialName.lastIndexOf('/');
+ if ((position = partialName.lastIndexOf('/')) != -1) {
+ packageName = partialName.substring(0, position);
+ }
+ int n = 0;
+ while(true) {
+ URLHandler handler = getHandler(n++);
+ if(handler == null) {
+ break;
+ }
+ Class<?> res = handler.findClass(packageName,classFileName,className);
+ if(res!=null) {
+ return res;
}
}
return null;
- }
- /**
- * @param url
- * URL the URL to explore
- * @param indexNumber
- * int the index in extensions to consider
- *
- * @return URL[] the URLs of bundled extensions that have been found (i.e.
- * the URL of jar files in the class-path attribute), or null if
- * none. if an INDEX.LIST has been found, an empty array is returned
- */
- URL[] explore(URL url, int indexNumber) {
- URL[] internal;
- synchronized (extensions) {
- internal = extensions.get(url);
- }
- if (internal != null) {
- return internal;
- }
- if (indexes[indexNumber] != null) {
- return null;
- }
-
- if (!url.getProtocol().equals("jar")) { //$NON-NLS-1$
- return null;
- }
-
- JarFile jf = resCache.get(url);
- // Add mappings from INDEX.LIST
- ZipEntry ze = jf.getEntry("META-INF/INDEX.LIST"); //$NON-NLS-1$
- if (ze != null) {
- if (url.equals(urls[indexNumber])) {
- try {
- Hashtable<String, URL[]> index = new Hashtable<String, URL[]>(
- 15);
- InputStream indexIS = jf.getInputStream(ze);
- List<String> lines = readLines(indexIS);
- indexIS.close();
- ListIterator<String> iterator = lines.listIterator();
- // Ignore the 2 first lines (index version)
- iterator.next();
- iterator.next();
- // Add mappings from resource to jar file
- URL fileURL = ((JarURLConnection) url.openConnection())
- .getJarFileURL();
- String file = fileURL.getFile();
- String parentFile = new File(file).getParent();
- parentFile = parentFile.replace(File.separatorChar, '/');
- if (parentFile.charAt(0) != '/') {
- parentFile = "/" + parentFile; //$NON-NLS-1$
- }
- URL parentURL = new URL(fileURL.getProtocol(), fileURL
- .getHost(), fileURL.getPort(), parentFile);
- while (iterator.hasNext()) {
- URL jar = new URL("jar:" //$NON-NLS-1$
- + parentURL.toExternalForm() + "/" //$NON-NLS-1$
- + iterator.next() + "!/"); //$NON-NLS-1$
- String resource = null;
- while (iterator.hasNext()
- && !(resource = iterator.next()).equals("")) { //$NON-NLS-1$
- if (index.containsKey(resource)) {
- URL[] jars = index.get(resource);
- URL[] newJars = new URL[jars.length + 1];
- System.arraycopy(jars, 0, newJars, 0,
- jars.length);
- newJars[jars.length] = jar;
- index.put(resource, newJars);
- } else {
- URL[] jars = { jar };
- index.put(resource, jars);
- }
- }
- }
- indexes[indexNumber] = index;
- } catch (MalformedURLException e) {
- // Ignore this jar's index
- } catch (IOException e) {
- // Ignore this jar's index
- }
- }
- return null;
- }
-
- // Returns URLs referenced by the class-path attribute.
- Manifest manifest = null;
- try {
- manifest = jf.getManifest();
- } catch (IOException e) {
- }
- String classpath = null;
- if (manifest != null) {
- classpath = manifest.getMainAttributes().getValue(
- Attributes.Name.CLASS_PATH);
- }
- synchronized (extensions) {
- internal = extensions.get(url);
- if (internal == null) {
- internal = classpath != null ? getInternalURLs(url, classpath)
- : NO_PATH;
- extensions.put(url, internal);
- }
- }
- return internal;
}
+
}
Modified: harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java?view=diff&rev=542426&r1=542425&r2=542426
==============================================================================
--- harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java (original)
+++ harmony/enhanced/classlib/trunk/modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java Mon May 28 23:34:30 2007
@@ -32,16 +32,15 @@
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.TreeSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipFile;
-import org.apache.harmony.kernel.vm.VM;
import org.apache.harmony.luni.util.Msg;
import org.apache.harmony.luni.util.Util;
@@ -54,9 +53,11 @@
*/
public class JarURLConnection extends java.net.JarURLConnection {
- static Hashtable<String, CacheEntry<? extends JarFile>> jarCache = new Hashtable<String, CacheEntry<?>>();
+ static HashMap<URL, JarFile> jarCache = new HashMap<URL, JarFile>();
- InputStream jarInput;
+ private URL jarFileURL;
+
+ private InputStream jarInput;
private JarFile jarFile;
@@ -64,83 +65,6 @@
private boolean closed;
- ReferenceQueue<JarFile> cacheQueue = new ReferenceQueue<JarFile>();
-
- static TreeSet<LRUKey> lru = new TreeSet<LRUKey>(
- new LRUComparator<LRUKey>());
-
- static int Limit;
-
- static {
- Limit = AccessController.doPrivileged(new PrivilegedAction<Integer>() {
- public Integer run() {
- return Integer.getInteger("jar.cacheSize", 500); //$NON-NLS-1$
- }
- });
- VM.closeJars();
- }
-
- static final class CacheEntry<T extends JarFile> extends WeakReference<T> {
- Object key;
-
- CacheEntry(T jar, String key, ReferenceQueue<JarFile> queue) {
- super(jar, queue);
- this.key = key;
- }
- }
-
- static final class LRUKey {
- JarFile jar;
-
- long ts;
-
- LRUKey(JarFile file, long time) {
- jar = file;
- ts = time;
- }
-
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(Object obj) {
- return (obj instanceof LRUKey) &&
- (jar == ((LRUKey) obj).jar);
- }
-
- @Override
- public int hashCode() {
- return jar.hashCode();
- }
- }
-
- static final class LRUComparator<T> implements Comparator<LRUKey> {
-
- LRUComparator() {
- }
-
- /**
- * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
- */
- public int compare(LRUKey o1, LRUKey o2) {
- if ((o1).ts > (o2).ts) {
- return 1;
- }
- return (o1).ts == (o2).ts ? 0 : -1;
- }
-
- /**
- * @param o1
- * an object to compare
- * @param o2
- * an object to compare
- * @return <code>true</code> if the objects are equal,
- * <code>false</code> otherwise.
- */
- public boolean equals(Object o1, Object o2) {
- return o1.equals(o2);
- }
- }
/**
* @param url
@@ -148,8 +72,10 @@
* @throws java.net.MalformedURLException
* if the URL is malformed
*/
- public JarURLConnection(java.net.URL url) throws MalformedURLException {
+ public JarURLConnection(java.net.URL url) throws MalformedURLException, IOException {
super(url);
+ jarFileURL = getJarFileURL();
+ jarFileURLConnection = jarFileURL.openConnection();
}
/**
@@ -157,10 +83,11 @@
*/
@Override
public void connect() throws IOException {
- jarFileURLConnection = getJarFileURL().openConnection();
- findJarFile(); // ensure the file can be found
- findJarEntry(); // ensure the entry, if any, can be found
- connected = true;
+ if (!connected) {
+ findJarFile(); // ensure the file can be found
+ findJarEntry(); // ensure the entry, if any, can be found
+ connected = true;
+ }
}
/**
@@ -174,9 +101,7 @@
*/
@Override
public JarFile getJarFile() throws IOException {
- if (!connected) {
- connect();
- }
+ connect();
return jarFile;
}
@@ -187,47 +112,47 @@
* if an IO error occurs while connecting to the resource.
*/
private void findJarFile() throws IOException {
- URL jarFileURL = getJarFileURL();
- if (jarFileURL.getProtocol().equals("file")) { //$NON-NLS-1$
- String fileName = jarFileURL.getFile();
- if(!new File(Util.decode(fileName,false)).exists()){
- // KA026=JAR entry {0} not found in {1}
- throw new FileNotFoundException(Msg.getString("KA026", //$NON-NLS-1$
- getEntryName(), fileName));
- }
- String host = jarFileURL.getHost();
- if (host != null && host.length() > 0) {
- fileName = "//" + host + fileName; //$NON-NLS-1$
+ JarFile jar = null;
+ if (getUseCaches()) {
+ synchronized(jarCache){
+ jarFile = jarCache.get(jarFileURL);
+ }
+ if (jarFile == null) {
+ jar = openJarFile();
+ synchronized(jarCache){
+ jarFile = jarCache.get(jarFileURL);
+ if (jarFile == null){
+ jarCache.put(jarFileURL, jar);
+ jarFile = jar;
+ }else{
+ jar.close();
+ }
+ }
}
- jarFile = openJarFile(fileName, fileName, false);
- return;
+ }else{
+ jarFile = openJarFile();
}
- final String externalForm = jarFileURLConnection.getURL()
- .toExternalForm();
- jarFile = AccessController
- .doPrivileged(new PrivilegedAction<JarFile>() {
- public JarFile run() {
- try {
- return openJarFile(null, externalForm, false);
- } catch (IOException e) {
- return null;
- }
- }
- });
- if (jarFile != null) {
- return;
+ if (jarFile == null) {
+ throw new IOException();
}
+ }
- // Build a temp jar file
- final InputStream is = jarFileURLConnection.getInputStream();
- try {
- jarFile = AccessController
+ JarFile openJarFile() throws IOException {
+ JarFile jar = null;
+ if (jarFileURL.getProtocol().equals("file")) { //$NON-NLS-1$
+ jar = new JarFile(new File(Util.decode(jarFileURL.getFile(), false)),
+ true, ZipFile.OPEN_READ);
+ } else{
+ final InputStream is = jarFileURL.openConnection().getInputStream();
+ try {
+ jar = AccessController
.doPrivileged(new PrivilegedAction<JarFile>() {
public JarFile run() {
try {
File tempJar = File.createTempFile("hyjar_", //$NON-NLS-1$
".tmp", null); //$NON-NLS-1$
+ tempJar.deleteOnExit();
FileOutputStream fos = new FileOutputStream(
tempJar);
byte[] buf = new byte[4096];
@@ -236,62 +161,18 @@
fos.write(buf, 0, nbytes);
}
fos.close();
- String path = tempJar.getPath();
- return openJarFile(path, externalForm, true);
+ return new JarFile(tempJar,
+ true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
} catch (IOException e) {
return null;
}
}
});
- } finally {
- is.close();
- }
- if (jarFile == null) {
- throw new IOException();
- }
- }
-
- JarFile openJarFile(String fileString, String key, boolean temp)
- throws IOException {
-
- JarFile jar = null;
- if (useCaches) {
- CacheEntry<? extends JarFile> entry;
- while ((entry = (CacheEntry<? extends JarFile>) cacheQueue.poll()) != null) {
- jarCache.remove(entry.key);
- }
- entry = jarCache.get(key);
- if (entry != null) {
- jar = entry.get();
+ } finally {
+ if (is != null) is.close();
}
- if (jar == null && fileString != null) {
- int flags = ZipFile.OPEN_READ
- + (temp ? ZipFile.OPEN_DELETE : 0);
- jar = new JarFile(new File(Util.decode(fileString, false)),
- true, flags);
- jarCache
- .put(key, new CacheEntry<JarFile>(jar, key, cacheQueue));
- } else {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkPermission(getPermission());
- }
- if (temp) {
- lru.remove(new LRUKey(jar, 0));
- }
- }
- } else if (fileString != null) {
- int flags = ZipFile.OPEN_READ + (temp ? ZipFile.OPEN_DELETE : 0);
- jar = new JarFile(new File(Util.decode(fileString, false)), true,
- flags);
}
- if (temp) {
- lru.add(new LRUKey(jar, new Date().getTime()));
- if (lru.size() > Limit) {
- lru.remove(lru.first());
- }
- }
return jar;
}
@@ -306,9 +187,7 @@
*/
@Override
public JarEntry getJarEntry() throws IOException {
- if (!connected) {
- connect();
- }
+ connect();
return jarEntry;
}
@@ -337,12 +216,11 @@
*/
@Override
public InputStream getInputStream() throws IOException {
+
if (closed) {
throw new IllegalStateException(Msg.getString("KA027"));
}
- if (!connected) {
- connect();
- }
+ connect();
if (jarInput != null) {
return jarInput;
}
@@ -375,16 +253,12 @@
cType = guessContentTypeFromName(entryName);
} else {
try {
- if (!connected) {
- connect();
- }
-
+ connect();
cType = jarFileURLConnection.getContentType();
} catch (IOException ioe) {
// Ignore
}
}
-
if (cType == null) {
cType = "content/unknown"; //$NON-NLS-1$
}
@@ -403,10 +277,7 @@
@Override
public int getContentLength() {
try {
- if (!connected) {
- connect();
- }
-
+ connect();
if (jarEntry == null) {
return jarFileURLConnection.getContentLength();
} else {
@@ -436,9 +307,7 @@
*/
@Override
public Object getContent() throws IOException {
- if (!connected) {
- connect();
- }
+ connect();
// if there is no Jar Entry, return a JarFile
if (jarEntry == null) {
return jarFile;
@@ -457,30 +326,50 @@
* thrown when an IO exception occurs while creating the
* permission.
*/
+
@Override
public Permission getPermission() throws IOException {
- if (jarFileURLConnection != null) {
- return jarFileURLConnection.getPermission();
- }
- return getJarFileURL().openConnection().getPermission();
+ return jarFileURLConnection.getPermission();
+ }
+
+ @Override
+ public boolean getUseCaches() {
+ return jarFileURLConnection.getUseCaches();
+ }
+
+ @Override
+ public void setUseCaches(boolean usecaches) {
+ jarFileURLConnection.setUseCaches(usecaches);
+ }
+
+ @Override
+ public boolean getDefaultUseCaches() {
+ return jarFileURLConnection.getDefaultUseCaches();
+ }
+
+ @Override
+ public void setDefaultUseCaches(boolean defaultusecaches) {
+ jarFileURLConnection.setDefaultUseCaches(defaultusecaches);
}
/**
* Closes the cached files.
*/
public static void closeCachedFiles() {
- Enumeration<CacheEntry<? extends JarFile>> elemEnum = jarCache
- .elements();
- while (elemEnum.hasMoreElements()) {
- try {
- ZipFile zip = elemEnum.nextElement().get();
- if (zip != null) {
- zip.close();
+ Set<Map.Entry<URL, JarFile>> s = jarCache.entrySet();
+ synchronized(jarCache){
+ Iterator<Map.Entry<URL, JarFile>> i = s.iterator();
+ while(i.hasNext()){
+ try {
+ ZipFile zip = i.next().getValue();
+ if (zip != null) {
+ zip.close();
+ }
+ } catch (IOException e) {
+ // Ignored
}
- } catch (IOException e) {
- // Ignored
}
- }
+ }
}
private class JarURLConnectionInputStream extends FilterInputStream {
@@ -497,7 +386,7 @@
@Override
public void close() throws IOException {
super.close();
- if (!useCaches) {
+ if (!getUseCaches()) {
closed = true;
jarFile.close();
}