001: /*
002: * @(#)JarURLConnection.java 1.34 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.net;
029:
030: import java.io.IOException;
031: import java.util.jar.JarFile;
032: import java.util.jar.JarEntry;
033: import java.util.jar.Attributes;
034: import java.util.jar.Manifest;
035: import java.security.Permission;
036:
037: /**
038: * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR
039: * file.
040: *
041: * <p>The syntax of a JAR URL is:
042: *
043: * <pre>
044: * jar:<url>!/{entry}
045: * </pre>
046: *
047: * <p>for example:
048: *
049: * <p><code>
050: * jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class<br>
051: * </code>
052: *
053: * <p>Jar URLs should be used to refer to a JAR file or entries in
054: * a JAR file. The example above is a JAR URL which refers to a JAR
055: * entry. If the entry name is omitted, the URL refers to the whole
056: * JAR file:
057: *
058: * <code>
059: * jar:http://www.foo.com/bar/baz.jar!/
060: * </code>
061: *
062: * <p>Users should cast the generic URLConnection to a
063: * JarURLConnection when they know that the URL they created is a JAR
064: * URL, and they need JAR-specific functionality. For example:
065: *
066: * <pre>
067: * URL url = new URL("jar:file:/home/duke/duke.jar!/");
068: * JarURLConnection jarConnection = (JarURLConnection)url.openConnection();
069: * Manifest manifest = jarConnection.getManifest();
070: * </pre>
071: *
072: * <p>Examples:
073: *
074: * <dl>
075: *
076: * <dt>A Jar entry
077: * <dd><code>jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class</code>
078: *
079: * <dt>A Jar file
080: * <dd><code>jar:http://www.foo.com/bar/baz.jar!/</code>
081: *
082: * <dt>A Jar directory
083: * <dd><code>jar:http://www.foo.com/bar/baz.jar!/COM/foo/</code>
084: *
085: * </dl>
086: *
087: * <p><code>!/</code> is refered to as the <em>separator</em>.
088: *
089: * <p>When constructing a JAR url via <code>new URL(context, spec)</code>,
090: * the following rules apply:
091: *
092: * <ul>
093: *
094: * <li>if there is no context URL and the specification passed to the
095: * URL constructor doesn't contain a separator, the URL is considered
096: * to refer to a JarFile.
097: *
098: * <li>if there is a context URL, the context URL is assumed to refer
099: * to a JAR file or a Jar directory.
100: *
101: * <li>if the specification begins with a '/', the Jar directory is
102: * ignored, and the spec is considered to be at the root of the Jar
103: * file.
104: *
105: * <p>Examples:
106: *
107: * <dl>
108: *
109: * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/</b>,
110: * spec:<b>baz/entry.txt</b>
111: *
112: * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
113: *
114: * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
115: * spec:<b>entry.txt</b>
116: *
117: * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
118: *
119: * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
120: * spec:<b>/entry.txt</b>
121: *
122: * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/entry.txt</b>
123: *
124: * </dl>
125: *
126: * </ul>
127: *
128: * @see java.net.URL
129: * @see java.net.URLConnection
130: *
131: * @see java.util.jar.JarFile
132: * @see java.util.jar.JarInputStream
133: * @see java.util.jar.Manifest
134: * @see java.util.zip.ZipEntry
135: *
136: * @author Benjamin Renaud
137: * @since 1.2
138: */
139: public abstract class JarURLConnection extends URLConnection {
140:
141: private URL jarFileURL;
142: private String entryName;
143:
144: /**
145: * The connection to the JAR file URL, if the connection has been
146: * initiated. This should be set by connect.
147: */
148: protected URLConnection jarFileURLConnection;
149:
150: /**
151: * Creates the new JarURLConnection to the specified URL.
152: * @param url the URL
153: * @throws MalformedURLException if no legal protocol
154: * could be found in a specification string or the
155: * string could not be parsed.
156: */
157:
158: protected JarURLConnection(URL url) throws MalformedURLException {
159: super (url);
160: parseSpecs(url);
161: }
162:
163: /* get the specs for a given url out of the cache, and compute and
164: * cache them if they're not there.
165: */
166: private void parseSpecs(URL url) throws MalformedURLException {
167: String spec = url.getFile();
168:
169: int separator = spec.indexOf('!');
170: if (separator == -1) {
171: throw new MalformedURLException("no ! found in url spec:"
172: + spec);
173: }
174:
175: jarFileURL = new URL(spec.substring(0, separator++));
176: entryName = null;
177:
178: /* if ! is the last letter of the innerURL, entryName is null */
179: if (++separator != spec.length()) {
180: entryName = spec.substring(separator, spec.length());
181: }
182: }
183:
184: /**
185: * Returns the URL for the Jar file for this connection.
186: *
187: * @return the URL for the Jar file for this connection.
188: */
189: public URL getJarFileURL() {
190: return jarFileURL;
191: }
192:
193: /**
194: * Return the entry name for this connection. This method
195: * returns null if the JAR file URL corresponding to this
196: * connection points to a JAR file and not a JAR file entry.
197: *
198: * @return the entry name for this connection, if any.
199: */
200: public String getEntryName() {
201: return entryName;
202: }
203:
204: /**
205: * Return the JAR file for this connection. The returned object is
206: * not modifiable, and will throw UnsupportedOperationException
207: * if the caller attempts to modify it.
208: *
209: * @return the JAR file for this connection. If the connection is
210: * a connection to an entry of a JAR file, the JAR file object is
211: * returned
212: *
213: * @exception IOException if an IOException occurs while trying to
214: * connect to the JAR file for this connection.
215: *
216: * @see #connect
217: */
218: public abstract JarFile getJarFile() throws IOException;
219:
220: /**
221: * Returns the Manifest for this connection, or null if none. The
222: * returned object is not modifiable, and will throw
223: * UnsupportedOperationException if the caller attempts to modify
224: * it.
225: *
226: * @return the manifest object corresponding to the JAR file object
227: * for this connection.
228: *
229: * @exception IOException if getting the JAR file for this
230: * connection causes an IOException to be trown.
231: *
232: * @see #getJarFile
233: */
234: public Manifest getManifest() throws IOException {
235: return getJarFile().getManifest();
236: }
237:
238: /**
239: * Return the JAR entry object for this connection, if any. This
240: * method returns null if the JAR file URL corresponding to this
241: * connection points to a JAR file and not a JAR file entry. The
242: * returned object is not modifiable, and will throw
243: * UnsupportedOperationException if the caller attempts to modify
244: * it.
245: *
246: * @return the JAR entry object for this connection, or null if
247: * the JAR URL for this connection points to a JAR file.
248: *
249: * @exception IOException if getting the JAR file for this
250: * connection causes an IOException to be trown.
251: *
252: * @see #getJarFile
253: * @see #getJarEntry
254: */
255: public JarEntry getJarEntry() throws IOException {
256: return getJarFile().getJarEntry(entryName);
257: }
258:
259: /**
260: * Return the Attributes object for this connection if the URL
261: * for it points to a JAR file entry, null otherwise.
262: *
263: * @return the Attributes object for this connection if the URL
264: * for it points to a JAR file entry, null otherwise.
265: *
266: * @exception IOException if getting the JAR entry causes an
267: * IOException to be thrown.
268: *
269: * @see #getJarEntry
270: */
271: public Attributes getAttributes() throws IOException {
272: JarEntry e = getJarEntry();
273: return e != null ? e.getAttributes() : null;
274: }
275:
276: /**
277: * Returns the main Attributes for the JAR file for this
278: * connection.
279: *
280: * @return the main Attributes for the JAR file for this
281: * connection.
282: *
283: * @exception IOException if getting the manifest causes an
284: * IOException to be thrown.
285: *
286: * @see #getJarFile
287: * @see #getManifest
288: */
289: public Attributes getMainAttributes() throws IOException {
290: Manifest man = getManifest();
291: return man != null ? man.getMainAttributes() : null;
292: }
293:
294: /**
295: * Return the Certificate object for this connection if the URL
296: * for it points to a JAR file entry, null otherwise. This method
297: * can only be called once
298: * the connection has been completely verified by reading
299: * from the input stream until the end of the stream has been
300: * reached. Otherwise, this method will return <code>null</code>
301: * <p>
302: * ***NOTE: In J2ME CDC, there is no support for certificates by design.
303: * If CDC by itself or a J2ME profile built on CDC does not add back the
304: * java.security.Signature class (plus all its dependencies),
305: * a <code>null</code> value must always be returned.
306: *
307: * @return the Certificate object for this connection if the URL
308: * for it points to a JAR file entry, null otherwise.
309: *
310: * @exception IOException if getting the JAR entry causes an
311: * IOException to be thrown.
312: *
313: * @see #getJarEntry
314: */
315: public java.security.cert.Certificate[] getCertificates()
316: throws IOException {
317: JarEntry e = getJarEntry();
318: return e != null ? e.getCertificates() : null;
319: }
320: }
|