package com.golshadi.majid.core.chunkWorker; import com.golshadi.majid.Utils.helper.FileUtils; import com.golshadi.majid.core.enums.TaskStates; import com.golshadi.majid.core.mainWorker.QueueModerator; import com.golshadi.majid.database.ChunksDataSource; import com.golshadi.majid.database.TasksDataSource; import com.golshadi.majid.database.elements.Chunk; import com.golshadi.majid.database.elements.Task; import com.golshadi.majid.report.ReportStructure; import com.golshadi.majid.report.listener.DownloadManagerListenerModerator; import java.util.HashMap; import java.util.List; /** * Created by Majid Golshadi on 4/14/2014. * * start * stop * downloader thread hear i call them AsyncWorker because i use AsyncTask instead of thread * for more information you can see these ref: */ public class Moderator { private ChunksDataSource chunksDataSource; // query on chunk table private TasksDataSource tasksDataSource; // query on task table public DownloadManagerListenerModerator downloadManagerListener; private HashMap<Integer , Thread> workerList; // chunk downloader list private HashMap<Integer , ReportStructure> processReports; // to save download percent private QueueModerator finishedDownloadQueueObserver; public Moderator(TasksDataSource tasksDS, ChunksDataSource chunksDS){ tasksDataSource = tasksDS; chunksDataSource = chunksDS; workerList = new HashMap<Integer, Thread>(); // chunk downloader with they id key processReports = new HashMap<Integer, ReportStructure>(); } public void setQueueObserver(QueueModerator queueObserver ){ finishedDownloadQueueObserver = queueObserver; } public void start(Task task, DownloadManagerListenerModerator listener){ downloadManagerListener = listener; // fetch task chunk info // set task state to Downloading // get any chunk file size calculate where it has to begin // start any of them as AsyncTask // fetch task chunk info List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(task.id); ReportStructure rps = new ReportStructure(); rps.setObjectValues(task, taskChunks); processReports.put(task.id, rps); Long downloaded; Long totalSize; if (taskChunks != null) { // set task state to Downloading // to lock start download again! task.state = TaskStates.DOWNLOADING; tasksDataSource.update(task); // get any chunk file size calculate for (Chunk chunk : taskChunks) { downloaded = new Long(FileUtils .size(task.save_address, String.valueOf(chunk.id))); totalSize = new Long(chunk.end - chunk.begin + 1); if (!task.resumable){ chunk.begin = 0; chunk.end = 0; // start one chunk as AsyncTask (duplicate code!! :( ) Thread chunkDownloaderThread = new AsyncWorker(task, chunk, this); workerList.put(chunk.id, chunkDownloaderThread); chunkDownloaderThread.start(); }else if (!downloaded.equals(totalSize)) { // where it has to begin // modify start point but i have not save it in Database chunk.begin = chunk.begin + downloaded; // start any of them as AsyncTask Thread chunkDownloaderThread = new AsyncWorker(task, chunk, this); workerList.put(chunk.id, chunkDownloaderThread); chunkDownloaderThread.start(); } } // notify to developer------------------------------------------------------------ downloadManagerListener.OnDownloadStarted(task.id); } } /* * pause all chunk thread related to one Task */ public void pause(int taskID){ Task task = tasksDataSource.getTaskInfo(taskID); if (task != null && task.state != TaskStates.PAUSED) { // pause task asyncWorker // change task state // save in DB // notify developer // pause task asyncWorker List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(task.id); for (Chunk chunk : taskChunks) { Thread worker = workerList.get(chunk.id); if (worker != null) { worker.interrupt(); workerList.remove(chunk.id); } } // change task state // save in DB task.state = TaskStates.PAUSED; tasksDataSource.update(task); // notify to developer------------------------------------------------------------ downloadManagerListener.OnDownloadPaused(task.id); } } public void connectionLost(int taskId) { downloadManagerListener.ConnectionLost(taskId); } /* to calculate download percentage if download task is un resumable it return -1 as percent */ private int downloadByteThreshold = 0; private final int THRESHOLD = 1024*20; public void process(int taskId, long byteRead){ ReportStructure report = processReports.get(taskId); double percent = -1; long downloadLength = report .setDownloadLength(byteRead); downloadByteThreshold += byteRead; if (downloadByteThreshold > THRESHOLD) { downloadByteThreshold = 0; if (report.isResumable()) { percent = ((float)downloadLength / report.getTotalSize() * 100); } // notify to developer------------------------------------------------------------ downloadManagerListener.onDownloadProcess(taskId, percent, downloadLength); } } public void rebuild(Chunk chunk){ workerList.remove(chunk.id); List<Chunk> taskChunks = chunksDataSource.chunksRelatedTask(chunk.task_id); // delete itself from worker list for (Chunk ch : taskChunks){ if ( workerList.get(ch.id) != null) return; } Task task = tasksDataSource.getTaskInfo(chunk.task_id); // set state task state to finished task.state = TaskStates.DOWNLOAD_FINISHED; tasksDataSource.update(task); // notify to developer------------------------------------------------------------ downloadManagerListener.OnDownloadFinished(task.id); // assign chunk files together Thread t = new Rebuilder(task, taskChunks, this); t.start(); } public void reBuildIsDone(Task task, List<Chunk> taskChunks) { // delete chunk row from chunk table for (Chunk chunk : taskChunks) { chunksDataSource.delete(chunk.id); FileUtils.delete(task.save_address, String.valueOf(chunk.id)); } // notify to developer------------------------------------------------------------ downloadManagerListener.OnDownloadRebuildFinished(task.id); // change task row state task.state = TaskStates.END; task.notify = false; tasksDataSource.update(task); // notify to developer------------------------------------------------------------ downloadManagerListener.OnDownloadCompleted(task.id); wakeUpObserver(task.id); } private void wakeUpObserver(int taskID) { if (finishedDownloadQueueObserver != null) { finishedDownloadQueueObserver.wakeUp(taskID); } } }