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 MessageClientExecutor<C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>>
extends PendingQueueClientExecutor<Message.ClientRequest<?>, Message.ServerResponse<?>, PendingQueueClientExecutor.RequestTask<Message.ClientRequest<?>, Message.ServerResponse<?>>, C, PendingQueueClientExecutor.PendingPromiseTask> {
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> MessageClientExecutor<C> newInstance(
ConnectMessage.Request request,
C connection,
ScheduledExecutorService executor) {
return newInstance(
ConnectTask.connect(request, connection),
connection,
TimeValue.milliseconds(request.getTimeOut()),
executor);
}
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> MessageClientExecutor<C> newInstance(
ListenableFuture<ConnectMessage.Response> session,
C connection,
TimeValue timeOut,
ScheduledExecutorService executor) {
return new MessageClientExecutor<C>(
LogManager.getLogger(MessageClientExecutor.class),
session,
connection,
timeOut,
executor);
}
protected final MessageActor actor;
protected MessageClientExecutor(
Logger logger,
ListenableFuture<ConnectMessage.Response> session,
C connection,
TimeValue timeOut,
ScheduledExecutorService scheduler) {
super(logger, session, connection, timeOut, scheduler);
this.actor = new MessageActor(logger);
}
@Override
public ListenableFuture<Message.ServerResponse<?>> submit(
Message.ClientRequest<?> request, Promise<Message.ServerResponse<?>> promise) {
RequestTask<Message.ClientRequest<?>, Message.ServerResponse<?>> task =
RequestTask.<Message.ClientRequest<?>, Message.ServerResponse<?>>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 MessageActor actor() {
return actor;
}
@Override
protected Logger logger() {
return actor.logger();
}
protected class MessageActor extends ForwardingActor {
protected MessageActor(
Logger logger) {
super(connection, logger);
}
@Override
protected boolean apply(RequestTask<Message.ClientRequest<?>, Message.ServerResponse<?>> input) {
if (! input.isDone()) {
PendingPromiseTask task = PendingPromiseTask.create(
input.promise(),
new SoftReference<Message.ClientRequest<?>>(input.task()),
SettableFuturePromise.<Message.ServerResponse<?>>create());
if (! pending.send(task)) {
input.cancel(true);
}
}
return true;
}
}
}