package com.droidworks.http.download; import java.io.IOException; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.LinkedList; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import android.util.Log; import com.droidworks.http.HttpGetWorker; import com.droidworks.http.HttpUtils; @Deprecated public class AsyncDownloader implements DownloadManager { public static final String LOG_LABEL = "AsyncDownloader"; private LinkedBlockingQueue<DownloadTask<?>> mTasks = new LinkedBlockingQueue<DownloadTask<?>>(500); private LinkedList<DownloadLooper> mLoopers = new LinkedList<DownloadLooper>(); private int mMaxThreads = 10; private int mPollDuration = 5; private int mDownloadCompleteTimeout = 3600; private static int mLooperCount = 0; private ExecutorService mExecutor; /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#setPollingDuration(int) */ public synchronized void setPollingDuration(int seconds) { mPollDuration = seconds; } /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#getThreadCount() */ public int getThreadCount() { int count = 0; for (DownloadLooper l : mLoopers) { if (l.getState() != Thread.State.TERMINATED) count++; } return count; } /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#isQueued(com.droidworks.http.download.DownloadTask) */ public boolean isQueued(DownloadTask<?> task) { if (mTasks.contains(task)) return true; return false; } /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#addDownloadTask(com.droidworks.http.download.DownloadTask) */ public void addDownloadTask(DownloadTask<?> task) { mTasks.add(task); // if no threads are running then we always start a thread if (getThreadCount() == 0) { startNewLooper(); } // if we have a backlog and have room for more threads, fire // another one up else if (mTasks.size() > 1 && getThreadCount() < mMaxThreads) { startNewLooper(); } drainLoopers(); } // drain off dead loopers private void drainLoopers() { ArrayList<DownloadLooper> removeList = new ArrayList<DownloadLooper>(); for (DownloadLooper l : mLoopers) { if (l.getState() == Thread.State.TERMINATED) { removeList.add(l); } } for (DownloadLooper l : removeList) { mLoopers.remove(l); } } private void startNewLooper() { DownloadLooper looper = new DownloadLooper("Looper " + ++mLooperCount); looper.start(); mLoopers.add(looper); } /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#cancelAll() */ public void cancelAll() { for (DownloadLooper l : mLoopers) { l.cancel(); l.interrupt(); } } /* (non-Javadoc) * @see com.droidworks.http.download.DownloadManager#setMaxThreads(int) */ public synchronized void setMaxThreads(int count) { mMaxThreads = count; } // private to prevent instantiation public AsyncDownloader() { mExecutor = Executors.newCachedThreadPool(); } class DownloadLooper extends Thread { private boolean _shutdown = false; private HttpGetWorker _worker; private final HttpClient _client = HttpUtils.getThreadSafeClient(); private int _resultCode; public DownloadLooper(String name) { super(name); } public void cancel() { _shutdown = true; if (_worker != null) { _worker.cancel(); } } @Override public void run() { android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_LOWEST); while (!_shutdown) { DownloadTask<?> task; // grab a task try { synchronized (AsyncDownloader.this) { _resultCode = -1; task = mTasks.poll(mPollDuration, TimeUnit.SECONDS); // shutdown on a null task if (task == null || _shutdown) { _shutdown = true; return; } // if we have a valid task, init a worker if (task.getUrl() != null) { HttpGet get = new HttpGet(task.getUrl()); // resetting the timeout each time is kind of lame // it makes more sense for the task's all to have the // same timeout value.. HttpUtils.setConnectionTimeout(_client, task.getTimeout()); _worker = new HttpGetWorker(get, null, _client); } } // if we have a worker, then we can do the download. if (_worker != null) { try { HttpResponse response = mExecutor.submit(_worker) .get(mDownloadCompleteTimeout, TimeUnit.SECONDS); task.processStream(response.getEntity().getContent()); } catch (ExecutionException e) { if (e.getCause() instanceof SocketTimeoutException) { _resultCode = DownloadTask.STATUS_TIMED_OUT; } // cancelled tasks are receiving an EE Log.e(LOG_LABEL, "Caught execution exception on task: " + task.getUrl(), e ); } catch (TimeoutException e) { _resultCode = DownloadTask.STATUS_TIMED_OUT; Log.e(LOG_LABEL, "Caught timeout exception task: " + task.getUrl(), e ); } catch (IllegalStateException e) { _resultCode = DownloadTask.STATUS_GENERAL_ERROR; Log.e(LOG_LABEL, "Caught exception: " + task.getUrl(), e ); } catch (IOException e) { _resultCode = DownloadTask.STATUS_GENERAL_ERROR; Log.e(LOG_LABEL, "Caught exception: " + task.getUrl(), e ); } } task.notifyListeners(); } catch (InterruptedException ignored) { _shutdown = true; } } } } @Override public void setTaskTimeout(int seconds) { // ignored } }