/**
* Copyright (c) 2002-2005, Simone Bordet
* All rights reserved.
*
* This software is distributable under the BSD license.
* See the terms of the BSD license in the documentation provided with this software.
*/
package foxtrot;
import java.security.AccessControlContext;
import java.security.AccessController;
import javax.swing.SwingUtilities;
/**
* A time-consuming task to be executed in the Worker Thread that may throw checked exceptions. <br />
* Users must implement the {@link #run} method with the time-consuming code, and not worry about
* exceptions, for example:
* <pre>
* Task task = new Task()
* {
* public Object run() throws InterruptedException
* {
* Thread.sleep(10000);
* return null;
* }
* };
* </pre>
* Exceptions and Errors thrown by the <code>run()</code> method will be rethrown automatically by
* {@link Worker#post(Task)} or by {@link ConcurrentWorker#post(Task)}
* @see Worker
* @see ConcurrentWorker
* @version $Revision: 1.13 $
*/
public abstract class Task
{
private Object result;
private Throwable throwable;
private boolean completed;
private AccessControlContext securityContext;
/**
* Creates a new Task.
*/
protected Task()
{
securityContext = AccessController.getContext();
}
/**
* The method to implement with time-consuming code.
* It should NOT be synchronized or synchronize on this Task instance, otherwise the AWT Event Dispatch Thread
* cannot efficiently test when this Task is completed.
*/
public abstract Object run() throws Exception;
/**
* Returns the result of this Task operation, as set by {@link #setResult}.
* If an exception or an error is thrown by {@link #run}, it is rethrown here.
* Synchronized since the variables are accessed from 2 threads
* Accessed from the AWT Event Dispatch Thread.
* @see #setResult
* @see #setThrowable
*/
protected final synchronized Object getResultOrThrow() throws Exception
{
Throwable t = getThrowable();
if (t != null)
{
if (t instanceof Exception)
throw (Exception)t;
else
throw (Error)t;
}
return getResult();
}
/**
* Returns the result of this Task operation, as set by {@link #setResult}.
* Synchronized since the variable is accessed from 2 threads
* Accessed from the AWT Event Dispatch Thread.
* @see #getResultOrThrow
*/
private final synchronized Object getResult()
{
return result;
}
/**
* Sets the result of this Task operation, as returned by the {@link #run} method.
* Synchronized since the variable is accessed from 2 threads
* Accessed from the worker thread.
* Package protected, used by {@link AbstractWorkerThread}
* @see #getResultOrThrow
* @see #getResult
*/
final synchronized void setResult(Object result)
{
this.result = result;
}
/**
* Returns the throwable as set by {@link #setThrowable}.
* Synchronized since the variable is accessed from 2 threads
* Accessed from the AWT Event Dispatch Thread.
*/
final synchronized Throwable getThrowable()
{
return throwable;
}
/**
* Sets the throwable eventually thrown by the {@link #run} method.
* Synchronized since the variable is accessed from 2 threads
* Accessed from the worker thread.
* Package protected, used by {@link AbstractWorkerThread}
* @see #getThrowable
*/
final synchronized void setThrowable(Throwable x)
{
throwable = x;
}
/**
* Returns whether the execution of this Task has been completed or not.
*/
public final synchronized boolean isCompleted()
{
// Synchronized since the variable is accessed from 2 threads
// Accessed from the AWT Event Dispatch Thread.
return completed;
}
/**
* Sets the completion status of this Task.
* Synchronized since the variable is accessed from 2 threads.
* Accessed from the worker thread and from the AWT Event Dispatch Thread.
* Package protected, used by {@link AbstractWorkerThread}
* @see #isCompleted
*/
final synchronized void setCompleted(boolean value)
{
completed = value;
if (value) notifyAll();
}
/**
* Returns the protection domain stack at the moment of instantiation of this Task.
* Synchronized since the variable is accessed from 2 threads
* Accessed from the worker thread.
* Package protected, used by {@link AbstractWorkerThread}
* @see #Task
*/
final synchronized AccessControlContext getSecurityContext()
{
return securityContext;
}
/**
* Resets the internal status of this Task, that can be therefore be reused.
* Synchronized since the variables are accessed from 2 threads
* Accessed from the AWT Event Dispatch Thread.
* Package protected, used by Worker
* @see #isCompleted
*/
final synchronized void reset()
{
setResult(null);
setThrowable(null);
setCompleted(false);
}
/**
* Callback invoked from the worker thread to perform some operation just after the Task
* has been {@link #isCompleted completed}.
*/
void postRun()
{
// Needed in case that no events are posted on the AWT Event Queue
// via the normal mechanisms (mouse movements, key typing, etc):
// the AWT Event Queue is waiting in EventQueue.getNextEvent(),
// posting this one will wake it up and allow the event pump to
// finish its job and release control to the original pump
SwingUtilities.invokeLater(new Runnable()
{
public final void run()
{
if (AbstractWorker.debug) System.out.println("[Task] Run completed for task " + Task.this);
}
});
}
}