KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > boot > PlatformURLConnection


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.boot;
12
13 import java.io.*;
14 import java.net.URL JavaDoc;
15 import java.net.URLConnection JavaDoc;
16 import java.util.Enumeration JavaDoc;
17 import java.util.Properties JavaDoc;
18 import org.eclipse.core.internal.runtime.Activator;
19 import org.eclipse.core.internal.runtime.CommonMessages;
20 import org.eclipse.osgi.service.debug.DebugOptions;
21 import org.eclipse.osgi.util.NLS;
22 import org.osgi.framework.Version;
23
24 /**
25  * Platform URL support
26  */

27 public abstract class PlatformURLConnection extends URLConnection JavaDoc {
28
29     // URL access
30
private boolean isInCache = false;
31     private boolean isJar = false;
32
33     // protected URL url; // declared in super (platform: URL)
34
private URL JavaDoc resolvedURL = null; // resolved file URL (e.g. http: URL)
35
private URL JavaDoc cachedURL = null; // file URL in cache (file: URL)
36

37     private URLConnection JavaDoc connection = null; // actual connection
38

39     // local cache
40
private static Properties JavaDoc cacheIndex = new Properties JavaDoc();
41     private static String JavaDoc cacheLocation;
42     private static String JavaDoc indexName;
43     private static String JavaDoc filePrefix;
44
45     // constants
46
private static final int BUF_SIZE = 32768;
47     private static final Object JavaDoc NOT_FOUND = new Object JavaDoc(); // marker
48
private static final String JavaDoc CACHE_PROP = ".cache.properties"; //$NON-NLS-1$
49
private static final String JavaDoc CACHE_LOCATION_PROP = "location"; //$NON-NLS-1$
50
private static final String JavaDoc CACHE_INDEX_PROP = "index"; //$NON-NLS-1$
51
private static final String JavaDoc CACHE_PREFIX_PROP = "prefix"; //$NON-NLS-1$
52
private static final String JavaDoc CACHE_INDEX = ".index.properties"; //$NON-NLS-1$
53
private static final String JavaDoc CACHE_DIR = ".eclipse-" + PlatformURLHandler.PROTOCOL + File.separator; //$NON-NLS-1$
54

55     // debug tracing
56
private static final String JavaDoc OPTION_DEBUG = "org.eclipse.core.runtime/url/debug"; //$NON-NLS-1$;
57
private static final String JavaDoc OPTION_DEBUG_CONNECT = OPTION_DEBUG + "/connect"; //$NON-NLS-1$;
58
private static final String JavaDoc OPTION_DEBUG_CACHE_LOOKUP = OPTION_DEBUG + "/cachelookup"; //$NON-NLS-1$;
59
private static final String JavaDoc OPTION_DEBUG_CACHE_COPY = OPTION_DEBUG + "/cachecopy"; //$NON-NLS-1$;
60

61     public final static boolean DEBUG;
62     public final static boolean DEBUG_CONNECT;
63     public final static boolean DEBUG_CACHE_LOOKUP;
64     public final static boolean DEBUG_CACHE_COPY;
65
66     static {
67         Activator activator = Activator.getDefault();
68         if (activator == null) {
69             DEBUG = DEBUG_CONNECT = DEBUG_CACHE_LOOKUP = DEBUG_CACHE_COPY = false;
70         } else {
71             DebugOptions debugOptions = activator.getDebugOptions();
72             if (debugOptions != null) {
73                 DEBUG = debugOptions.getBooleanOption(OPTION_DEBUG, false);
74                 DEBUG_CONNECT = debugOptions.getBooleanOption(OPTION_DEBUG_CONNECT, true);
75                 DEBUG_CACHE_LOOKUP = debugOptions.getBooleanOption(OPTION_DEBUG_CACHE_LOOKUP, true);
76                 DEBUG_CACHE_COPY = debugOptions.getBooleanOption(OPTION_DEBUG_CACHE_COPY, true);
77             } else
78                 DEBUG = DEBUG_CONNECT = DEBUG_CACHE_LOOKUP = DEBUG_CACHE_COPY = false;
79         }
80     }
81
82     protected PlatformURLConnection(URL JavaDoc url) {
83         super(url);
84     }
85
86     protected boolean allowCaching() {
87         return false;
88     }
89
90     public void connect() throws IOException {
91         connect(false);
92     }
93
94     private synchronized void connect(boolean asLocal) throws IOException {
95         if (connected)
96             return;
97
98         if (shouldCache(asLocal)) {
99             try {
100                 URL JavaDoc inCache = getURLInCache();
101                 if (inCache != null)
102                     connection = inCache.openConnection();
103             } catch (IOException e) {
104                 // failed to cache ... will use resolved URL instead
105
}
106         }
107
108         // use resolved URL
109
if (connection == null)
110             connection = resolvedURL.openConnection();
111         connected = true;
112         if (DEBUG && DEBUG_CONNECT)
113             debug("Connected as " + connection.getURL()); //$NON-NLS-1$
114
}
115
116     //TODO consider refactoring this method... it is too long
117
//TODO avoid cryptic identifiers such as ix, tgt, tmp, srcis, tgtos...
118
private void copyToCache() throws IOException {
119
120         if (isInCache | cachedURL == null)
121             return;
122         String JavaDoc tmp;
123         int ix;
124
125         // cache entry key
126
String JavaDoc key;
127         if (isJar) {
128             tmp = url.getFile();
129             ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
130             if (ix != -1)
131                 tmp = tmp.substring(0, ix);
132             key = tmp;
133         } else
134             key = url.getFile();
135
136         // source url
137
URL JavaDoc src;
138         if (isJar) {
139             tmp = resolvedURL.getFile();
140             ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
141             if (ix != -1)
142                 tmp = tmp.substring(0, ix);
143             src = new URL JavaDoc(tmp);
144         } else
145             src = resolvedURL;
146         InputStream srcis = null;
147
148         // cache target
149
String JavaDoc tgt;
150         if (isJar) {
151             tmp = cachedURL.getFile();
152             ix = tmp.indexOf(PlatformURLHandler.PROTOCOL_SEPARATOR);
153             if (ix != -1)
154                 tmp = tmp.substring(ix + 1);
155             ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
156             if (ix != -1)
157                 tmp = tmp.substring(0, ix);
158             tgt = tmp;
159         } else
160             tgt = cachedURL.getFile();
161         File tgtFile = null;
162         FileOutputStream tgtos = null;
163
164         boolean error = false;
165         long total = 0;
166
167         try {
168             if (DEBUG && DEBUG_CACHE_COPY) {
169                 if (isJar)
170                     debug("Caching jar as " + tgt); //$NON-NLS-1$
171
else
172                     debug("Caching as " + tgt); //$NON-NLS-1$
173
}
174
175             srcis = src.openStream();
176             byte[] buf = new byte[BUF_SIZE];
177             int count = srcis.read(buf);
178
179             tgtFile = new File(tgt);
180             tgtos = new FileOutputStream(tgtFile);
181
182             while (count != -1) {
183                 total += count;
184                 tgtos.write(buf, 0, count);
185                 count = srcis.read(buf);
186             }
187
188             srcis.close();
189             srcis = null;
190             tgtos.flush();
191             tgtos.getFD().sync();
192             tgtos.close();
193             tgtos = null;
194
195             // add cache entry
196
cacheIndex.put(key, tgt);
197             isInCache = true;
198         } catch (IOException e) {
199             error = true;
200             cacheIndex.put(key, NOT_FOUND);
201             // mark cache entry for this execution
202
if (DEBUG && DEBUG_CACHE_COPY)
203                 debug("Failed to cache due to " + e); //$NON-NLS-1$
204
throw e;
205         } finally {
206             if (!error && DEBUG && DEBUG_CACHE_COPY)
207                 debug(total + " bytes copied"); //$NON-NLS-1$
208
if (srcis != null)
209                 srcis.close();
210             if (tgtos != null)
211                 tgtos.close();
212         }
213     }
214
215     protected void debug(String JavaDoc s) {
216         System.out.println("URL " + getURL().toString() + "^" + Integer.toHexString(Thread.currentThread().hashCode()) + " " + s); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
217
}
218
219     private static void debugStartup(String JavaDoc s) {
220         System.out.println("URL " + s); //$NON-NLS-1$
221
}
222
223     public URL JavaDoc[] getAuxillaryURLs() throws IOException {
224         return null;
225     }
226
227     public synchronized InputStream getInputStream() throws IOException {
228         if (!connected)
229             connect();
230         return connection.getInputStream();
231     }
232
233     public URL JavaDoc getResolvedURL() {
234         return resolvedURL;
235     }
236
237     public URL JavaDoc getURLAsLocal() throws IOException {
238         connect(true); // connect and force caching if necessary
239
URL JavaDoc u = connection.getURL();
240         String JavaDoc up = u.getProtocol();
241         if (!up.equals(PlatformURLHandler.FILE) && !up.equals(PlatformURLHandler.JAR) && !up.startsWith(PlatformURLHandler.BUNDLE))
242             throw new IOException(NLS.bind(CommonMessages.url_noaccess, up));
243         return u;
244     }
245
246     //TODO consider refactoring this method... it is too long
247
private URL JavaDoc getURLInCache() throws IOException {
248
249         if (!allowCaching())
250             return null; // target should not be cached
251

252         if (isInCache)
253             return cachedURL;
254
255         if (cacheLocation == null | cacheIndex == null)
256             return null; // not caching
257

258         // check if we are dealing with a .jar/ .zip
259
String JavaDoc file = ""; //$NON-NLS-1$
260
String JavaDoc jarEntry = null;
261         if (isJar) {
262             file = url.getFile();
263             int ix = file.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
264             if (ix != -1) {
265                 jarEntry = file.substring(ix + PlatformURLHandler.JAR_SEPARATOR.length());
266                 file = file.substring(0, ix);
267             }
268         } else {
269             file = url.getFile();
270         }
271
272         // check for cached entry
273
String JavaDoc tmp = (String JavaDoc) cacheIndex.get(file);
274
275         // check for "not found" marker
276
if (tmp != null && tmp == NOT_FOUND)
277             throw new IOException();
278
279         // validate cache entry
280
if (tmp != null && !(new File(tmp)).exists()) {
281             tmp = null;
282             cacheIndex.remove(url.getFile());
283         }
284
285         // found in cache
286
if (tmp != null) {
287             if (isJar) {
288                 if (DEBUG && DEBUG_CACHE_LOOKUP)
289                     debug("Jar located in cache as " + tmp); //$NON-NLS-1$
290
tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;
291                 cachedURL = new URL JavaDoc(PlatformURLHandler.JAR, null, -1, tmp);
292             } else {
293                 if (DEBUG && DEBUG_CACHE_LOOKUP)
294                     debug("Located in cache as " + tmp); //$NON-NLS-1$
295
cachedURL = new URL JavaDoc(PlatformURLHandler.FILE, null, -1, tmp);
296             }
297             isInCache = true;
298         } else {
299             // attempt to cache
300
int ix = file.lastIndexOf("/"); //$NON-NLS-1$
301
tmp = file.substring(ix + 1);
302             tmp = cacheLocation + filePrefix + Long.toString((new java.util.Date JavaDoc()).getTime()) + "_" + tmp; //$NON-NLS-1$
303
tmp = tmp.replace(File.separatorChar, '/');
304             if (isJar) {
305                 tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;
306                 cachedURL = new URL JavaDoc(PlatformURLHandler.JAR, null, -1, tmp);
307             } else
308                 cachedURL = new URL JavaDoc(PlatformURLHandler.FILE, null, -1, tmp);
309             copyToCache();
310         }
311
312         return cachedURL;
313     }
314
315     /*
316      * to be implemented by subclass
317      * @return URL resolved URL
318      */

319     protected URL JavaDoc resolve() throws IOException {
320         // TODO throw UnsupportedOperationException instead - this is a bug in subclass, not an actual failure
321
throw new IOException();
322     }
323
324     protected String JavaDoc getId(String JavaDoc spec) {
325         String JavaDoc id = (String JavaDoc) parse(spec)[0];
326         return id == null ? spec : id;
327     }
328
329     protected String JavaDoc getVersion(String JavaDoc spec) {
330         Version version = (Version) parse(spec)[1];
331         return version == null ? "" : version.toString(); //$NON-NLS-1$
332
}
333
334     private Object JavaDoc[] parse(String JavaDoc spec) {
335         String JavaDoc bsn = null;
336         Version version = null;
337         int underScore = spec.indexOf('_');
338         while (underScore >= 0) {
339             bsn = spec.substring(0, underScore);
340             try {
341                 version = Version.parseVersion(spec.substring(underScore + 1));
342             } catch (IllegalArgumentException JavaDoc iae) {
343                 // continue to next underscore
344
underScore = spec.indexOf('_', underScore + 1);
345                 continue;
346             }
347             break;
348         }
349         return new Object JavaDoc[] {bsn, version};
350     }
351
352     void setResolvedURL(URL JavaDoc url) throws IOException {
353         if (url == null)
354             throw new IOException();
355         if (resolvedURL != null)
356             return;
357         int ix = url.getFile().lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
358         isJar = -1 != ix;
359         // Resolved URLs containing !/ separator are assumed to be jar URLs.
360
// If the resolved protocol is not jar, new jar URL is created.
361
if (isJar && !url.getProtocol().equals(PlatformURLHandler.JAR))
362             url = new URL JavaDoc(PlatformURLHandler.JAR, "", -1, url.toExternalForm()); //$NON-NLS-1$
363
resolvedURL = url;
364     }
365
366     private boolean shouldCache(boolean asLocal) {
367
368         // don't cache files that are known to be local
369
String JavaDoc rp = resolvedURL.getProtocol();
370         String JavaDoc rf = resolvedURL.getFile();
371         if (rp.equals(PlatformURLHandler.FILE))
372             return false;
373         if (rp.equals(PlatformURLHandler.JAR) && (rf.startsWith(PlatformURLHandler.FILE)))
374             return false;
375
376         // for other files force caching if local connection was requested
377
if (asLocal)
378             return true;
379
380         // for now cache all files
381
// XXX: add cache policy support
382
return true;
383     }
384
385     static void shutdown() {
386         if (indexName != null && cacheLocation != null) {
387             // weed out "not found" entries
388
Enumeration JavaDoc keys = cacheIndex.keys();
389             String JavaDoc key;
390             Object JavaDoc value;
391             while (keys.hasMoreElements()) {
392                 key = (String JavaDoc) keys.nextElement();
393                 value = cacheIndex.get(key);
394                 if (value == NOT_FOUND)
395                     cacheIndex.remove(key);
396             }
397             //if the cache index is empty we don't need to save it
398
if (cacheIndex.size() == 0)
399                 return;
400             try {
401                 // try to save cache index
402
FileOutputStream fos = null;
403                 fos = new FileOutputStream(cacheLocation + indexName);
404                 try {
405                     cacheIndex.store(fos, null);
406                     fos.flush();
407                     fos.getFD().sync();
408                 } finally {
409                     fos.close();
410                 }
411             } catch (IOException e) {
412                 // failed to store cache index ... ignore
413
}
414         }
415     }
416
417     //TODO consider splitting this method into two or more steps - it is too long
418
static void startup(String JavaDoc location, String JavaDoc os, String JavaDoc ws, String JavaDoc nl) {
419         verifyLocation(location); // check for platform location, ignore errors
420
String JavaDoc cacheProps = location.trim();
421         if (!cacheProps.endsWith(File.separator))
422             cacheProps += File.separator;
423         cacheProps += CACHE_PROP;
424         File cachePropFile = new File(cacheProps);
425         Properties JavaDoc props = null;
426         FileInputStream fis;
427
428         if (cachePropFile.exists()) {
429             // load existing properties
430
try {
431                 props = new Properties JavaDoc();
432                 fis = new FileInputStream(cachePropFile);
433                 try {
434                     props.load(fis);
435                 } finally {
436                     fis.close();
437                 }
438             } catch (IOException e) {
439                 props = null;
440             }
441         }
442
443         if (props == null) {
444             // first time up, or failed to load previous settings
445
props = new Properties JavaDoc();
446
447             String JavaDoc tmp = System.getProperty("user.home"); //$NON-NLS-1$
448
if (!tmp.endsWith(File.separator))
449                 tmp += File.separator;
450             tmp += CACHE_DIR;
451             props.put(CACHE_LOCATION_PROP, tmp);
452
453             tmp = Long.toString((new java.util.Date JavaDoc()).getTime());
454             props.put(CACHE_PREFIX_PROP, tmp);
455
456             tmp += CACHE_INDEX;
457             props.put(CACHE_INDEX_PROP, tmp);
458
459             // save for next time around
460
FileOutputStream fos = null;
461             try {
462                 fos = new FileOutputStream(cachePropFile);
463                 try {
464                     props.store(fos, null);
465                     fos.flush();
466                     fos.getFD().sync();
467                 } finally {
468                     fos.close();
469                 }
470             } catch (IOException e) {
471                 // failed to store cache location metadata ... ignore
472
}
473         }
474
475         // remember settings for shutdown processing
476
filePrefix = (String JavaDoc) props.get(CACHE_PREFIX_PROP);
477         indexName = (String JavaDoc) props.get(CACHE_INDEX_PROP);
478         cacheLocation = (String JavaDoc) props.get(CACHE_LOCATION_PROP);
479
480         if (DEBUG) {
481             debugStartup("Cache location: " + cacheLocation); //$NON-NLS-1$
482
debugStartup("Cache index: " + indexName); //$NON-NLS-1$
483
debugStartup("Cache file prefix: " + filePrefix); //$NON-NLS-1$
484
}
485
486         // create cache directory structure if needed
487
if (!verifyLocation(cacheLocation)) {
488             indexName = null;
489             cacheLocation = null;
490             if (DEBUG)
491                 debugStartup("Failed to create cache directory structure. Caching suspended"); //$NON-NLS-1$
492
return;
493         }
494
495         // attempt to initialize cache index
496
if (cacheLocation != null && indexName != null) {
497             try {
498                 fis = new FileInputStream(cacheLocation + indexName);
499                 try {
500                     cacheIndex.load(fis);
501                 } finally {
502                     fis.close();
503                 }
504             } catch (IOException e) {
505                 if (DEBUG)
506                     debugStartup("Failed to initialize cache"); //$NON-NLS-1$
507
}
508         }
509     }
510
511     private static boolean verifyLocation(String JavaDoc location) {
512         // verify cache directory exists. Create if needed
513
File cacheDir = new File(location);
514         if (cacheDir.exists())
515             return true;
516         return cacheDir.mkdirs();
517     }
518 }
519
Popular Tags