package edu.uw.zookeeper.server; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Iterator; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.locks.ReentrantReadWriteLock; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Supplier; import com.google.common.collect.MapMaker; import com.google.common.hash.Hashing; import edu.uw.zookeeper.ServerInetAddressView; import edu.uw.zookeeper.ZooKeeperApplication; import edu.uw.zookeeper.common.ParameterizedFactory; import edu.uw.zookeeper.common.RuntimeModule; import edu.uw.zookeeper.common.TaskExecutor; import edu.uw.zookeeper.data.NameTrie; import edu.uw.zookeeper.data.ZNodeNode; import edu.uw.zookeeper.protocol.ConnectMessage; import edu.uw.zookeeper.protocol.FourLetterRequest; import edu.uw.zookeeper.protocol.FourLetterResponse; import edu.uw.zookeeper.protocol.NotificationListener; import edu.uw.zookeeper.protocol.Operation; import edu.uw.zookeeper.protocol.Session; import edu.uw.zookeeper.protocol.proto.IWatcherEvent; import edu.uw.zookeeper.protocol.server.ServerConnectionFactoryBuilder; import edu.uw.zookeeper.protocol.server.ServerExecutor; import edu.uw.zookeeper.protocol.server.SessionExecutor; import edu.uw.zookeeper.protocol.server.ZxidGenerator; public class SimpleServerExecutor<T extends SessionExecutor> implements ServerExecutor<T> { public static Builder builder(ServerConnectionFactoryBuilder connections) { return Builder.defaults(connections); } public static class Builder implements ZooKeeperApplication.RuntimeBuilder<SimpleServerExecutor<?>, Builder> { public static Builder defaults(ServerConnectionFactoryBuilder connections) { return new Builder(ServerBuilder.defaults(connections)); } protected final ServerBuilder server; protected Builder(ServerBuilder server) { this.server = checkNotNull(server); } public ServerBuilder getServer() { return server; } public Builder setServer(ServerBuilder server) { return newInstance(server); } @Override public RuntimeModule getRuntimeModule() { return server.getRuntimeModule(); } @Override public Builder setRuntimeModule(RuntimeModule runtime) { return newInstance(server.setRuntimeModule(runtime)); } @Override public Builder setDefaults() { ServerBuilder server = this.server.setDefaults(); if (server != this.server) { return setServer(server).setDefaults(); } return this; } @Override public SimpleServerExecutor<?> build() { return setDefaults().doBuild(); } protected Builder newInstance(ServerBuilder server) { return new Builder(server); } protected SimpleServerExecutor<?> doBuild() { getServer().build(); @SuppressWarnings("unchecked") SimpleSessionManager<SimpleSessionExecutor> sessions = (SimpleSessionManager<SimpleSessionExecutor>) getServer().getSessions(); SimpleConnectExecutor<SimpleSessionExecutor> connect = SimpleConnectExecutor.defaults(sessions.executors(), sessions, getServer().getZxids()); return new SimpleServerExecutor<SimpleSessionExecutor>( getServer().getSessionExecutors(), connect, getDefaultAnonymousExecutor()); } protected TaskExecutor<? super FourLetterRequest, ? extends FourLetterResponse> getDefaultAnonymousExecutor() { return ProcessorTaskExecutor.of(FourLetterRequestProcessor.create(getServer())); } } public static class ServerBuilder extends SimpleServer.Builder<ServerBuilder> { public static ServerBuilder defaults(ServerConnectionFactoryBuilder connections) { return new ServerBuilder(connections, new SimpleServerSupplier(null), null, null, null, null, null, null, null, null, null); } protected static class SimpleServerSupplier implements Supplier<SimpleServer> { private volatile SimpleServer instance; public SimpleServerSupplier(SimpleServer instance) { this.instance = instance; } public SimpleServerSupplier set(SimpleServer instance) { this.instance = instance; return this; } @Override public SimpleServer get() { return instance; } } protected final ServerConnectionFactoryBuilder connections; protected final ConcurrentMap<Long, SimpleSessionExecutor> sessionExecutors; protected final SimpleServerSupplier server; protected ServerBuilder( ServerConnectionFactoryBuilder connections, SimpleServerSupplier server, ConcurrentMap<Long, SimpleSessionExecutor> sessionExecutors, ZxidGenerator zxids, NameTrie<ZNodeNode> data, SessionManager sessions, ReentrantReadWriteLock lock, Watches dataWatches, Watches childWatches, Function<Long, ? extends NotificationListener<Operation.ProtocolResponse<IWatcherEvent>>> listeners, RuntimeModule runtime) { super(zxids, data, sessions, lock, dataWatches, childWatches, listeners, runtime); this.connections = checkNotNull(connections); this.server = checkNotNull(server); this.sessionExecutors = sessionExecutors; } public ConcurrentMap<Long, SimpleSessionExecutor> getSessionExecutors() { return sessionExecutors; } public ServerBuilder setSessionExecutors(ConcurrentMap<Long, SimpleSessionExecutor> sessionExecutors) { return newInstance(connections, server, sessionExecutors, zxids, data, sessions, lock, dataWatches, childWatches, listeners, runtime); } @Override public ServerBuilder setDefaults() { if (getSessionExecutors() == null) { return setSessionExecutors(getDefaultSessionExecutors()).setDefaults(); } return super.setDefaults(); } @Override protected ServerBuilder newInstance( ZxidGenerator zxids, NameTrie<ZNodeNode> data, SessionManager sessions, ReentrantReadWriteLock lock, Watches dataWatches, Watches childWatches, Function<Long, ? extends NotificationListener<Operation.ProtocolResponse<IWatcherEvent>>> listeners, RuntimeModule runtime) { return newInstance(connections, server, sessionExecutors, zxids, data, sessions, lock, dataWatches, childWatches, listeners, runtime); } protected ServerBuilder newInstance( ServerConnectionFactoryBuilder connections, SimpleServerSupplier server, ConcurrentMap<Long, SimpleSessionExecutor> sessionExecutors, ZxidGenerator zxids, NameTrie<ZNodeNode> data, SessionManager sessions, ReentrantReadWriteLock lock, Watches dataWatches, Watches childWatches, Function<Long, ? extends NotificationListener<Operation.ProtocolResponse<IWatcherEvent>>> listeners, RuntimeModule runtime) { return new ServerBuilder(connections, server, sessionExecutors, zxids, data, sessions, lock, dataWatches, childWatches, listeners, runtime); } @Override protected SimpleServer doBuild() { synchronized (server) { if (server.get() == null) { server.set(super.doBuild()); } } return server.get(); } @Override protected Function<Long, ? extends NotificationListener<Operation.ProtocolResponse<IWatcherEvent>>> getDefaultListeners() { return Functions.forMap(getSessionExecutors()); } @Override protected SimpleSessionManager<SimpleSessionExecutor> getDefaultSessions() { return SimpleSessionManager.fromConfiguration( getDefaultSessionId(), getSessionExecutors(), getDefaultSessionFactory(), getRuntimeModule().getConfiguration()); } protected ConcurrentMap<Long, SimpleSessionExecutor> getDefaultSessionExecutors() { return new MapMaker().makeMap(); } protected ParameterizedFactory<Session, SimpleSessionExecutor> getDefaultSessionFactory() { return SimpleSessionExecutor.factory( getRuntimeModule().getExecutors().get(ScheduledExecutorService.class), server); } protected short getDefaultSessionId() { ServerInetAddressView address = connections.setRuntimeModule(getRuntimeModule()).setDefaults().getAddress(); return (short) Hashing.murmur3_32().hashInt(address.get().hashCode()).asInt(); } } protected final TaskExecutor<? super FourLetterRequest, ? extends FourLetterResponse> anonymousExecutor; protected final TaskExecutor<ConnectMessage.Request, ? extends ConnectMessage.Response> connectExecutor; protected final ConcurrentMap<Long, T> sessionExecutors; public SimpleServerExecutor( ConcurrentMap<Long, T> sessionExecutors, TaskExecutor<ConnectMessage.Request, ? extends ConnectMessage.Response> connectExecutor, TaskExecutor<? super FourLetterRequest, ? extends FourLetterResponse> anonymousExecutor) { this.anonymousExecutor = anonymousExecutor; this.connectExecutor = connectExecutor; this.sessionExecutors = sessionExecutors; } @Override public TaskExecutor<? super FourLetterRequest, ? extends FourLetterResponse> anonymousExecutor() { return anonymousExecutor; } @Override public TaskExecutor<ConnectMessage.Request, ? extends ConnectMessage.Response> connectExecutor() { return connectExecutor; } @Override public T sessionExecutor(long sessionId) { return sessionExecutors.get(sessionId); } @Override public Iterator<T> iterator() { return sessionExecutors.values().iterator(); } }