View Javadoc

1   /*
2    * $Id: DownloadFileOperation.java,v 1.7 2005/06/01 20:45:40 jlerner Exp $
3    *
4    * Copyright (c) 1999-2004, BBN Technologies, LLC.
5    * All rights reserved.
6    * http://www.daml.org/legal/opensource/bbn_license.html
7    */
8    
9   package com.bbn.swede.core.libraries;
10  
11  import java.io.BufferedInputStream;
12  import java.io.BufferedOutputStream;
13  import java.io.File;
14  import java.io.FileOutputStream;
15  import java.io.IOException;
16  import java.lang.reflect.InvocationTargetException;
17  import java.net.URL;
18  import java.net.URLConnection;
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.eclipse.core.runtime.IProgressMonitor;
23  import org.eclipse.jface.operation.IRunnableWithProgress;
24  
25  /***
26   * Generalized operation suitable for downloading a file from a URL.
27   * Supports progress monitoring and cancelation.  
28   * 
29   * This operation is intended to be run only once.  Attempting to 
30   * run the operation more than once will lead to undefined behaviour.
31   * 
32   * @author aperezlo
33   */
34  public class DownloadFileOperation implements IRunnableWithProgress
35  {
36     private IProgressMonitor _progressMonitor;
37     private URL _sourceURL;
38     private String _outfileName;
39     private File _outDirectory;
40     private File _localCache;
41     private ArrayList _exceptions;
42     private boolean _wasCanceled;
43     private boolean _shouldDelete;
44     
45     /***
46      * Creates a runnable to download a file from the web.
47      * @param source a {@link URL} representing the location of the file 
48      *               to be downloaded
49      * @param filename the name that the file should have once downloaded
50      * @param shouldDelete if this is <code>true</code>, the file will be set to
51      *        delete on exit 
52      */
53     public DownloadFileOperation(URL source, String filename, boolean shouldDelete)
54     {
55        this(source, new File(System.getProperty("java.io.tmpdir")), filename, shouldDelete);
56     }
57  
58     /***
59      * Creates a runnable to download a file from the web.
60      * @param source a {@link URL} representing the location of the file to be 
61      *               downloaded
62      * @param downloadDirectory the directory to which the file should be
63      *                          downloaded
64      * @param filename the name that the file should have once downloaded
65      * @param shouldDelete if this is <code>true</code>, the file will be set to
66      *                     delete on exit
67      */
68     public DownloadFileOperation(URL source, File downloadDirectory, String filename, boolean shouldDelete)
69     {
70        _outfileName = filename;
71        _sourceURL = source;
72        _exceptions = new ArrayList();
73        _shouldDelete = shouldDelete;
74        _outDirectory = downloadDirectory;
75     }
76     
77     
78     /***
79      * <p>Creates a runnable to download a file from the web.  The name that will
80      * be used for the local copy of the downloaded file is unspecified.</p>
81      * 
82      * <p>This is a convenience method, fully equivalent to
83      * <blockquote>DownloadFileOperation(source, null, true);</blockquote></p>
84      * @param source a {@link URL} representing the location of the file to be 
85      *               downloaded
86      */
87     public DownloadFileOperation(URL source)
88     {
89        this(source, null, true);
90     }
91     
92     /***
93      * Retrieves the source URL of the download operation.
94      * @return the source URL as given to the constructor
95      */
96     public URL getURL()
97     {
98        return _sourceURL;
99     }
100    
101    /***
102     * Indicates whether the operation was canceled.
103     * @return <code>true</code> if this operation was canceled by the progress
104     *         monitor, <code>false</code> otherwise
105     */
106    public boolean getWasCanceled()
107    {
108       return _wasCanceled;
109    }
110    
111    /***
112     * Returns a List containing any and all exceptions generated by 
113     * this operation.  If this list is empty, it can be assumed 
114     * that no exceptions occurred during the operation.
115     * 
116     * @return a List of all exceptions   
117     */
118    public List getExceptions()
119    {
120       return _exceptions;
121    }
122    
123    /***
124     * Return a handle to the downloaded file.  If the download 
125     * was unsuccessful, or was canceled, this value will be 
126     * <code>null</code>.
127     * 
128     * @return a handle to the downloaded file
129     */
130    public File getFile()
131    {
132       return _localCache;
133    }
134    
135    /*
136     * Downloads the file.  Will return progress information via the 
137     * progress monitor, and will obey cancelation actions taken upon 
138     * the progress monitor.
139     *  (non-Javadoc)
140     * @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
141     */
142    public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
143    {
144       monitor.beginTask("Downloading '" + _sourceURL.toExternalForm() + "'...", 110);
145       final int iChunkSize = 2048;
146       byte[] buffer = new byte[iChunkSize];
147       int length = iChunkSize;
148       int chunksDownloaded = 0;
149       int bytesDownloaded = 0;
150       Exception error = null;
151       URLConnection conn = null;
152       BufferedInputStream in = null;
153       BufferedOutputStream out = null;
154       try
155       {
156          if(_outfileName == null)
157          {
158             _localCache = File.createTempFile("tmp", null, _outDirectory);
159          }
160          else
161          {
162             _localCache = new File(_outDirectory, _outfileName);
163          }
164          if(_shouldDelete)
165          {
166             _localCache.deleteOnExit();
167          }
168          out = new BufferedOutputStream(new FileOutputStream(_localCache));
169          monitor.worked(5);
170          monitor.subTask("Opening Connection...");
171          conn = _sourceURL.openConnection();
172          monitor.worked(5);
173          final double contentLength = (double) conn.getContentLength();
174          in = new BufferedInputStream(conn.getInputStream());
175          monitor.subTask("Downloading...");
176          while(length > -1 && !monitor.isCanceled())
177          {
178             length = iChunkSize;
179             length = in.read(buffer, 0, length);
180             if(length > -1)
181             {
182                out.write(buffer, 0, length);
183                out.flush();
184             }
185             bytesDownloaded += length;
186             if(bytesDownloaded > (contentLength / 100))
187             {
188                monitor.worked((int) Math.floor(bytesDownloaded / (contentLength / 100)));
189                bytesDownloaded = 0;
190                length = iChunkSize;
191             }
192          }
193       }
194       catch (IOException e)
195       {
196          _exceptions.add(e);
197       }
198       finally
199       {
200          try
201          {
202             in.close();
203             out.close();
204             if(monitor.isCanceled())
205             {
206                _wasCanceled = true;
207                _localCache.delete();
208             }
209             monitor.done();
210          }
211          catch(Exception e)
212          {
213             _exceptions.add(e);
214          }
215       }
216    }
217 }