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();
             }