package edu.uw.zookeeper.client;
import java.util.concurrent.ScheduledExecutorService;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import edu.uw.zookeeper.ServerInetAddressView;
import edu.uw.zookeeper.common.DefaultsFactory;
import edu.uw.zookeeper.common.Factory;
import edu.uw.zookeeper.common.Pair;
import edu.uw.zookeeper.common.TimeValue;
import edu.uw.zookeeper.net.ClientConnectionFactory;
import edu.uw.zookeeper.protocol.ConnectMessage;
import edu.uw.zookeeper.protocol.Message;
import edu.uw.zookeeper.protocol.Operation;
import edu.uw.zookeeper.protocol.ProtocolConnection;
import edu.uw.zookeeper.protocol.Session;
import edu.uw.zookeeper.protocol.client.ConnectionClientExecutor;
import edu.uw.zookeeper.protocol.client.OperationClientExecutor;
import edu.uw.zookeeper.protocol.client.ZxidTracker;
public class ServerViewFactory<V, C extends ConnectionClientExecutor<?,?,?,?>> extends Pair<ServerInetAddressView, ZxidTracker> implements DefaultsFactory<V, ListenableFuture<C>>, Function<C, C> {
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> ServerViewFactory<Session, OperationClientExecutor<C>> defaults(
ClientConnectionFactory<C> connections,
ServerInetAddressView view,
TimeValue timeOut,
ScheduledExecutorService executor) {
ZxidTracker zxids = ZxidTracker.zero();
final DefaultsFactory<Session, ConnectMessage.Request> requestFactory = ConnectMessage.Request.factory(timeOut, zxids);
final FromRequestFactory<C> delegate =
FromRequestFactory.create(
FixedClientConnectionFactory.create(view.get(), connections),
executor);
return new ServerViewFactory<Session, OperationClientExecutor<C>>(
view,
new DefaultsFactory<Session, ListenableFuture<? extends OperationClientExecutor<C>>>() {
@Override
public ListenableFuture<OperationClientExecutor<C>> get() {
return delegate.get(requestFactory.get());
}
@Override
public ListenableFuture<OperationClientExecutor<C>> get(Session value) {
return delegate.get(requestFactory.get(value));
}
},
zxids);
}
public static <V, C extends ConnectionClientExecutor<?,?,?,?>> ServerViewFactory<V,C> create(
ServerInetAddressView view,
DefaultsFactory<V, ? extends ListenableFuture<? extends C>> delegate,
ZxidTracker zxids) {
return new ServerViewFactory<V,C>(view, delegate, zxids);
}
public static class FromRequestFactory<C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> implements DefaultsFactory<ConnectMessage.Request, ListenableFuture<OperationClientExecutor<C>>> {
public static <C extends ProtocolConnection<? super Message.ClientSession, ? extends Operation.Response,?,?,?>> FromRequestFactory<C> create(
Factory<ListenableFuture<? extends C>> connections,
ScheduledExecutorService executor) {
return new FromRequestFactory<C>(connections, executor);
}
protected final Factory<ListenableFuture<? extends C>> connections;
protected final ScheduledExecutorService executor;
public FromRequestFactory(
Factory<ListenableFuture<? extends C>> connections,
ScheduledExecutorService executor) {
this.connections = connections;
this.executor = executor;
}
@Override
public ListenableFuture<OperationClientExecutor<C>> get() {
return get(ConnectMessage.Request.NewRequest.newInstance());
}
@Override
public ListenableFuture<OperationClientExecutor<C>> get(ConnectMessage.Request request) {
return Futures.transform(connections.get(), new Constructor(request));
}
protected class Constructor implements Function<C, OperationClientExecutor<C>> {
protected final ConnectMessage.Request task;
public Constructor(ConnectMessage.Request task) {
this.task = task;
}
@Override
public OperationClientExecutor<C> apply(C input) {
return OperationClientExecutor.newInstance(
task, input, executor);
}
}
}
protected final DefaultsFactory<V, ? extends ListenableFuture<? extends C>> delegate;
protected ServerViewFactory(
ServerInetAddressView view,
DefaultsFactory<V, ? extends ListenableFuture<? extends C>> delegate,
ZxidTracker zxids) {
super(view, zxids);
this.delegate = delegate;
}
@Override
public ListenableFuture<C> get() {
return Futures.transform(delegate.get(), this);
}
@Override
public ListenableFuture<C> get(V value) {
return Futures.transform(delegate.get(value), this);
}
@Override
public C apply(C input) {
ZxidTracker.listener(second(), input.connection());
return input;
}
}