JarURLConnectionImpl.java revision 3819a76e7c1f49253f0e077bd497f149340c02b8
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  this work for additional information regarding copyright ownership.
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  the License.  You may obtain a copy of the License at
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  See the License for the specific language governing permissions and
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *  limitations under the License.
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage org.apache.harmony.luni.internal.net.www.protocol.jar;
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileNotFoundException;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FileOutputStream;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.FilterInputStream;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.InputStream;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.ContentHandler;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.ContentHandlerFactory;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.MalformedURLException;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.URL;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.AccessController;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.Permission;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.security.PrivilegedAction;
333819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilsonimport java.util.HashMap;
343819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilsonimport java.util.Iterator;
353819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilsonimport java.util.Map;
363819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilsonimport java.util.Set;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarEntry;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.jar.JarFile;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.zip.ZipFile;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.luni.util.Msg;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport org.apache.harmony.luni.util.Util;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This subclass extends <code>URLConnection</code>.
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p>
473819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson *
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This class is responsible for connecting and retrieving resources from a Jar
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * file which can be anywhere that can be refered to by an URL.
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class JarURLConnection extends java.net.JarURLConnection {
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
533819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    static HashMap<URL, JarFile> jarCache = new HashMap<URL, JarFile>();
543819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
553819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    private URL jarFileURL;
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
573819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    private InputStream jarInput;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private JarFile jarFile;
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private JarEntry jarEntry;
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
633819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    private boolean closed;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param url
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            the URL of the JAR
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws MalformedURLException
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if the URL is malformed
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
723819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    public JarURLConnection(java.net.URL url) throws MalformedURLException, IOException {
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(url);
743819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        jarFileURL = getJarFileURL();
753819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        jarFileURLConnection = jarFileURL.openConnection();
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see java.net.URLConnection#connect()
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void connect() throws IOException {
833819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (!connected) {
843819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            findJarFile(); // ensure the file can be found
853819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            findJarEntry(); // ensure the entry, if any, can be found
863819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            connected = true;
873819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        }
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the Jar file refered by this <code>URLConnection</code>
923819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the JAR file referenced by this connection
943819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             thrown if an IO error occurs while connecting to the
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             resource.
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public JarFile getJarFile() throws IOException {
1013819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        connect();
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return jarFile;
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the Jar file refered by this <code>URLConnection</code>
1073819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occurs while connecting to the resource.
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void findJarFile() throws IOException {
1123819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        JarFile jar = null;
1133819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (getUseCaches()) {
1143819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            synchronized(jarCache){
1153819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                jarFile = jarCache.get(jarFileURL);
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1173819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            if (jarFile == null) {
1183819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                jar = openJarFile();
1193819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                synchronized(jarCache){
1203819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    jarFile = jarCache.get(jarFileURL);
1213819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    if (jarFile == null){
1223819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                        jarCache.put(jarFileURL, jar);
1233819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                        jarFile = jar;
1243819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    }else{
1253819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                        jar.close();
1263819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    }
1273819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                }
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1293819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        }else{
1303819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            jarFile = openJarFile();
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1333819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (jarFile == null) {
1343819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            throw new IOException();
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1363819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    }
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1383819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    JarFile openJarFile() throws IOException {
1393819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        JarFile jar = null;
1403819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (jarFileURL.getProtocol().equals("file")) { //$NON-NLS-1$
1413819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            jar = new JarFile(new File(Util.decode(jarFileURL.getFile(), false)),
1423819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                        true, ZipFile.OPEN_READ);
1433819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        } else{
1443819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            final InputStream is = jarFileURL.openConnection().getInputStream();
1453819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            try {
1463819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                jar = AccessController
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .doPrivileged(new PrivilegedAction<JarFile>() {
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        public JarFile run() {
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            try {
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                File tempJar = File.createTempFile("hyjar_", //$NON-NLS-1$
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        ".tmp", null); //$NON-NLS-1$
1523819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                                tempJar.deleteOnExit();
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                FileOutputStream fos = new FileOutputStream(
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        tempJar);
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                byte[] buf = new byte[4096];
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                int nbytes = 0;
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                while ((nbytes = is.read(buf)) > -1) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    fos.write(buf, 0, nbytes);
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                fos.close();
1613819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                                return new JarFile(tempJar,
1623819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                                        true, ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            } catch (IOException e) {
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                return null;
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            }
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    });
1683819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            } finally {
1693819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                if (is != null) is.close();
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return jar;
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the JarEntry of the entry referenced by this
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <code>URLConnection</code>.
1793819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return java.util.jar.JarEntry the JarEntry referenced
1813819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occurs while getting the entry
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public JarEntry getJarEntry() throws IOException {
1873819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        connect();
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return jarEntry;
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Look up the JarEntry of the entry referenced by this
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <code>URLConnection</code>.
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void findJarEntry() throws IOException {
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (getEntryName() == null) {
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        jarEntry = jarFile.getJarEntry(getEntryName());
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (jarEntry == null) {
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new FileNotFoundException(getEntryName());
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates an input stream for reading from this URL Connection.
2083819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the input stream
2103819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occurs while connecting to the resource.
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public InputStream getInputStream() throws IOException {
2163819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (closed) {
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalStateException(Msg.getString("KA027"));
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2203819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        connect();
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (jarInput != null) {
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return jarInput;
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (jarEntry == null) {
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IOException(Msg.getString("K00fc")); //$NON-NLS-1$
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return jarInput = new JarURLConnectionInputStream(jarFile
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                .getInputStream(jarEntry), jarFile);
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
2323819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * Returns the content type of the resource.
2333819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * For jar file itself "x-java/jar" should be returned,
2343819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * for jar entries the content type of the entry should be returned.
2353819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * Returns non-null results ("content/unknown" for unknown types).
2363819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the content type
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String getContentType() {
2413819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        if (url.getFile().endsWith("!/")) { //$NON-NLS-1$
2423819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            // the type for jar file itself is always "x-java/jar"
2433819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            return "x-java/jar"; //$NON-NLS-1$
2443819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        } else {
2453819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            String cType = null;
2463819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            String entryName = getEntryName();
2473819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
2483819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            if (entryName != null) {
2493819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                // if there is an Jar Entry, get the content type from the name
2503819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                cType = guessContentTypeFromName(entryName);
2513819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            } else {
2523819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                try {
2533819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    connect();
2543819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    cType = jarFileURLConnection.getContentType();
2553819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                } catch (IOException ioe) {
2563819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    // Ignore
2573819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                }
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
2593819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            if (cType == null) {
2603819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                cType = "content/unknown"; //$NON-NLS-1$
2613819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            }
2623819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            return cType;
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the content length of the resource. Test cases reveal that if the
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * URL is refering to a Jar file, this method returns a content-length
2693819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * returned by URLConnection. For jar entry it should return it's size.
2703819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     * Otherwise, it will return -1.
2713819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the content length
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public int getContentLength() {
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
2773819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            connect();
2783819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            if (jarEntry == null) {
2793819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                return jarFileURLConnection.getContentLength();
2803819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            } else {
2813819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                return (int) getJarEntry().getSize();
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IOException e) {
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            //Ignored
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the object pointed by this <code>URL</code>. If this
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * URLConnection is pointing to a Jar File (no Jar Entry), this method will
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * return a <code>JarFile</code> If there is a Jar Entry, it will return
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the object corresponding to the Jar entry content type.
2943819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return a non-null object
2963819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if an IO error occured
2993819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see ContentHandler
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see ContentHandlerFactory
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see java.io.IOException
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @see #setContentHandlerFactory(ContentHandlerFactory)
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Object getContent() throws IOException {
3073819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        connect();
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // if there is no Jar Entry, return a JarFile
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (jarEntry == null) {
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return jarFile;
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return super.getContent();
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns the permission, in this case the subclass, FilePermission object
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * which represents the permission necessary for this URLConnection to
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * establish the connection.
3193819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the permission required for this URLConnection.
3213819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson     *
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws IOException
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             thrown when an IO exception occurs while creating the
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             permission.
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3263819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public Permission getPermission() throws IOException {
3293819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        return jarFileURLConnection.getPermission();
3303819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    }
3313819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
3323819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    @Override
3333819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    public boolean getUseCaches() {
3343819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        return jarFileURLConnection.getUseCaches();
3353819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    }
3363819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
3373819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    @Override
3383819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    public void setUseCaches(boolean usecaches) {
3393819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        jarFileURLConnection.setUseCaches(usecaches);
3403819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    }
3413819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
3423819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    @Override
3433819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    public boolean getDefaultUseCaches() {
3443819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        return jarFileURLConnection.getDefaultUseCaches();
3453819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    }
3463819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson
3473819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    @Override
3483819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson    public void setDefaultUseCaches(boolean defaultusecaches) {
3493819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        jarFileURLConnection.setDefaultUseCaches(defaultusecaches);
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Closes the cached files.
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static void closeCachedFiles() {
3563819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        Set<Map.Entry<URL, JarFile>> s = jarCache.entrySet();
3573819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson        synchronized(jarCache){
3583819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            Iterator<Map.Entry<URL, JarFile>> i = s.iterator();
3593819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            while(i.hasNext()){
3603819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                try {
3613819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    ZipFile zip = i.next().getValue();
3623819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    if (zip != null) {
3633819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                        zip.close();
3643819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    }
3653819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                } catch (IOException e) {
3663819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson                    // Ignored
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
3693819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson       }
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private class JarURLConnectionInputStream extends FilterInputStream {
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InputStream inputStream;
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        JarFile jarFile;
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        protected JarURLConnectionInputStream(InputStream in, JarFile file) {
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            super(in);
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            inputStream = in;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            jarFile = file;
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        @Override
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public void close() throws IOException {
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            super.close();
3863819a76e7c1f49253f0e077bd497f149340c02b8Jesse Wilson            if (!getUseCaches()) {
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                closed = true;
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                jarFile.close();
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        @Override
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int read() throws IOException {
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return inputStream.read();
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        @Override
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public int read(byte[] buf, int off, int nbytes) throws IOException {
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return inputStream.read(buf, off, nbytes);
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        @Override
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        public long skip(long nbytes) throws IOException {
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return inputStream.skip(nbytes);
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
408