package ecologylab.io; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import ecologylab.appframework.StatusReporter; import ecologylab.concurrent.BasicSite; import ecologylab.concurrent.Downloadable; import ecologylab.concurrent.DownloadableLogRecord; import ecologylab.generic.Continuation; import ecologylab.generic.Debug; import ecologylab.net.ParsedURL; public class DownloadableFileToDisk extends Debug implements Downloadable, Continuation<Object> { private boolean downloadDone = false; private boolean downloadStarted = false; private InputStream inputStream = null; private OutputStream outputStream; private ParsedURL target; private File destination; private static final int BUFFER_SIZE = 8192; private StatusReporter status = null; private int fileSize = -1; public DownloadableFileToDisk(ParsedURL target, File destination, StatusReporter status) { this.target = target; this.destination = destination; this.status = status; } public DownloadableFileToDisk(ParsedURL target, InputStream inputStream, File destination, StatusReporter status) { this(target, destination, status); this.inputStream = inputStream; } public DownloadableFileToDisk(ParsedURL target, File destination) { this(target, destination, null); } public DownloadableFileToDisk(ParsedURL target, InputStream inputStream, File destination) { this(target, inputStream, destination, null); } @Override public void handleIoError(Throwable e) { closeStreams(); downloadDone = true; } public boolean isDownloadDone() { return downloadDone; } @Override public void performDownload() throws IOException { debug("performDownload() top"); if (downloadStarted) return; downloadStarted = true; //this gets the stream and sets the member field 'fileSize' // inputStream = getInputStream(zipSource); if (inputStream == null) inputStream = target.url().openStream(); debug("performDownload() got InputStream"); //actually read and write the file // if the file already exists, delete it //FIXME -- consider using the existing, instead of deleting it!!! if (destination.exists()) { boolean deleted = destination.delete(); debug("File exists, so deleting = " + deleted); } outputStream = new BufferedOutputStream(new FileOutputStream(destination)); debug("performDownload() got outputStream from " + destination); byte fileBytes[] = new byte[BUFFER_SIZE]; //Read data from the source url and write it out to the file int count = 0; int lastTenth = 1; int incrementSize = fileSize/10; //int i=0; while(( count = inputStream.read(fileBytes, 0, BUFFER_SIZE)) != -1 ) { if (status != null) { //Our status will be in 10% increments if (count >= incrementSize*(lastTenth)) status.display("Downloading file " + destination.getName(), 1, count/10, incrementSize); //can't just increment because we maybe skip/hit 1/10ths due to //faster/slower transfer rates, traffic, etc. lastTenth = (int) Math.floor(((double)count/fileSize)*10); } outputStream.write(fileBytes, 0, count); } closeStreams(); synchronized (this) { downloadDone = true; } } public void closeStreams() { try { if (outputStream != null) { OutputStream oStream = this.outputStream; this.outputStream = null; oStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (inputStream != null) { InputStream iStream = this.inputStream; this.inputStream = null; iStream.close(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void callback(Object o) { System.out.println("Finished download file: " + target + " -> " + destination); } @Override public boolean isRecycled() { // TODO Auto-generated method stub return false; } @Override public BasicSite getSite() { // TODO Auto-generated method stub return null; } @Override public ParsedURL location() { return target; } /** * * @return What to tell the user about what is being downloaded. */ @Override public String message() { return null; } @Override public void recycle() { } /** * Default empty implementation; will be ignored for this type. */ @Override public boolean isImage() { return false; } @Override public BasicSite getDownloadSite() { return null; } @Override public ParsedURL getDownloadLocation() { // TODO Auto-generated method stub return location(); } @Override public boolean isCached() { // TODO Auto-generated method stub return false; } @Override public DownloadableLogRecord getLogRecord() { // TODO Auto-generated method stub return null; } }