package wowodc.background.tasks; import java.util.concurrent.Callable; import java.util.concurrent.Future; import wowodc.eof.TaskInfo; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOGlobalID; import com.webobjects.foundation.NSTimestamp; import er.extensions.concurrency.ERXExecutorService; import er.extensions.concurrency.ERXTask; import er.extensions.concurrency.IERXPercentComplete; import er.extensions.concurrency.IERXStoppable; import er.extensions.foundation.IERXStatus; /** * A demo task that runs two other tasks in sequence and uses the result of the first as the argument for the second. * * @author kieran */ public class T07EOFTaskWithSubTasks extends ERXTask<EOGlobalID> implements Callable<EOGlobalID>, IERXStatus, IERXPercentComplete, IERXStoppable { private T04SimpleEOFTask _task1 = null; private T06EOFFactorialUpdateTask _task2 = null; private volatile boolean _isStopped = false; private EOGlobalID _taskInfoGID = null; @Override public EOGlobalID _call() throws Exception { long startTime = System.currentTimeMillis(); if (!_isStopped) { _task1 = new T04SimpleEOFTask(); // Two ways to skin the cat (http://www.worldwidewords.org/qa/qa-mor1.htm) are shown here // For the first task, we simple execute it in the current thread by calling it directly _taskInfoGID = _task1.call(); } if (!_isStopped) { // We create an ec just for the sake of the constructor API on // T06EOFFactorialUpdateTask EOEditingContext ec = newEditingContext(); ec.lock(); try { TaskInfo taskInfo = (TaskInfo) ec.faultForGlobalID(_taskInfoGID, ec); _task2 = new T06EOFFactorialUpdateTask(taskInfo); } finally { ec.unlock(); } // Sometimes it ise useful to share the parent OSC with a subtask to avoid data out of sync issues _task2.setParentObjectStore(parentObjectStore()); // Here we show how the second task can be executed in yet another thread while this // thread waits for the result Future<EOGlobalID> future = ERXExecutorService.executorService().submit(_task2); // This next statement blocks until the task, running in another thread, is complete. _taskInfoGID = future.get(); // Finally, overwrite the startTime and Duration to reflect this combo task // rather than the last task. ec = newEditingContext(); ec.lock(); try { TaskInfo taskInfo = (TaskInfo) ec.faultForGlobalID(_taskInfoGID, ec); taskInfo.setStartTime(new NSTimestamp(startTime)); taskInfo.setDuration(Long.valueOf(taskInfo.endTime().getTime() - startTime)); ec.saveChanges(); } finally { ec.unlock(); } } return _taskInfoGID; } public void stop() { _isStopped = true; if (_task1 != null) { _task1.stop(); } if (_task2 != null) { _task2.stop(); } } public Double percentComplete() { double _percent = 0.0d; if (_task1 != null) { _percent += _task1.percentComplete().doubleValue(); } if (_task2 != null) { _percent += _task2.percentComplete().doubleValue(); } // Two tasks, so get the average completion. // This also works for parallel tasks return Double.valueOf(_percent / 2); } public String status() { String _status = "Processing"; // Check last task first (acceptable approach when each consecutive task is created as needed) if (_task2 != null) { return "Factorials: " + _task2.status(); } if (_task1 != null) { return "Primes: " + _task1.status(); } // Default return _status; } }