1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import java.io.IOException;
21import java.security.cert.Certificate;
22import java.util.jar.Attributes;
23import java.util.jar.JarEntry;
24import java.util.jar.JarFile;
25import java.util.jar.Manifest;
26
27/**
28 * This class establishes a connection to a {@code jar:} URL using the {@code
29 * JAR} protocol. A {@code JarURLConnection} instance can refer to either a JAR
30 * archive file or to an entry of such a file. {@code jar:} URLs are specified
31 * as follows: <i>jar:{archive-url}!/{entry}</i> where "!/" is called a
32 * separator. This separator is important to determine if an archive or an entry
33 * of an archive is referred.
34 * <p>
35 * Examples:
36 * <li>Archive: {@code jar:http://www.example.com/applets/archive.jar!/}</li>
37 * <li>File Entry: {@code
38 * jar:http://www.example.com/applets/archive.jar!/test.class}</li>
39 * <li>Directory Entry: {@code
40 * jar:http://www.example.com/applets/archive.jar!/applets/}</li>
41 */
42public abstract class JarURLConnection extends URLConnection {
43
44    /**
45     * The location part of the represented URL.
46     */
47    protected URLConnection jarFileURLConnection;
48
49    private String entryName;
50
51    private URL fileURL;
52
53    // the file component of the URL
54    private String file;
55
56    /**
57     * Constructs an instance of {@code JarURLConnection} that refers to the
58     * specified URL.
59     *
60     * @param url
61     *            the URL that contains the location to connect to.
62     * @throws MalformedURLException
63     *             if an invalid URL has been entered.
64     */
65    protected JarURLConnection(URL url) throws MalformedURLException {
66        super(url);
67        file = url.getFile();
68        int sepIdx;
69        if ((sepIdx = file.indexOf("!/")) < 0) { //$NON-NLS-1$
70            throw new MalformedURLException();
71        }
72        fileURL = new URL(url.getFile().substring(0,sepIdx));
73        sepIdx += 2;
74        if (file.length() == sepIdx) {
75            return;
76        }
77        entryName = file.substring(sepIdx, file.length());
78        if (null != url.getRef()) {
79            entryName += "#" + url.getRef(); //$NON-NLS-1$
80        }
81    }
82
83    /**
84     * Returns all attributes of the {@code JarEntry} referenced by this {@code
85     * JarURLConnection}.
86     *
87     * @return the attributes of the referenced {@code JarEntry}.
88     * @throws IOException
89     *                if an I/O exception occurs while retrieving the
90     *                JAR-entries.
91     */
92    public Attributes getAttributes() throws java.io.IOException {
93        JarEntry jEntry = getJarEntry();
94        return (jEntry == null) ? null : jEntry.getAttributes();
95    }
96
97    /**
98     * Returns all certificates of the {@code JarEntry} referenced by this
99     * {@code JarURLConnection} instance. This method will return {@code null}
100     * until the {@code InputStream} has been completely verified.
101     *
102     * @return the certificates of the {@code JarEntry} as an array.
103     * @throws IOException
104     *                if there is an I/O exception occurs while getting the
105     *                {@code JarEntry}.
106     */
107    public Certificate[] getCertificates() throws java.io.IOException {
108        JarEntry jEntry = getJarEntry();
109        if (jEntry == null) {
110            return null;
111        }
112
113        return jEntry.getCertificates();
114    }
115
116    /**
117     * Gets the name of the entry referenced by this {@code JarURLConnection}.
118     * The return value will be {@code null} if this instance refers to a JAR
119     * file rather than an JAR file entry.
120     *
121     * @return the {@code JarEntry} name this instance refers to.
122     */
123    public String getEntryName() {
124        return entryName;
125    }
126
127    /**
128     * Gets the {@code JarEntry} object of the entry referenced by this {@code
129     * JarURLConnection}.
130     *
131     * @return the referenced {@code JarEntry} object or {@code null} if no
132     *         entry name is specified.
133     * @throws IOException
134     *             if an error occurs while getting the file or file-entry.
135     */
136    public JarEntry getJarEntry() throws IOException {
137        if (!connected) {
138            connect();
139        }
140        if (entryName == null) {
141            return null;
142        }
143        // The entry must exist since the connect succeeded
144        return getJarFile().getJarEntry(entryName);
145    }
146
147    /**
148     * Gets the manifest file associated with this JAR-URL.
149     *
150     * @return the manifest of the referenced JAR-file.
151     * @throws IOException
152     *             if an error occurs while getting the manifest file.
153     */
154    public Manifest getManifest() throws java.io.IOException {
155        return (Manifest)getJarFile().getManifest().clone();
156    }
157
158    /**
159     * Gets the {@code JarFile} object referenced by this {@code
160     * JarURLConnection}.
161     *
162     * @return the referenced JarFile object.
163     * @throws IOException
164     *                if an I/O exception occurs while retrieving the JAR-file.
165     */
166    public abstract JarFile getJarFile() throws java.io.IOException;
167
168    /**
169     * Gets the URL to the JAR-file referenced by this {@code JarURLConnection}.
170     *
171     * @return the URL to the JAR-file or {@code null} if there was an error
172     *         retrieving the URL.
173     */
174    public URL getJarFileURL() {
175        return fileURL;
176    }
177
178    /**
179     * Gets all attributes of the manifest file referenced by this {@code
180     * JarURLConnection}. If this instance refers to a JAR-file rather than a
181     * JAR-file entry, {@code null} will be returned.
182     *
183     * @return the attributes of the manifest file or {@code null}.
184     * @throws IOException
185     *                if an I/O exception occurs while retrieving the {@code
186     *                JarFile}.
187     */
188    public Attributes getMainAttributes() throws java.io.IOException {
189        Manifest m = getJarFile().getManifest();
190        return (m == null) ? null : m.getMainAttributes();
191    }
192}
193