1 /* JarURLConnection.java -- Class for manipulating remote jar files
2 Copyright (C) 1998 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
43 import java.util.jar.*;
44 import java.util.zip.*;
46 import java.util.Vector;
47 import java.util.Hashtable;
48 import java.security.cert.Certificate;
51 * @author Kresten Krab Thorup <krab@gnu.org>
57 public abstract class JarURLConnection extends URLConnection
59 // three different ways to say the same thing
60 private final URL jarFileURL;
62 /** The connection to the jar file itself. A JarURLConnection
63 * can represent an entry in a jar file or an entire jar file. In
64 * either case this describes just the jar file itself. */
65 protected URLConnection jarFileURLConnection;
67 // If this is a connection to a jar file element this is set, otherwise null.
68 private final String element;
70 // Cached JarURLConnection's
71 static Hashtable conn_cache = new Hashtable();
73 public URL getJarFileURL ()
78 public String getEntryName ()
84 * Creates a new JarURLConnection
86 * @exception MalformedURLException If url is invalid
88 * @specnote This constructor is protected since JDK 1.4
90 protected JarURLConnection(URL url)
91 throws MalformedURLException
95 String spec = url.getFile();
96 int bang = spec.indexOf ("!/", 0);
98 throw new MalformedURLException (url + ": No `!/' in spec.");
100 // Extact the url for the jar itself.
101 jarFileURL = new URL(spec.substring (0, bang));
103 // Get the name of the element, if any.
104 element = (bang+2==spec.length() ? null : spec.substring (bang+2));
107 public synchronized void connect() throws IOException
109 // Call is ignored if already connected.
115 jarFileURLConnection = (URLConnection) conn_cache.get (jarFileURL);
117 if (jarFileURLConnection == null)
119 jarFileURLConnection = jarFileURL.openConnection ();
120 jarFileURLConnection.setUseCaches (true);
121 jarFileURLConnection.connect ();
122 conn_cache.put (jarFileURL, jarFileURLConnection);
127 jarFileURLConnection = jarFileURL.openConnection ();
128 jarFileURLConnection.connect ();
134 public InputStream getInputStream() throws IOException
140 throw new ProtocolException("Can't open InputStream if doInput is false");
144 // This is a JarURLConnection for the entire jar file.
146 InputStream jar_is = new BufferedInputStream(
147 jarFileURLConnection.getInputStream ());
148 return new JarInputStream(jar_is);
151 // Reaching this point, we're looking for an element of a jar file.
153 JarFile jarfile = null;
157 jarfile = getJarFile ();
159 catch (java.io.IOException x)
166 // this is the easy way...
167 ZipEntry entry = jarfile.getEntry(element);
169 return jarfile.getInputStream (entry);
175 // If the jar file is not local, ...
176 JarInputStream zis = new JarInputStream(
177 jarFileURLConnection.getInputStream ());
179 // This is hideous, we're doing a linear search...
180 for (ZipEntry ent = zis.getNextEntry ();
182 ent = zis.getNextEntry ())
184 if (element.equals (ent.getName ()))
186 int size = (int)ent.getSize();
187 byte[] data = new byte[size];
188 zis.read (data, 0, size);
189 return new ByteArrayInputStream (data);
198 * Return the JAR entry object for this connection, if any
200 * @exception IOException If an error occurs
202 public JarEntry getJarEntry () throws IOException
204 JarFile jarfile = null;
210 throw new ProtocolException("Can't open JarEntry if doInput is false");
214 jarfile = getJarFile ();
216 catch (IOException x)
223 JarInputStream zis = new JarInputStream(
224 jarFileURLConnection.getInputStream ());
226 // This is hideous, we're doing a linear search for the thing...
227 for (ZipEntry ent = zis.getNextEntry ();
229 ent = zis.getNextEntry ())
231 if (element.equals (ent.getName ()))
233 return new JarEntry (ent);
240 return jarfile.getJarEntry (element);
247 * Return the JAR file for this connection
249 * @exception IOException If an error occurs
251 public abstract JarFile getJarFile() throws IOException;
254 // Steal and borrow from protocol/file/Connection.java
256 private Hashtable hdrHash = new Hashtable();
257 private Vector hdrVec = new Vector();
258 private boolean gotHeaders = false;
260 // Override default method in URLConnection.
261 public String getHeaderField(String name)
267 catch (IOException x)
271 return (String) hdrHash.get(name.toLowerCase());
274 // Override default method in URLConnection.
275 public Map getHeaderFields()
281 catch (IOException x)
288 // Override default method in URLConnection.
289 public String getHeaderField(int n)
295 catch (IOException x)
299 if (n < hdrVec.size())
300 return getField((String) hdrVec.elementAt(n));
305 // Override default method in URLConnection.
306 public String getHeaderFieldKey(int n)
312 catch (IOException x)
316 if (n < hdrVec.size())
317 return getKey((String) hdrVec.elementAt(n));
322 private String getKey(String str)
326 int index = str.indexOf(':');
328 return str.substring(0, index);
333 private String getField(String str)
337 int index = str.indexOf(':');
339 return str.substring(index + 1).trim();
344 private void getHeaders() throws IOException
352 // Yes, it is overkill to use the hash table and vector here since
353 // we're only putting one header in the file, but in case we need
354 // to add others later and for consistency, we'll implement it this way.
356 // Add the only header we know about right now: Content-length.
360 if (jarFileURLConnection != null)
361 len = jarFileURLConnection.getContentLength ();
364 JarEntry entry = getJarEntry();
366 len = entry.getSize ();
369 String line = "Content-length: " + len;
370 hdrVec.addElement(line);
372 // The key will never be null in this scenario since we build up the
373 // headers ourselves. If we ever rely on getting a header from somewhere
374 // else, then we may have to check if the result of getKey() is null.
375 String key = getKey(line);
376 hdrHash.put(key.toLowerCase(), Long.toString(len));
380 * Returns an array of Certificate objects for the jar file entry specified
381 * by this URL or null if there are none
383 * @return A Certificate array
385 * @exception IOException If an error occurs
387 public Certificate[] getCertificates() throws IOException
389 return getJarEntry().getCertificates();
393 * Returns the main Attributes for the JAR file for this connection
395 * @exception IOException If an error occurs
397 public Attributes getMainAttributes () throws IOException
399 return getManifest ().getMainAttributes ();
403 * Return the Attributes object for this connection if the URL for it points
404 * to a JAR file entry, null otherwise
406 * @exception IOException If an error occurs
408 public Attributes getAttributes () throws IOException
410 // FIXME: implement this
415 * Returns the Manifest for this connection, or null if none
417 * @exception IOException If an error occurs
419 public Manifest getManifest () throws IOException
421 JarFile file = getJarFile ();
423 return (file != null) ? file.getManifest() : null;