package edu.uw.zookeeper.protocol.client; import org.apache.zookeeper.KeeperException; import com.google.common.base.Optional; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import edu.uw.zookeeper.common.Automaton; import edu.uw.zookeeper.common.Pair; import edu.uw.zookeeper.common.Promise; import edu.uw.zookeeper.common.PromiseTask; import edu.uw.zookeeper.common.SettableFuturePromise; import edu.uw.zookeeper.net.Connection; import edu.uw.zookeeper.protocol.ConnectMessage; import edu.uw.zookeeper.protocol.Operation; public class ConnectTask<C extends Connection<? super ConnectMessage.Request, ? extends Operation.Response,?>> extends PromiseTask<Pair<ConnectMessage.Request, C>, ConnectMessage.Response> implements FutureCallback<ConnectMessage.Request>, Connection.Listener<Operation.Response>, Runnable { public static <C extends Connection<? super ConnectMessage.Request, ? extends Operation.Response,?>> ConnectTask<C> connect( ConnectMessage.Request message, C connection) { ConnectTask<C> task = create(message, connection, SettableFuturePromise.<ConnectMessage.Response>create()); task.run(); return task; } public static <C extends Connection<? super ConnectMessage.Request, ? extends Operation.Response,?>> ConnectTask<C> create( ConnectMessage.Request message, C connection, Promise<ConnectMessage.Response> promise) { return new ConnectTask<C>(Pair.create(message, connection), promise); } protected Optional<ListenableFuture<ConnectMessage.Request>> write; protected ConnectTask( Pair<ConnectMessage.Request, C> task, Promise<ConnectMessage.Response> promise) { super(task, promise); this.write = Optional.absent(); addListener(this, MoreExecutors.directExecutor()); } @Override public void handleConnectionState(Automaton.Transition<Connection.State> event) { if (Connection.State.CONNECTION_CLOSED == event.to()) { onFailure(new KeeperException.ConnectionLossException()); } } @Override public void handleConnectionRead(Operation.Response message) { if (message instanceof ConnectMessage.Response) { set((ConnectMessage.Response) message); } else { setException(new IllegalStateException(String.valueOf(message))); } } @Override public void onSuccess(ConnectMessage.Request result) { } @Override public void onFailure(Throwable t) { setException(t); } @Override public synchronized void run() { if (! isDone()) { if (! write.isPresent()) { task.second().subscribe(this); try { write = Optional.of(task.second().write(task().first())); } catch (Throwable e) { setException(e); return; } Futures.addCallback(write.get(), this); } } else { task().second().unsubscribe(this); if (write.isPresent()) { write.get().cancel(true); } } } }