package edu.uw.zookeeper.protocol.client;
import java.lang.ref.SoftReference;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import edu.uw.zookeeper.common.LoggingFutureListener;
import edu.uw.zookeeper.common.Promise;
import edu.uw.zookeeper.common.SettableFuturePromise;
import edu.uw.zookeeper.common.TimeValue;
import edu.uw.zookeeper.protocol.Message;
import edu.uw.zookeeper.protocol.ConnectMessage;
import edu.uw.zookeeper.protocol.Operation;
import edu.uw.zookeeper.protocol.ProtocolConnection;
public class OperationClientExecutor<C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>>
extends PendingQueueClientExecutor<Operation.Request, Message.ServerResponse<?>, PendingQueueClientExecutor.RequestTask<Operation.Request, Message.ServerResponse<?>>, C, PendingQueueClientExecutor.PendingPromiseTask> {
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> OperationClientExecutor<C> newInstance(
ConnectMessage.Request request,
C connection,
ScheduledExecutorService executor) {
return newInstance(
request,
AssignXidProcessor.newInstance(),
connection,
executor);
}
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> OperationClientExecutor<C> newInstance(
ConnectMessage.Request request,
AssignXidProcessor xids,
C connection,
ScheduledExecutorService executor) {
return newInstance(
ConnectTask.connect(request, connection),
xids,
connection,
TimeValue.milliseconds(request.getTimeOut()),
executor);
}
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> OperationClientExecutor<C> newInstance(
ListenableFuture<ConnectMessage.Response> session,
AssignXidProcessor xids,
C connection,
TimeValue timeOut,
ScheduledExecutorService executor) {
return new OperationClientExecutor<C>(
xids,
LogManager.getLogger(OperationClientExecutor.class),
session,
connection,
timeOut,
executor);
}
protected final OperationActor actor;
protected final AssignXidProcessor xids;
protected OperationClientExecutor(
AssignXidProcessor xids,
Logger logger,
ListenableFuture<ConnectMessage.Response> session,
C connection,
TimeValue timeOut,
ScheduledExecutorService scheduler) {
super(logger, session, connection, timeOut, scheduler);
this.xids = xids;
this.actor = new OperationActor(logger);
}
@Override
public ListenableFuture<Message.ServerResponse<?>> submit(
Operation.Request request, Promise<Message.ServerResponse<?>> promise) {
RequestTask<Operation.Request, Message.ServerResponse<?>> task =
RequestTask.of(request, promise);
LoggingFutureListener.listen(logger(), task);
if (! send(task)) {
task.cancel(true);
}
return Futures.nonCancellationPropagating(task);
}
@Override
public void onSuccess(PendingPromiseTask result) {
try {
Message.ServerResponse<?> response = result.get();
result.getPromise().set(response);
} catch (ExecutionException e) {
result.getPromise().setException(e.getCause());
onFailure(e.getCause());
} catch (CancellationException e) {
result.getPromise().cancel(true);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
}
@Override
protected OperationActor actor() {
return actor;
}
@Override
protected Logger logger() {
return actor.logger();
}
protected class OperationActor extends ForwardingActor {
protected OperationActor(
Logger logger) {
super(connection, logger);
}
@Override
protected boolean apply(RequestTask<Operation.Request, Message.ServerResponse<?>> input) {
if (! input.isDone()) {
// Assign xids here so we can properly track message request -> response
Message.ClientRequest<?> message = (Message.ClientRequest<?>) xids.apply(input.task());
PendingPromiseTask task = PendingPromiseTask.create(
input.promise(),
new SoftReference<Message.ClientRequest<?>>(message),
SettableFuturePromise.<Message.ServerResponse<?>>create());
if (! pending.send(task)) {
input.cancel(true);
}
}
return true;
}
}
}