package org.sdnplatform.sync.internal.config.bootstrap;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.sdnplatform.sync.error.SyncException;
import org.sdnplatform.sync.internal.SyncManager;
import org.sdnplatform.sync.internal.config.AuthScheme;
import org.sdnplatform.sync.internal.config.Node;
import org.sdnplatform.sync.internal.rpc.RPCService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.net.HostAndPort;
/**
* Makes an attempt to bootstrap the cluster based on seeds stored in the
* local system store
* @author readams
*/
public class Bootstrap {
protected static final Logger logger =
LoggerFactory.getLogger(Bootstrap.class);
/**
* Channel group that will hold all our channels
*/
protected ChannelGroup cg;
/**
* Transaction ID used in message headers in the RPC protocol
*/
protected AtomicInteger transactionId = new AtomicInteger();
/**
* The {@link SyncManager} that we'll be bootstrapping
*/
protected SyncManager syncManager;
protected final AuthScheme authScheme;
protected final String keyStorePath;
protected final String keyStorePassword;
ExecutorService bossExecutor = null;
ExecutorService workerExecutor = null;
ClientBootstrap bootstrap = null;
BootstrapPipelineFactory pipelineFactory;
protected Node localNode;
protected volatile boolean succeeded = false;
public Bootstrap(SyncManager syncManager, AuthScheme authScheme,
String keyStorePath, String keyStorePassword) {
super();
this.syncManager = syncManager;
this.authScheme = authScheme;
this.keyStorePath = keyStorePath;
this.keyStorePassword = keyStorePassword;
}
public void init() throws SyncException {
cg = new DefaultChannelGroup("Cluster Bootstrap");
bossExecutor = Executors.newCachedThreadPool();
workerExecutor = Executors.newCachedThreadPool();
bootstrap =
new ClientBootstrap(new NioClientSocketChannelFactory(bossExecutor,
workerExecutor));
bootstrap.setOption("child.reuseAddr", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.sendBufferSize",
RPCService.SEND_BUFFER_SIZE);
bootstrap.setOption("child.receiveBufferSize",
RPCService.SEND_BUFFER_SIZE);
bootstrap.setOption("child.connectTimeoutMillis",
RPCService.CONNECT_TIMEOUT);
pipelineFactory = new BootstrapPipelineFactory(this);
bootstrap.setPipelineFactory(pipelineFactory);
}
public void shutdown() {
if (cg != null) {
cg.close().awaitUninterruptibly();
cg = null;
}
if (bootstrap != null)
bootstrap.releaseExternalResources();
bootstrap = null;
if (pipelineFactory != null)
pipelineFactory.releaseExternalResources();
pipelineFactory = null;
if (workerExecutor != null)
workerExecutor.shutdown();
workerExecutor = null;
if (bossExecutor != null)
bossExecutor.shutdown();
bossExecutor = null;
}
public boolean bootstrap(HostAndPort seed,
Node localNode) throws SyncException {
this.localNode = localNode;
succeeded = false;
SocketAddress sa =
new InetSocketAddress(seed.getHostText(), seed.getPort());
ChannelFuture future = bootstrap.connect(sa);
future.awaitUninterruptibly();
if (!future.isSuccess()) {
logger.debug("Could not connect to " + seed, future.getCause());
return false;
}
Channel channel = future.getChannel();
logger.debug("[{}] Connected to {}",
localNode != null ? localNode.getNodeId() : null,
seed);
try {
channel.getCloseFuture().await();
} catch (InterruptedException e) {
logger.debug("Interrupted while waiting for bootstrap");
return succeeded;
}
return succeeded;
}
}