--- /home/tromey/gnu/Nightly/classpath/classpath/gnu/java/net/protocol/jar/Connection.java 2004-01-05 02:21:24.000000000 -0700 +++ gnu/java/net/protocol/jar/Connection.java 2004-07-23 02:18:42.000000000 -0600 @@ -38,6 +38,8 @@ package gnu.java.net.protocol.jar; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; @@ -47,9 +49,15 @@ import java.net.ProtocolException; import java.net.URL; import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; import java.util.Hashtable; +import java.util.Locale; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.jar.JarInputStream; +import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** @@ -60,66 +68,21 @@ */ public final class Connection extends JarURLConnection { + private static Hashtable file_cache = new Hashtable(); + + /** + * HTTP-style DateFormat, used to format the last-modified header. + */ + private static SimpleDateFormat dateFormat + = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", + new Locale ("En", "Us", "Unix")); + private JarFile jar_file; - private JarEntry jar_entry; - private URL jar_url; - - public static class JarFileCache - { - private static Hashtable cache = new Hashtable(); - private static final int READBUFSIZE = 4*1024; - private static boolean is_trying = false; - - public static synchronized JarFile get (URL url) throws IOException - { - JarFile jf = (JarFile) cache.get (url); - - if (jf != null) - return jf; - - if (is_trying) - return null; - - try - { - is_trying = true; - - if ("file".equals (url.getProtocol())) - { - File f = new File (url.getFile()); - jf = new JarFile (f, true, ZipFile.OPEN_READ); - } - else - { - URLConnection urlconn = url.openConnection(); - InputStream is = urlconn.getInputStream(); - byte[] buf = new byte [READBUFSIZE]; - File f = File.createTempFile ("cache", "jar"); - FileOutputStream fos = new FileOutputStream (f); - int len = 0; - - while ((len = is.read (buf)) != -1) - { - fos.write (buf, 0, len); - } - - fos.close(); - // Always verify the Manifest, open read only and delete when done. - // XXX ZipFile.OPEN_DELETE not yet implemented. - // jf = new JarFile (f, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); - jf = new JarFile (f, true, ZipFile.OPEN_READ); - } - - cache.put (url, jf); - } - finally - { - is_trying = false; - } - - return jf; - } - } + + /** + * Cached JarURLConnection objects. + */ + static HashMap connectionCache = new HashMap(); protected Connection(URL url) throws MalformedURLException @@ -133,17 +96,23 @@ if (connected) return; - jar_url = getJarFileURL(); - jar_file = JarFileCache.get (jar_url); - String entry_name = getEntryName(); - - if (entry_name != null - && !entry_name.equals ("")) + if (getUseCaches()) { - jar_entry = (JarEntry) jar_file.getEntry (entry_name); + jarFileURLConnection = + (URLConnection) connectionCache.get(getJarFileURL()); - if(jar_entry == null) - throw new IOException ("No entry for " + entry_name + " exists."); + if (jarFileURLConnection == null) + { + jarFileURLConnection = getJarFileURL().openConnection(); + jarFileURLConnection.setUseCaches(true); + jarFileURLConnection.connect(); + connectionCache.put(getJarFileURL(), jarFileURLConnection); + } + } + else + { + jarFileURLConnection = getJarFileURL().openConnection(); + jarFileURLConnection.connect(); } connected = true; @@ -156,11 +125,61 @@ if (! doInput) throw new ProtocolException("Can't open InputStream if doInput is false"); + + if (getEntryName() == null) + { + // This is a JarURLConnection for the entire jar file. + + InputStream in = new BufferedInputStream + (jarFileURLConnection.getInputStream()); + return new JarInputStream(in); + } + + // Reaching this point, we're looking for an entry of a jar file. + + JarFile jarfile = null; + + try + { + jarfile = getJarFile (); + } + catch (IOException x) + { + /* ignore */ + } - if (jar_entry == null) - throw new IOException (jar_url + " couldn't be found."); - - return jar_file.getInputStream (jar_entry); + if (jarfile != null) + { + // this is the easy way... + ZipEntry entry = jarfile.getEntry(getEntryName()); + + if (entry != null) + return jarfile.getInputStream (entry); + else + return null; + } + else + { + // If the jar file is not local, ... + JarInputStream zis = new JarInputStream( + jarFileURLConnection.getInputStream ()); + + // This is hideous, we're doing a linear search... + for (ZipEntry entry = zis.getNextEntry(); + entry != null; + entry = zis.getNextEntry()) + { + if (getEntryName().equals(entry.getName())) + { + int size = (int) entry.getSize(); + byte[] data = new byte[size]; + zis.read (data, 0, size); + return new ByteArrayInputStream (data); + } + } + } + + return null; } public synchronized JarFile getJarFile() throws IOException @@ -171,14 +190,99 @@ if (! doInput) throw new ProtocolException("Can't open JarFile if doInput is false"); + if (jar_file != null) + return jar_file; + + URL jarFileURL = getJarFileURL(); + + if (jarFileURL.getProtocol().equals ("file") + && jarFileURL.getHost().equals ("")) + { + if (getUseCaches()) + { + jar_file = (JarFile) file_cache.get (jarFileURL); + if (jar_file == null) + { + jar_file = new JarFile (jarFileURL.getFile()); + file_cache.put (jarFileURL, jar_file); + } + } + else + jar_file = new JarFile (jarFileURL.getFile()); + } + else + { + URLConnection urlconn = jarFileURL.openConnection(); + InputStream is = urlconn.getInputStream(); + byte[] buf = new byte[4*1024]; + File f = File.createTempFile("cache", "jar"); + FileOutputStream fos = new FileOutputStream(f); + int len = 0; + while ((len = is.read(buf)) != -1) + fos.write(buf, 0, len); + fos.close(); + // Always verify the Manifest, open read only and delete when done. + // XXX ZipFile.OPEN_DELETE not yet implemented. + // jf = new JarFile(f, true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); + jar_file = new JarFile (f, true, ZipFile.OPEN_READ); + } + return jar_file; } + public String getHeaderField(String field) + { + try + { + if (!connected) + connect(); + + if (field.equals("content-type")) + return guessContentTypeFromName(getJarEntry().getName()); + else if (field.equals("content-length")) + return Long.toString(getJarEntry().getSize()); + else if (field.equals("last-modified")) + { + synchronized (dateFormat) + { + return dateFormat.format(new Date(getJarEntry().getTime())); + } + } + } + catch (IOException e) + { + // Fall through. + } + return null; + } + public int getContentLength() { if (!connected) return -1; - return (int) jar_entry.getSize(); + try + { + return (int) getJarEntry().getSize(); + } + catch (IOException e) + { + return -1; + } + } + + public long getLastModified() + { + if (!connected) + return -1; + + try + { + return getJarEntry().getTime(); + } + catch (IOException e) + { + return -1; + } } }