blob: e553e235903e56374311aba6c64f85860b1cfa0c [file] [log] [blame]
package org.eclipse.core.internal.boot;
/*
* Licensed Materials - Property of IBM,
* WebSphere Studio Workbench
* (c) Copyright IBM Corp 2000
*/
/**
* Platform URL support
*/
import java.net.*;
import java.io.*;
import java.util.*;
public abstract class PlatformURLConnection extends URLConnection {
// URL access
private boolean isInCache = false;
private boolean isJar = false;
// protected URL url; // declared in super (platform: URL)
private URL resolvedURL = null; // resolved file URL (eg. http: URL)
private URL cachedURL = null; // file URL in cache (file: URL)
private URLConnection connection = null; // actual connection
// local cache
private static Properties cacheIndex = new Properties();
private static String cacheLocation;
private static String indexName;
private static String filePrefix;
// constants
private static final int BUF_SIZE = 32768;
private static final Object NOT_FOUND = new Object(); // marker
private static final String CACHE_PROP = ".cache.properties";
private static final String CACHE_LOCATION_PROP = "location";
private static final String CACHE_INDEX_PROP = "index";
private static final String CACHE_PREFIX_PROP = "prefix";
private static final String CACHE_INDEX = ".index.properties";
private static final String CACHE_DIR = PlatformURLHandler.PROTOCOL + File.separator;
// debug tracing
public static boolean DEBUG = false;
public static boolean DEBUG_CONNECT = true;
public static boolean DEBUG_CACHE_LOOKUP = true;
public static boolean DEBUG_CACHE_COPY = true;
protected PlatformURLConnection(URL url) {
super(url);
}
protected boolean allowCaching() {
return false;
}
public void connect() throws IOException {
connect(false);
}
private synchronized void connect(boolean asLocal) throws IOException {
if (!connected) {
if (shouldCache(asLocal)) {
try {
URL inCache = getURLInCache();
if (inCache!=null) connection = inCache.openConnection();
} catch(IOException e) {
// failed to cache ... will use resolved URL instead
}
}
// use resolved URL
if (connection==null) connection = resolvedURL.openConnection();
connected = true;
if (DEBUG && DEBUG_CONNECT)
debug("Connected as "+connection.getURL());
}
}
private void copyToCache() throws IOException {
if (isInCache | cachedURL==null) return;
String tmp;
int ix;
// cache entry key
String key;
if (isJar) {
tmp = url.getFile();
ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
if (ix!=-1) tmp = tmp.substring(0,ix);
key = tmp;
}
else key = url.getFile();
// source url
URL src;
if (isJar) {
tmp = resolvedURL.getFile();
ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
if (ix!=-1) tmp = tmp.substring(0,ix);
src = new URL(tmp);
}
else src = resolvedURL;
InputStream srcis = null;
// cache target
String tgt;
if (isJar) {
tmp = cachedURL.getFile();
ix = tmp.indexOf(PlatformURLHandler.PROTOCOL_SEPARATOR);
if (ix!=-1) tmp = tmp.substring(ix+1);
ix = tmp.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
if (ix!=-1) tmp = tmp.substring(0,ix);
tgt = tmp;
}
else tgt = cachedURL.getFile();
File tgtFile = null;
FileOutputStream tgtos = null;
boolean error = false;
long total = 0;
try {
if (DEBUG && DEBUG_CACHE_COPY) {
if (isJar) debug ("Caching jar as "+tgt);
else debug("Caching as "+tgt);
}
srcis = src.openStream();
byte[] buf = new byte[BUF_SIZE];
int count = srcis.read(buf);
tgtFile = new File(tgt);
tgtos = new FileOutputStream(tgtFile);
while(count!=-1) {
total += count;
tgtos.write(buf,0,count);
count = srcis.read(buf);
}
srcis.close();
srcis=null;
tgtos.close();
tgtos=null;
// add cache entry
cacheIndex.put(key,tgt);
isInCache = true;
}
catch(IOException e) {
error = true;
cacheIndex.put(key,NOT_FOUND); // mark cache entry for this execution
if (DEBUG && DEBUG_CACHE_COPY)
debug("Failed to cache due to "+e);
throw e;
}
finally {
if (!error && DEBUG && DEBUG_CACHE_COPY)
debug(total + " bytes copied");
if (srcis!=null) srcis.close();
if (tgtos!=null) tgtos.close();
}
}
protected void debug(String s) {
System.out.println("URL "+getURL().toString()+"^"+Integer.toHexString(Thread.currentThread().hashCode())+" "+s);
}
private static void debugStartup(String s) {
System.out.println("URL "+s);
}
public synchronized InputStream getInputStream() throws IOException {
if (!connected) connect();
return connection.getInputStream();
}
public URL getResolvedURL() {
return resolvedURL;
}
public URL getURLAsLocal() throws IOException {
connect(true); // connect and force caching if necessary
URL u = connection.getURL();
String up = u.getProtocol();
if (!up.equals(PlatformURLHandler.FILE) && !up.equals(PlatformURLHandler.JAR) && !up.equals(PlatformURLHandler.VA)) throw new IOException("Unable to access URL as local "+url.toString());
return u;
}
private URL getURLInCache() throws IOException {
if (!allowCaching()) return null; // target should not be cached
if (isInCache) return cachedURL;
if (cacheLocation==null | cacheIndex==null) return null; // not caching
// check if we are dealing with a .jar/ .zip
String file = "";
String jarEntry = null;
if (isJar) {
file = url.getFile();
int ix = file.lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
if (ix!=-1) {
jarEntry = file.substring(ix+PlatformURLHandler.JAR_SEPARATOR.length());
file = file.substring(0,ix);
}
}
else {
file = url.getFile();
jarEntry = null;
}
// check for cached entry
String tmp = (String)cacheIndex.get(file);
// check for "not found" marker
if (tmp!=null && tmp==NOT_FOUND) throw new IOException();
// validate cache entry
if (tmp!=null && !(new File(tmp)).exists()) {
tmp = null;
cacheIndex.remove(url.getFile());
}
// found in cache
if (tmp!=null) {
if (isJar) {
if (DEBUG && DEBUG_CACHE_LOOKUP)
debug("Jar located in cache as "+tmp);
tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;
cachedURL = new URL(PlatformURLHandler.JAR,null,-1,tmp);
}
else {
if (DEBUG && DEBUG_CACHE_LOOKUP)
debug("Located in cache as "+tmp);
cachedURL = new URL(PlatformURLHandler.FILE,null,-1,tmp);
}
isInCache = true;
}
else {
// attemp to cache
int ix = file.lastIndexOf("/");
tmp = file.substring(ix+1);
tmp = cacheLocation + filePrefix + Long.toString((new java.util.Date()).getTime(),36) + "_" + tmp;
tmp = tmp.replace(File.separatorChar,'/');
if (isJar) {
tmp = PlatformURLHandler.FILE + PlatformURLHandler.PROTOCOL_SEPARATOR + tmp + PlatformURLHandler.JAR_SEPARATOR + jarEntry;
cachedURL = new URL(PlatformURLHandler.JAR,null,-1,tmp);
}
else cachedURL = new URL(PlatformURLHandler.FILE,null,-1,tmp);
copyToCache();
}
return cachedURL;
}
/*
* to be implemented by subclass
* @return URL resolved URL
*/
protected URL resolve() throws IOException {
throw new IOException();
}
void setResolvedURL(URL url) throws IOException {
if (resolvedURL==null) {
int ix = url.getFile().lastIndexOf(PlatformURLHandler.JAR_SEPARATOR);
isJar = -1 != ix;
// Resolved URLs containing !/ separator are assumed to be jar URLs.
// If the resolved protocol is not jar, new jar URL is created.
if (isJar && !url.getProtocol().equals(PlatformURLHandler.JAR)) url = new URL(PlatformURLHandler.JAR,null,-1,url.toExternalForm());
resolvedURL=url;
}
}
private boolean shouldCache(boolean asLocal) {
// don't cache files that are known to be local
String rp = resolvedURL.getProtocol();
String rf = resolvedURL.getFile();
if (rp.equals(PlatformURLHandler.FILE) || rp.equals(PlatformURLHandler.VA)) return false;
if (rp.equals(PlatformURLHandler.JAR) && (rf.startsWith(PlatformURLHandler.FILE) || rf.startsWith(PlatformURLHandler.VA) )) return false;
// for other files force caching if local connection was requested
if (asLocal) return true;
// for now cache all files
// XXX: add cache policy support
return true;
}
static void shutdown() {
if (indexName!=null && cacheLocation!=null) {
// weed out "not found" entries
Enumeration keys = cacheIndex.keys();
String key;
Object value;
while (keys.hasMoreElements()) {
key = (String) keys.nextElement();
value = cacheIndex.get(key);
if (value==NOT_FOUND) cacheIndex.remove(key);
}
// try to save cache index
FileOutputStream fos = null;
try {
fos = new FileOutputStream(cacheLocation+indexName);
try {
cacheIndex.store(fos,null);
}
finally {
fos.close();
}
}
catch(IOException e) {
// failed to store cache index ... ignore
}
}
}
static void startup(String location) {
verifyLocation(location); // check for platform location, ignore errors
String cacheProps = location.trim();
if (!cacheProps.endsWith(File.separator)) cacheProps += File.separator;
cacheProps += CACHE_PROP;
File cachePropFile = new File(cacheProps);
Properties props = null;
FileInputStream fis;
if (cachePropFile.exists()) {
// load existing properties
try {
props = new Properties();
fis = new FileInputStream(cachePropFile);
try {
props.load(fis);
}
finally {
fis.close();
}
}
catch(IOException e) {
props = null;
}
}
if (props==null) {
// first time up, or failed to load previous settings
props = new Properties();
String tmp = System.getProperty("java.io.tmpdir");
if (!tmp.endsWith(File.separator)) tmp += File.separator;
tmp += CACHE_DIR;
props.put(CACHE_LOCATION_PROP,tmp);
tmp = Long.toString((new java.util.Date()).getTime(),36);
props.put(CACHE_PREFIX_PROP,tmp);
tmp += CACHE_INDEX;
props.put(CACHE_INDEX_PROP,tmp);
// save for next time around
FileOutputStream fos = null;
try {
fos = new FileOutputStream(cachePropFile);
try {
props.store(fos,null);
}
finally {
fos.close();
}
}
catch(IOException e) {
// failed to store cache location metadata ... ignore
}
}
// remember settings for shutdown processing
filePrefix = (String)props.get(CACHE_PREFIX_PROP);
indexName = (String)props.get(CACHE_INDEX_PROP);
cacheLocation = (String)props.get(CACHE_LOCATION_PROP);
if (DEBUG) {
debugStartup("Cache location: " + cacheLocation);
debugStartup("Cache index: " + indexName);
debugStartup("Cache file prefix: " + filePrefix);
}
// create cache directory structure if needed
if (!verifyLocation(cacheLocation)) {
indexName = null;
cacheLocation = null;
if (DEBUG)
debugStartup("Failed to create cache directory structure. Caching suspended");
return;
}
// attempt to initialize cache index
if (cacheLocation!=null && indexName!=null) {
try {
fis = new FileInputStream(cacheLocation+indexName);
try {
cacheIndex.load(fis);
}
finally {
fis.close();
}
}
catch(IOException e) {
if (DEBUG)
debugStartup("Failed to initialize cache");
}
}
}
private static boolean verifyLocation(String location) {
// verify cache directory exists. Create if needed
StringTokenizer t = new StringTokenizer(location, File.separator);
String cacheName = "";
File cacheDir;
boolean result = true;
while(t.hasMoreElements()) {
cacheName += t.nextElement() + File.separator;
cacheDir = new File(cacheName);
if (!cacheDir.exists()) {
if (!cacheDir.mkdir()) {
result = false;
break;
}
}
}
return result;
}
}