blob: 17d3fd537e1709f520a480815c708f13de5f27d3 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net.www.protocol.jar;
27
28import java.io.InputStream;
29import java.io.IOException;
30import java.io.FileNotFoundException;
31import java.io.BufferedInputStream;
32import java.net.URL;
33import java.net.URLConnection;
34import java.net.MalformedURLException;
35import java.net.UnknownServiceException;
36import java.util.Enumeration;
37import java.util.Map;
38import java.util.List;
39import java.util.jar.JarEntry;
40import java.util.jar.JarFile;
41import java.util.jar.Manifest;
42import java.security.Permission;
43
44/**
45 * @author Benjamin Renaud
46 * @since 1.2
47 */
48public class JarURLConnection extends java.net.JarURLConnection {
49
50 private static final boolean debug = false;
51
52 /* the Jar file factory. It handles both retrieval and caching.
53 */
54 private static JarFileFactory factory = new JarFileFactory();
55
56 /* the url for the Jar file */
57 private URL jarFileURL;
58
59 /* the permission to get this JAR file. This is the actual, ultimate,
60 * permission, returned by the jar file factory.
61 */
62 private Permission permission;
63
64 /* the url connection for the JAR file */
65 private URLConnection jarFileURLConnection;
66
67 /* the entry name, if any */
68 private String entryName;
69
70 /* the JarEntry */
71 private JarEntry jarEntry;
72
73 /* the jar file corresponding to this connection */
74 private JarFile jarFile;
75
76 /* the content type for this connection */
77 private String contentType;
78
79 public JarURLConnection(URL url, Handler handler)
80 throws MalformedURLException, IOException {
81 super(url);
82
83 jarFileURL = getJarFileURL();
84 jarFileURLConnection = jarFileURL.openConnection();
85 entryName = getEntryName();
86 }
87
88 public JarFile getJarFile() throws IOException {
89 connect();
90 return jarFile;
91 }
92
93 public JarEntry getJarEntry() throws IOException {
94 connect();
95 return jarEntry;
96 }
97
98 public Permission getPermission() throws IOException {
99 return jarFileURLConnection.getPermission();
100 }
101
102 class JarURLInputStream extends java.io.FilterInputStream {
103 JarURLInputStream (InputStream src) {
104 super (src);
105 }
106 public void close () throws IOException {
107 try {
108 super.close();
109 } finally {
110 if (!getUseCaches()) {
111 jarFile.close();
112 }
113 }
114 }
115 }
116
117
118
119 public void connect() throws IOException {
120 if (!connected) {
121 /* the factory call will do the security checks */
122 jarFile = factory.get(getJarFileURL(), getUseCaches());
123
124 /* we also ask the factory the permission that was required
125 * to get the jarFile, and set it as our permission.
126 */
127 if (getUseCaches()) {
128 jarFileURLConnection = factory.getConnection(jarFile);
129 }
130
131 if ((entryName != null)) {
132 jarEntry = (JarEntry)jarFile.getEntry(entryName);
133 if (jarEntry == null) {
134 try {
135 if (!getUseCaches()) {
136 jarFile.close();
137 }
138 } catch (Exception e) {
139 }
140 throw new FileNotFoundException("JAR entry " + entryName +
141 " not found in " +
142 jarFile.getName());
143 }
144 }
145 connected = true;
146 }
147 }
148
149 public InputStream getInputStream() throws IOException {
150 connect();
151
152 InputStream result = null;
153
154 if (entryName == null) {
155 throw new IOException("no entry name specified");
156 } else {
157 if (jarEntry == null) {
158 throw new FileNotFoundException("JAR entry " + entryName +
159 " not found in " +
160 jarFile.getName());
161 }
162 result = new JarURLInputStream (jarFile.getInputStream(jarEntry));
163 }
164 return result;
165 }
166
167 public int getContentLength() {
168 long result = getContentLengthLong();
169 if (result > Integer.MAX_VALUE)
170 return -1;
171 return (int) result;
172 }
173
174 public long getContentLengthLong() {
175 long result = -1;
176 try {
177 connect();
178 if (jarEntry == null) {
179 /* if the URL referes to an archive */
180 result = jarFileURLConnection.getContentLengthLong();
181 } else {
182 /* if the URL referes to an archive entry */
183 result = getJarEntry().getSize();
184 }
185 } catch (IOException e) {
186 }
187 return result;
188 }
189
190 public Object getContent() throws IOException {
191 Object result = null;
192
193 connect();
194 if (entryName == null) {
195 result = jarFile;
196 } else {
197 result = super.getContent();
198 }
199 return result;
200 }
201
202 public String getContentType() {
203 if (contentType == null) {
204 if (entryName == null) {
205 contentType = "x-java/jar";
206 } else {
207 try {
208 connect();
209 InputStream in = jarFile.getInputStream(jarEntry);
210 contentType = guessContentTypeFromStream(
211 new BufferedInputStream(in));
212 in.close();
213 } catch (IOException e) {
214 // don't do anything
215 }
216 }
217 if (contentType == null) {
218 contentType = guessContentTypeFromName(entryName);
219 }
220 if (contentType == null) {
221 contentType = "content/unknown";
222 }
223 }
224 return contentType;
225 }
226
227 public String getHeaderField(String name) {
228 return jarFileURLConnection.getHeaderField(name);
229 }
230
231 /**
232 * Sets the general request property.
233 *
234 * @param key the keyword by which the request is known
235 * (e.g., "<code>accept</code>").
236 * @param value the value associated with it.
237 */
238 public void setRequestProperty(String key, String value) {
239 jarFileURLConnection.setRequestProperty(key, value);
240 }
241
242 /**
243 * Returns the value of the named general request property for this
244 * connection.
245 *
246 * @return the value of the named general request property for this
247 * connection.
248 */
249 public String getRequestProperty(String key) {
250 return jarFileURLConnection.getRequestProperty(key);
251 }
252
253 /**
254 * Adds a general request property specified by a
255 * key-value pair. This method will not overwrite
256 * existing values associated with the same key.
257 *
258 * @param key the keyword by which the request is known
259 * (e.g., "<code>accept</code>").
260 * @param value the value associated with it.
261 */
262 public void addRequestProperty(String key, String value) {
263 jarFileURLConnection.addRequestProperty(key, value);
264 }
265
266 /**
267 * Returns an unmodifiable Map of general request
268 * properties for this connection. The Map keys
269 * are Strings that represent the request-header
270 * field names. Each Map value is a unmodifiable List
271 * of Strings that represents the corresponding
272 * field values.
273 *
274 * @return a Map of the general request properties for this connection.
275 */
276 public Map<String,List<String>> getRequestProperties() {
277 return jarFileURLConnection.getRequestProperties();
278 }
279
280 /**
281 * Set the value of the <code>allowUserInteraction</code> field of
282 * this <code>URLConnection</code>.
283 *
284 * @param allowuserinteraction the new value.
285 * @see java.net.URLConnection#allowUserInteraction
286 */
287 public void setAllowUserInteraction(boolean allowuserinteraction) {
288 jarFileURLConnection.setAllowUserInteraction(allowuserinteraction);
289 }
290
291 /**
292 * Returns the value of the <code>allowUserInteraction</code> field for
293 * this object.
294 *
295 * @return the value of the <code>allowUserInteraction</code> field for
296 * this object.
297 * @see java.net.URLConnection#allowUserInteraction
298 */
299 public boolean getAllowUserInteraction() {
300 return jarFileURLConnection.getAllowUserInteraction();
301 }
302
303 /*
304 * cache control
305 */
306
307 /**
308 * Sets the value of the <code>useCaches</code> field of this
309 * <code>URLConnection</code> to the specified value.
310 * <p>
311 * Some protocols do caching of documents. Occasionally, it is important
312 * to be able to "tunnel through" and ignore the caches (e.g., the
313 * "reload" button in a browser). If the UseCaches flag on a connection
314 * is true, the connection is allowed to use whatever caches it can.
315 * If false, caches are to be ignored.
316 * The default value comes from DefaultUseCaches, which defaults to
317 * true.
318 *
319 * @see java.net.URLConnection#useCaches
320 */
321 public void setUseCaches(boolean usecaches) {
322 jarFileURLConnection.setUseCaches(usecaches);
323 }
324
325 /**
326 * Returns the value of this <code>URLConnection</code>'s
327 * <code>useCaches</code> field.
328 *
329 * @return the value of this <code>URLConnection</code>'s
330 * <code>useCaches</code> field.
331 * @see java.net.URLConnection#useCaches
332 */
333 public boolean getUseCaches() {
334 return jarFileURLConnection.getUseCaches();
335 }
336
337 /**
338 * Sets the value of the <code>ifModifiedSince</code> field of
339 * this <code>URLConnection</code> to the specified value.
340 *
341 * @param value the new value.
342 * @see java.net.URLConnection#ifModifiedSince
343 */
344 public void setIfModifiedSince(long ifmodifiedsince) {
345 jarFileURLConnection.setIfModifiedSince(ifmodifiedsince);
346 }
347
348 /**
349 * Sets the default value of the <code>useCaches</code> field to the
350 * specified value.
351 *
352 * @param defaultusecaches the new value.
353 * @see java.net.URLConnection#useCaches
354 */
355 public void setDefaultUseCaches(boolean defaultusecaches) {
356 jarFileURLConnection.setDefaultUseCaches(defaultusecaches);
357 }
358
359 /**
360 * Returns the default value of a <code>URLConnection</code>'s
361 * <code>useCaches</code> flag.
362 * <p>
363 * Ths default is "sticky", being a part of the static state of all
364 * URLConnections. This flag applies to the next, and all following
365 * URLConnections that are created.
366 *
367 * @return the default value of a <code>URLConnection</code>'s
368 * <code>useCaches</code> flag.
369 * @see java.net.URLConnection#useCaches
370 */
371 public boolean getDefaultUseCaches() {
372 return jarFileURLConnection.getDefaultUseCaches();
373 }
374}