package org.handwerkszeug.riak.transport.internal; import static org.handwerkszeug.riak.util.Validation.notNull; import java.util.concurrent.Executor; import org.handwerkszeug.riak.RiakAction; import org.handwerkszeug.riak.RiakClient; import org.handwerkszeug.riak.config.RiakConfig; import org.handwerkszeug.riak.op.BucketOperations; import org.handwerkszeug.riak.op.ObjectKeyOperations; import org.handwerkszeug.riak.op.Querying; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.util.internal.ExecutorUtil; /** * @author taichi */ public abstract class AbstractRiakClient<CONF extends RiakConfig, OP extends BucketOperations & ObjectKeyOperations & Querying & Completion> implements RiakClient<OP> { protected final CONF config; protected final ChannelPipelineFactory pipelineFactory; protected final ClientSocketChannelFactory channelFactory; protected final Executor actionExecutor; protected final Executor[] externalResources = new Executor[3]; public AbstractRiakClient(CONF config, ChannelPipelineFactory pipelineFactory) { this.externalResources[0] = config.getActionExecutor(); this.externalResources[1] = config.getBossExecutor(); this.externalResources[2] = config.getWorkerExecutor(); this.actionExecutor = this.externalResources[0]; this.channelFactory = new NioClientSocketChannelFactory( this.externalResources[1], this.externalResources[2]); this.pipelineFactory = pipelineFactory; this.config = config; } @Override public void execute(final RiakAction<OP> action) { notNull(action, "action"); // TODO stress test and implement connection pooling. ClientBootstrap bootstrap = new ClientBootstrap(this.channelFactory); Integer i = this.config.getTimeout(); if (i != null) { bootstrap.setOption("connectTimeoutMillis", i); } bootstrap.setPipelineFactory(this.pipelineFactory); ChannelFuture future = bootstrap.connect(this.config.getRiakAddress()); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { final Channel channel = future.getChannel(); AbstractRiakClient.this.actionExecutor .execute(new Runnable() { @Override public void run() { OP op = newOperations(channel); try { action.execute(op); } finally { op.complete(); } } }); } } }); } protected abstract OP newOperations(Channel channel); @Override public void dispose() { ExecutorUtil.terminate(this.externalResources); } }