Index: modules/luni/src/main/java/java/net/JarURLConnection.java =================================================================== --- modules/luni/src/main/java/java/net/JarURLConnection.java (revision 541591) +++ modules/luni/src/main/java/java/net/JarURLConnection.java (working copy) @@ -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; } /** Index: modules/luni/src/main/java/java/net/URLClassLoader.java =================================================================== --- modules/luni/src/main/java/java/net/URLClassLoader.java (revision 541591) +++ modules/luni/src/main/java/java/net/URLClassLoader.java (working copy) @@ -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]; + ArrayList originalUrls; - @SuppressWarnings("unchecked") - private static Hashtable[] newHashtableArray(int size) { - return new Hashtable[size]; - } + List searchList; + ArrayList handlerList; + Map handlerMap = new HashMap(); - URL[] urls, orgUrls; - - Set invalidUrls = Collections.synchronizedSet(new HashSet()); - - private Map resCache = - Collections.synchronizedMap(new IdentityHashMap(32)); - - private Object lock = new Object(); - private URLStreamHandlerFactory factory; - HashMap extensions; - - Hashtable[] indexes; - private AccessControlContext currentContext; static class SubURLClassLoader extends URLClassLoader { @@ -130,6 +112,487 @@ } } + static class IndexFile { + + private HashMap> 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> pre_map = new HashMap>(); + // 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 list; + if(pre_map.containsKey(line)) { + list = pre_map.get(line); + } else { + list = new ArrayList(); + 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> map) { + this.map = map; + } + + ArrayList 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 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 subHandlers = new HashMap(); + + 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 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 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 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 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 (idx0) { + 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[] 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,218 +657,55 @@ if (name == null) { return null; } - Vector result = AccessController.doPrivileged( - new PrivilegedAction>() { - public Vector run() { - return findResources(urls, name, new Vector()); + ArrayList result = AccessController.doPrivileged( + new PrivilegedAction>() { + public ArrayList run() { + ArrayList results = new ArrayList(); + findResourcesImpl(name, results); + return results; } }, currentContext); SecurityManager sm; int length = result.size(); if (length > 0 && (sm = System.getSecurityManager()) != null) { - Vector reduced = new Vector(length); + ArrayList reduced = new ArrayList(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 findResources(URL[] searchURLs, String name, Vector 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 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 resources, boolean url) { - Hashtable 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 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. * * @return byte[] the byte array * @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(nbUrls * 2); + originalUrls = new ArrayList(nbUrls); + handlerList = new ArrayList(nbUrls); + searchList = Collections.synchronizedList(new ArrayList(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>() { public Class run() { - return findClassImpl(urls, clsName); + return findClassImpl(clsName); } }, currentContext); if (cls != null) { @@ -672,7 +945,7 @@ } URL result = AccessController.doPrivileged(new PrivilegedAction() { 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); + 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)); } - } 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; - } } - } 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 getInternalURLs(URL root, String classpath) { // Class-path attribute is composed of space-separated values. StringTokenizer tokenizer = new java.util.StringTokenizer(classpath); - Vector addedURLs = new Vector(); + ArrayList addedURLs = new ArrayList(); 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 readLines(InputStream in) throws IOException { - byte[] buff = new byte[144]; - List lines = new ArrayList(); - 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; + Class findClassImpl(String className) { + Class loadedClass = findLoadedClass(className); + if (null != loadedClass) { + return loadedClass; } - if (pos > 0) { - lines.add(new String(buff, 0, pos, "UTF8")); //$NON-NLS-1$ + 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); } - 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; - } - } - } + 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 index = new Hashtable( - 15); - InputStream indexIS = jf.getInputStream(ze); - List lines = readLines(indexIS); - indexIS.close(); - ListIterator 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; } + } Index: modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java =================================================================== --- modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java (revision 541591) +++ modules/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnection.java (working copy) @@ -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,102 +53,29 @@ */ public class JarURLConnection extends java.net.JarURLConnection { - static Hashtable> jarCache = new Hashtable>(); + static HashMap jarCache = new HashMap(); - InputStream jarInput; + private URL jarFileURL; + private InputStream jarInput; + private JarFile jarFile; private JarEntry jarEntry; private boolean closed; - ReferenceQueue cacheQueue = new ReferenceQueue(); - static TreeSet lru = new TreeSet( - new LRUComparator()); - - static int Limit; - - static { - Limit = AccessController.doPrivileged(new PrivilegedAction() { - public Integer run() { - return Integer.getInteger("jar.cacheSize", 500); //$NON-NLS-1$ - } - }); - VM.closeJars(); - } - - static final class CacheEntry extends WeakReference { - Object key; - - CacheEntry(T jar, String key, ReferenceQueue 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 implements Comparator { - - 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 true if the objects are equal, - * false otherwise. - */ - public boolean equals(Object o1, Object o2) { - return o1.equals(o2); - } - } - /** * @param url * the URL of the JAR * @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)); + JarFile jar = null; + if (getUseCaches()) { + synchronized(jarCache){ + jarFile = jarCache.get(jarFileURL); } - String host = jarFileURL.getHost(); - if (host != null && host.length() > 0) { - fileName = "//" + host + fileName; //$NON-NLS-1$ + 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() { - 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() { 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 entry; - while ((entry = (CacheEntry) cacheQueue.poll()) != null) { - jarCache.remove(entry.key); + } finally { + if (is != null) is.close(); } - entry = jarCache.get(key); - if (entry != null) { - jar = entry.get(); - } - 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(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> elemEnum = jarCache - .elements(); - while (elemEnum.hasMoreElements()) { - try { - ZipFile zip = elemEnum.nextElement().get(); - if (zip != null) { - zip.close(); + Set> s = jarCache.entrySet(); + synchronized(jarCache){ + Iterator> 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(); }