package com.nutiteq.task; import java.util.Timer; import java.util.TimerTask; import com.nutiteq.cache.Cache; import com.nutiteq.fs.FileSystem; import com.nutiteq.io.RetrieveResourceTask; import com.nutiteq.license.LicenseKeyCheck; import com.nutiteq.log.Log; import com.nutiteq.net.DownloadCounter; import com.nutiteq.net.DownloadStreamOpener; public class TaskWorker extends Thread { private boolean stopping; private TasksRunner tasksRunner; private DownloadStreamOpener downloadStreamOpener; private Cache networkCache; private Object currentObject; private DownloadCounter downloadCounter; private FileSystem fileSystem; private LicenseKeyCheck licenseKeyCheck; private final Timer timeoutTimer = new Timer(); public TaskWorker(final TasksRunner tasksRunner, final DownloadStreamOpener downloadStreamOpener, final Cache networkCache, final DownloadCounter downloadCounter, final FileSystem fileSystem, final LicenseKeyCheck licenseKeyCheck) { this.tasksRunner = tasksRunner; this.downloadStreamOpener = downloadStreamOpener; this.networkCache = networkCache; this.downloadCounter = downloadCounter; this.fileSystem = fileSystem; this.licenseKeyCheck = licenseKeyCheck; } public void run() { setPriority(MIN_PRIORITY); while (!stopping) { synchronized (this) { // is queue empty? if (!tasksRunner.hasMoreTasks()) { try { wait(); } catch (final InterruptedException ignore) { } } currentObject = tasksRunner.getNextTask(); } if (stopping) { break; } if (currentObject == null) { continue; } executeTask(currentObject, true); currentObject = null; } tasksRunner = null; downloadStreamOpener = null; networkCache = null; downloadCounter = null; fileSystem = null; licenseKeyCheck = null; } protected void executeTask(final Object currentObject, final boolean onErrorInitializeNewWorker) { boolean done = false; try { boolean isNetworkTask = false; if (currentObject instanceof NetworkTask) { isNetworkTask = true; ((NetworkTask) currentObject).initialize(downloadStreamOpener, networkCache, downloadCounter); if (licenseKeyCheck != null) { tasksRunner.enqueueDownload(licenseKeyCheck, Cache.CACHE_LEVEL_NONE); licenseKeyCheck = null; } } else if (currentObject instanceof RetrieveResourceTask) { ((RetrieveResourceTask) currentObject).initialize(downloadStreamOpener, networkCache, downloadCounter, tasksRunner, fileSystem); } Timeout timeout = null; if (isNetworkTask) { timeout = new Timeout(currentObject, this, System.currentTimeMillis()); timeoutTimer.schedule(timeout, downloadStreamOpener.getTimeout()); } ((Task) currentObject).execute(); done = true; if (timeout != null) { timeout.cancel(); } } catch (final Exception e) { Log.error("Error in task runner: " + e.getMessage()); Log.printStackTrace(e); notifyError(currentObject); } finally { if (done) { tasksRunner.taskCompleted(); } else if (onErrorInitializeNewWorker && !stopping) { Log.debug("TW: create new worker"); stopping = true; final TaskWorker next = new TaskWorker(tasksRunner, downloadStreamOpener, networkCache, downloadCounter, fileSystem, licenseKeyCheck); tasksRunner.setWorker(next); next.start(); } } } private void notifyError(final Object executed) { if (executed instanceof NetworkTask) { ((NetworkTask) executed).notifyError(); } } public void setDownloadStreamOpener(final DownloadStreamOpener opener) { downloadStreamOpener = opener; } public void setNetworkCache(final Cache networkCache) { this.networkCache = networkCache; } public synchronized void quit() { stopping = true; notify(); } public void setDownloadCounter(final DownloadCounter downloadCounter) { this.downloadCounter = downloadCounter; } public void setFileSystem(final FileSystem fs) { this.fileSystem = fs; } public Cache getNetworkCache() { return networkCache; } public FileSystem getFileSystem() { return fileSystem; } public void setLicenceKeyCheck(final LicenseKeyCheck licenseKeyCheck) { this.licenseKeyCheck = licenseKeyCheck; } private static class Timeout extends TimerTask { private final Object executed; private final TaskWorker worker; private final long startTime; public Timeout(final Object currentObject, final TaskWorker worker, final long startTime) { this.executed = currentObject; this.worker = worker; this.startTime = startTime; } public void run() { if (worker.currentObject == executed) { Log.debug("TO: interrupt after " + (System.currentTimeMillis() - startTime)); worker.interrupt(); } } } }