blob: 75b9243fd7bad5c20e72aed45a33f07a8cca8215 [file] [log] [blame]
package aQute.lib.deployer.obr;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
import aQute.bnd.service.ResourceHandle;
public class URLResourceHandle implements ResourceHandle {
static final String FILE_SCHEME = "file:";
static final String HTTP_SCHEME = "http:";
final File cacheDir;
// The resolved, absolute URL of the resource
final URL url;
// The local file, if the resource IS a file, otherwise null.
final File localFile;
// The cached file copy of the resource, if it is remote and has been downloaded.
final File cachedFile;
public URLResourceHandle(String url, String baseUrl, final File cacheDir) throws IOException {
this.cacheDir = cacheDir;
if (url.startsWith(FILE_SCHEME)) {
// File URL may be relative or absolute
File file = new File(url.substring(FILE_SCHEME.length()));
if (file.isAbsolute()) {
this.localFile = file;
} else {
if (!baseUrl.startsWith(FILE_SCHEME))
throw new IllegalArgumentException("Relative file URLs cannot be resolved if the base URL is a non-file URL.");
this.localFile = resolveFile(baseUrl.substring(FILE_SCHEME.length()), file.toString());
}
this.url = localFile.toURI().toURL();
if (!localFile.isFile() && !localFile.isDirectory())
throw new FileNotFoundException("File URL " + this.url + " points at a non-existing file.");
this.cachedFile = null;
} else if (url.startsWith(HTTP_SCHEME)) {
// HTTP URLs must be absolute
this.url = new URL(url);
this.localFile = null;
this.cachedFile = mapRemoteURL(this.url);
} else {
// A path with no scheme means resolve relative to the base URL
if (baseUrl.startsWith(FILE_SCHEME)) {
this.localFile = resolveFile(baseUrl.substring(FILE_SCHEME.length()), url);
this.url = localFile.toURI().toURL();
this.cachedFile = null;
} else {
URL base = new URL(baseUrl);
this.url = new URL(base, url);
this.localFile = null;
this.cachedFile = mapRemoteURL(this.url);
}
}
}
File resolveFile(String baseFileName, String fileName) {
File resolved;
File baseFile = new File(baseFileName);
if (baseFile.isDirectory())
resolved = new File(baseFile, fileName);
else if (baseFile.isFile())
resolved = new File(baseFile.getParentFile(), fileName);
else
throw new IllegalArgumentException("Cannot resolve relative to non-existant base file path: " + baseFileName);
return resolved;
}
private File mapRemoteURL(URL url) throws UnsupportedEncodingException {
String encoded = URLEncoder.encode(url.toString(), "UTF-8");
return new File(cacheDir, encoded);
}
public String getName() {
return url.toString();
}
public Location getLocation() {
Location result;
if (localFile != null)
result = Location.local;
else if (cachedFile.exists())
result = Location.remote_cached;
else
result = Location.remote;
return result;
}
public File request() throws IOException {
if (localFile != null)
return localFile;
if (cachedFile == null)
throw new IllegalStateException("Invalid URLResourceHandle: both local file and cache file are uninitialised.");
if (!cachedFile.exists()) {
cacheDir.mkdirs();
downloadToFile(url, cachedFile);
}
return cachedFile;
}
private static void downloadToFile(URL url, File file) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = url.openStream();
out = new FileOutputStream(file);
byte[] buf = new byte[1024];
for(;;) {
int bytes = in.read(buf, 0, 1024);
if (bytes < 0) break;
out.write(buf, 0, bytes);
}
} finally {
try { if (in != null) in.close(); } catch (IOException e) {};
try { if (out != null) in.close(); } catch (IOException e) {};
}
}
}