package dmg.util.command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import dmg.cells.nucleus.DelayedReply;
import dmg.cells.nucleus.Reply;
import dmg.util.CommandPanicException;
import org.dcache.util.ReflectionUtils;
/**
* Abstract base class for annotated commands for executing the command
* asynchronously using an executor.
*
* By default a new thread is spawned for each command.
*/
public abstract class DelayedCommand<T extends Serializable>
extends DelayedReply
implements Callable<Reply>, Runnable
{
private static final Logger LOGGER = LoggerFactory.getLogger(DelayedCommand.class);
private final Executor executor;
protected DelayedCommand()
{
this(command -> new Thread(command).start());
}
protected DelayedCommand(Executor executor)
{
this.executor = executor;
}
@Override
public Reply call() throws Exception
{
executor.execute(this);
return this;
}
protected abstract T execute() throws Exception;
@Override
public void run()
{
Serializable result;
try {
result = execute();
} catch (Exception e) {
try {
Method method = ReflectionUtils.getAnyMethod(getClass(), "execute");
if (!ReflectionUtils.hasDeclaredException(method, e)) {
LOGGER.error("Command failed due to a bug, please contact support@dcache.org.", e);
e = new CommandPanicException("Command failed: " + e, e);
}
} catch (NoSuchMethodException suppressed) {
e.addSuppressed(suppressed);
}
result = e;
}
reply(result);
}
}