package adept.artifact;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.concurrent.Callable;
import adept.artifact.models.Artifact;
import adept.artifact.models.ArtifactHash;
import adept.artifact.models.ArtifactLocation;
import adept.logging.JavaLogger;
import adept.progress.ProgressMonitor;
public class ArtifactDownloader implements Callable<ArtifactDownloadResult> {
static public String USER_AGENT = "AdeptDownloader/1.0-ALPHA";
static private int MAX_RETRIES_DEFAULT = 5;
final private Artifact artifact;
final private File tmpFile;
final private JavaLogger logger;
final private int maxRetries;
final private String filename;
final private ProgressMonitor progress;
private File baseDir;
public ArtifactDownloader(Artifact artifact, String filename, File tmpFile, JavaLogger logger, ProgressMonitor progress) {
this.artifact = artifact;
this.tmpFile = tmpFile;
this.filename = filename;
this.logger = logger;
this.progress = progress;
this.maxRetries = MAX_RETRIES_DEFAULT;
}
public ArtifactDownloader(File baseDir, Artifact artifact, String filename, File tmpFile, int maxRetries,
JavaLogger logger, ProgressMonitor progress) {
this.baseDir = baseDir;
this.artifact = artifact;
this.tmpFile = tmpFile;
this.filename = filename;
this.logger = logger;
this.maxRetries = maxRetries;
this.progress = progress;
}
protected boolean verify = true;
@Override
public ArtifactDownloadResult call() throws Exception {
if (artifact.locations.size() != 1)
throw new Exception("Locations different from 1 is not currently implemented and we got: " + artifact); // TODO:
// implement!
ArtifactLocation location = artifact.locations.iterator().next();
URL url = location.getURL();
int retries = 0;
ArtifactDownloadResult result = null;
while (result == null) {
FileOutputStream fos = null;
InputStream is = null;
try {
ArtifactHash hash = artifact.hash;
File currentCachedFile = ArtifactCache.getOrCreateExistingCacheFile(baseDir, hash, filename, verify);
if (currentCachedFile != null && currentCachedFile.isFile()) {
result = new ArtifactDownloadResult(artifact, tmpFile, filename);
result.setCachedFile(currentCachedFile);
} else {
URLConnection conn = url.openConnection();
conn.setRequestProperty("User-Agent", USER_AGENT);
is = conn.getInputStream();
ReadableByteChannel rbc = Channels.newChannel(is);
fos = new FileOutputStream(tmpFile);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
result = new ArtifactDownloadResult(artifact, tmpFile, filename);
File srcFile = tmpFile;
result.setCachedFile(ArtifactCache.cache(baseDir, srcFile, hash, filename));
}
Long kilobytesDownloaded = artifact.size / 1024;
progress.update(kilobytesDownloaded.intValue());
} catch (IOException ioException) {
logger.debug("Got exception: " + ioException.getMessage() + " cause: " + ioException.getCause());
retries = retries + 1;
if (retries > maxRetries)
result = new ArtifactDownloadResult(artifact, filename, ioException);
else {
logger.debug("Sleeping before retrying...");
Thread.sleep(500); // sleeping in a callable makes me worried.... make
// sure we are not doing something too stupid
// here...
}
} finally {
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
}
}
return result;
}
}