1 package org.codehaus.classworlds.uberjar.protocol.jar;
2
3 /*
4 $Id: JarUrlConnection.java,v 1.1 2003/09/23 18:11:30 jvanzyl Exp $
5
6 Copyright 2002 (C) The Werken Company. All Rights Reserved.
7
8 Redistribution and use of this software and associated documentation
9 ("Software"), with or without modification, are permitted provided
10 that the following conditions are met:
11
12 1. Redistributions of source code must retain copyright
13 statements and notices. Redistributions must also contain a
14 copy of this document.
15
16 2. Redistributions in binary form must reproduce the
17 above copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
20
21 3. The name "classworlds" must not be used to endorse or promote
22 products derived from this Software without prior written
23 permission of The Werken Company. For written permission,
24 please contact bob@werken.com.
25
26 4. Products derived from this Software may not be called "classworlds"
27 nor may "classworlds" appear in their names without prior written
28 permission of The Werken Company. "classworlds" is a registered
29 trademark of The Werken Company.
30
31 5. Due credit should be given to The Werken Company.
32 (http://classworlds.werken.com/).
33
34 THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS
35 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
36 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
37 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
38 THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
39 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
43 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
45 OF THE POSSIBILITY OF SUCH DAMAGE.
46
47 */
48
49 import org.codehaus.classworlds.UrlUtils;
50
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.net.JarURLConnection;
54 import java.net.MalformedURLException;
55 import java.net.URL;
56 import java.net.URLDecoder;
57 import java.util.ArrayList;
58 import java.util.List;
59 import java.util.StringTokenizer;
60 import java.util.jar.JarEntry;
61 import java.util.jar.JarFile;
62 import java.util.jar.JarInputStream;
63
64 /*** <code>URLConnection</code> capable of handling multiply-nested jars.
65 *
66 *
67 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
68 *
69 * @version $Id: JarUrlConnection.java,v 1.1 2003/09/23 18:11:30 jvanzyl Exp $
70 */
71 public class JarUrlConnection
72 extends JarURLConnection
73 {
74 // ----------------------------------------------------------------------
75 // Instance members
76 // ----------------------------------------------------------------------
77
78 /*** Base resource. */
79 private URL baseResource;
80
81 /*** Additional nested segments. */
82 private String[] segments;
83
84 /*** Terminal input-stream. */
85 private InputStream in;
86
87 // ----------------------------------------------------------------------
88 // Constructors
89 // ----------------------------------------------------------------------
90
91 /*** Construct.
92 *
93 * @param url Target URL of the connections.
94 *
95 * @throws java.io.IOException If an error occurs while attempting to initialize
96 * the connection.
97 */
98 JarUrlConnection( URL url )
99 throws IOException
100 {
101 super( url = normaliseURL( url ) );
102
103 String baseText = url.getPath();
104
105 int bangLoc = baseText.indexOf( "!" );
106
107 String baseResourceText = baseText.substring( 0, bangLoc );
108
109 String extraText = "";
110
111 if ( bangLoc <= ( baseText.length() - 2 )
112 &&
113 baseText.charAt( bangLoc + 1 ) == '/' )
114 {
115 if ( bangLoc + 2 == baseText.length() )
116 {
117 extraText = "";
118 }
119 else
120 {
121 extraText = baseText.substring( bangLoc + 1 );
122 }
123 }
124 else
125 {
126 throw new MalformedURLException( "No !/ in url: " + url.toExternalForm() );
127 }
128
129
130 List segments = new ArrayList();
131
132 StringTokenizer tokens = new StringTokenizer( extraText, "!" );
133
134 while ( tokens.hasMoreTokens() )
135 {
136 segments.add( tokens.nextToken() );
137 }
138
139 this.segments = (String[]) segments.toArray( new String[segments.size()] );
140
141 this.baseResource = new URL( baseResourceText );
142 }
143
144 protected static URL normaliseURL( URL url ) throws MalformedURLException
145 {
146 String text = UrlUtils.normalizeUrlPath( url.toString() );
147
148 if ( !text.startsWith( "jar:" ) )
149 {
150 text = "jar:" + text;
151 }
152
153 if ( text.indexOf( '!' ) < 0 )
154 {
155 text = text + "!/";
156 }
157
158 return new URL( text );
159 }
160
161 // ----------------------------------------------------------------------
162 // Instance methods
163 // ----------------------------------------------------------------------
164
165 /*** Retrieve the nesting path segments.
166 *
167 * @return The segments.
168 */
169 protected String[] getSegments()
170 {
171 return this.segments;
172 }
173
174 /*** Retrieve the base resource <code>URL</code>.
175 *
176 * @return The base resource url.
177 */
178 protected URL getBaseResource()
179 {
180 return this.baseResource;
181 }
182
183 /*** @see java.net.URLConnection
184 */
185 public void connect()
186 throws IOException
187 {
188 if ( this.segments.length == 0 )
189 {
190 setupBaseResourceInputStream();
191 }
192 else
193 {
194 setupPathedInputStream();
195 }
196 }
197
198 /*** Setup the <code>InputStream</code> purely from the base resource.
199 *
200 * @throws java.io.IOException If an I/O error occurs.
201 */
202 protected void setupBaseResourceInputStream()
203 throws IOException
204 {
205 this.in = getBaseResource().openStream();
206 }
207
208 /*** Setup the <code>InputStream</code> for URL with nested segments.
209 *
210 * @throws java.io.IOException If an I/O error occurs.
211 */
212 protected void setupPathedInputStream()
213 throws IOException
214 {
215 InputStream curIn = getBaseResource().openStream();
216
217 for ( int i = 0; i < this.segments.length; ++i )
218 {
219 curIn = getSegmentInputStream( curIn,
220 segments[i] );
221 }
222
223 this.in = curIn;
224 }
225
226 /*** Retrieve the <code>InputStream</code> for the nesting
227 * segment relative to a base <code>InputStream</code>.
228 *
229 * @param baseIn The base input-stream.
230 * @param segment The nesting segment path.
231 *
232 * @return The input-stream to the segment.
233 *
234 * @throws java.io.IOException If an I/O error occurs.
235 */
236 protected InputStream getSegmentInputStream( InputStream baseIn,
237 String segment )
238 throws IOException
239 {
240 JarInputStream jarIn = new JarInputStream( baseIn );
241 JarEntry entry = null;
242
243 while ( jarIn.available() != 0 )
244 {
245 entry = jarIn.getNextJarEntry();
246
247 if ( entry == null )
248 {
249 break;
250 }
251
252 if ( ( "/" + entry.getName() ).equals( segment ) )
253 {
254 return jarIn;
255 }
256 }
257
258 throw new IOException( "unable to locate segment: " + segment );
259 }
260
261 /*** @see java.net.URLConnection
262 */
263 public InputStream getInputStream()
264 throws IOException
265 {
266 if ( this.in == null )
267 {
268 connect();
269 }
270 return this.in;
271 }
272
273 /***
274 * @return JarFile
275 * @throws java.io.IOException
276 * @see java.net.JarURLConnection#getJarFile()
277 */
278 public JarFile getJarFile() throws IOException
279 {
280 String url = baseResource.toExternalForm();
281
282 if ( url.startsWith( "file:/" ) )
283 {
284 url = url.substring( 6 );
285 }
286
287 return new JarFile( URLDecoder.decode( url, "UTF-8" ) );
288 }
289 }
This page was automatically generated by Maven