/**
*
*/
package interactivespaces.util.concurrency;
import org.apache.commons.logging.Log;
import java.util.concurrent.Future;
/**
* @author Keith M. Hughes
*/
public class SimpleManagedCommand implements ManagedCommand {
/**
* The command to be run.
*/
private final Runnable command;
/**
* The task of the command.
*/
private final WrappedTask task;
/**
* The managed commands this command is part of.
*/
private final SimpleManagedCommands managedCommands;
/**
* The future associated with this task.
*/
private Future<?> future;
/**
* The logger to use.
*/
private final Log log;
/**
* Construct a managed command for the given wrapped task.
*
* @param command
* the command to run
* @param managedCommands
* the managed commands that the command is part of
* @param repeating
* {@code true} if this command will be repeating
* @param allowTerminate
* {@code true} if the repeating command should be allowed to terminate if an exception is thrown
* @param log
* the log to use
*/
SimpleManagedCommand(Runnable command, SimpleManagedCommands managedCommands, boolean repeating,
boolean allowTerminate, Log log) {
this.command = command;
this.task = new WrappedTask(command, repeating, allowTerminate);
this.managedCommands = managedCommands;
this.log = log;
}
/**
* Set the future for this task.
*
* @param future
* the future
*/
void setFuture(Future<?> future) {
this.future = future;
}
/**
* Cancel the task whether or not it was running.
*/
public void cancel() {
synchronized (managedCommands) {
future.cancel(true);
managedCommands.removeManagedCommand(this);
}
}
/**
* Has the command been cancelled?
*
* @return {@code true} if cancelled
*/
public boolean isCancelled() {
return future.isCancelled();
}
/**
* Is the command done?
*
* @return {@code true} if done
*/
public boolean isDone() {
return future.isDone();
}
/**
* Get the task for the command.
*
* @return the wrapped task
*/
WrappedTask getTask() {
return task;
}
/**
* A runnable that logs exceptions.
*
* @author Keith M. Hughes
*/
class WrappedTask implements Runnable {
/**
* The actual runnable to be run.
*/
private final Runnable delegate;
/**
* {@code true} if this task is a repeating task.
*/
private final boolean repeating;
/**
* {@code true} if this task should terminate if an exception happens.
*/
private final boolean allowTerminate;
/**
* Construct a new wrapped task.
*
* @param delegate
* the actual runnable to run
* @param repeating
* {@code true} if this delegate will be repeating
* @param allowTerminate
* {@code true} if the potentially periodic running of the delegate can stop the periodic running
*/
WrappedTask(Runnable delegate, boolean repeating, boolean allowTerminate) {
this.delegate = delegate;
this.repeating = repeating;
this.allowTerminate = allowTerminate;
}
@Override
public void run() {
try {
delegate.run();
} catch (Throwable e) {
log.error("Exception caught during Managed Command", e);
if (allowTerminate) {
// This guarantees the future will stop immediately
throw new RuntimeException();
}
} finally {
if (!repeating) {
managedCommands.removeManagedCommand(SimpleManagedCommand.this);
}
}
}
}
}