org.bidib.jbidibc.netbidib.server.NetBidibServer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jbidibc-netbidib-server Show documentation
Show all versions of jbidibc-netbidib-server Show documentation
jBiDiB jbidibc NetBiDiB Server POM
package org.bidib.jbidibc.netbidib.server;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.apache.commons.lang3.time.StopWatch;
import org.bidib.jbidibc.core.schema.BidibFactory;
import org.bidib.jbidibc.messages.HostAdapter;
import org.bidib.jbidibc.messages.message.netbidib.NetBidibLinkData;
import org.bidib.jbidibc.messages.utils.ThreadFactoryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.Future;
public abstract class NetBidibServer {
private static final Logger LOGGER = LoggerFactory.getLogger(NetBidibServer.class);
public static final int DEFAULT_PORTNUM = 62875;
public static final String DEFAULT_HOSTNAME = "localhost";
private int portNumber = DEFAULT_PORTNUM;
private String hostName;
private String connectionName;
private EventLoopGroup group;
private EventLoopGroup parentGroup;
private ChannelGroup channelGroup;
private ChannelFuture channelFuture;
private final HostAdapter hostAdapter;
private final Object shutdownLock = new Object();
private Thread shutdownHook;
private NetBidibLinkData serverLinkData;
private final ScheduledExecutorService serverWorkers;
private final RoleTypeEnum roleType;
private final NetBidibLinkData pairedPartner;
public NetBidibServer(final HostAdapter hostAdapter, final String connectionName,
final NetBidibLinkData serverLinkData, RoleTypeEnum roleType, final NetBidibLinkData pairedPartner) {
this(DEFAULT_HOSTNAME, DEFAULT_PORTNUM, hostAdapter, connectionName, serverLinkData, roleType, pairedPartner);
}
/**
* Create a {@code NetBidibServer} instance with the provided hostname and portNumber.
*
* @param hostName
* the hostname
* @param portNumber
* the port number
*/
public NetBidibServer(String hostName, int portNumber, final HostAdapter hostAdapter,
final String connectionName, final NetBidibLinkData serverLinkData, final RoleTypeEnum roleType,
final NetBidibLinkData pairedPartner) {
this.hostName = hostName;
this.portNumber = portNumber;
this.hostAdapter = hostAdapter;
this.connectionName = connectionName;
this.serverLinkData = serverLinkData;
this.roleType = roleType;
this.pairedPartner = pairedPartner;
final ThreadFactory namedThreadFactory =
new ThreadFactoryBuilder().setNameFormat("netBidibServerWorkers-thread-%d").build();
this.serverWorkers = Executors.newScheduledThreadPool(1, namedThreadFactory);
}
/**
* @return the shutdownHook
*/
public Thread getShutdownHook() {
return shutdownHook;
}
/**
* @param shutdownHook
* the shutdownHook to set
*/
public void setShutdownHook(Thread shutdownHook) {
this.shutdownHook = shutdownHook;
}
public Object getShutdownLock() {
return shutdownLock;
}
/**
* Create the {@code NetBidibServerHandler} instance.
*
* Note: Override this method to do more initialization of the {@code NetBidibServerHandler}.
*
*
* @param channelGroup
* the netty channel group
* @return the serverHandler instance
*/
protected abstract NetBidibServerHandler createNetBidibServerHandler(
final ChannelGroup channelGroup, final NetBidibLinkData serverLinkData, final HostAdapter hostAdapter,
final String connectionName, final Consumer> lazyInitializationCallback,
final RoleTypeEnum roleType, final NetBidibLinkData pairedPartner);
/**
* Start the server.
*/
public void startServer() {
final Runnable serverThread = () -> {
try {
this.group = new NioEventLoopGroup();
this.parentGroup = new NioEventLoopGroup();
channelGroup =
new io.netty.channel.group.DefaultChannelGroup(
io.netty.util.concurrent.ImmediateEventExecutor.INSTANCE);
LOGGER.info("Create ServerBootstrap with hostname: {}, portNumber: {}", hostName, portNumber);
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(this.parentGroup, this.group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress(hostName, portNumber));
serverBootstrap.option(ChannelOption.SO_BACKLOG, 100);
// serverBootstrap.option(ChannelOption.SO_REUSEADDR, true);
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(final SocketChannel socketChannel) throws Exception {
LOGGER.info("Init the socketChannel: {}", socketChannel);
final NetBidibServerHandler serverHandler =
createNetBidibServerHandler(channelGroup, serverLinkData, hostAdapter, connectionName,
toHostPublisher -> hostAdapter.setToGuestPublisher(toHostPublisher), roleType,
pairedPartner);
socketChannel.pipeline().addLast(serverHandler);
}
});
LOGGER.info("Start pre-loading the messageTypes.");
StopWatch sw = StopWatch.createStarted();
BidibFactory.getMessageTypes();
sw.stop();
LOGGER.info("Finished pre-loading the messageTypes, duration: {}ms", sw.getTime());
LOGGER.info("Start the TCP server.");
ChannelFuture channelFuture = serverBootstrap.bind().sync();
this.channelFuture = channelFuture;
final Channel channel = channelFuture.channel();
channel.closeFuture().sync();
LOGGER.info("The TCP server channel was closed.");
}
catch (Exception ex) {
LOGGER.warn("Process socket with netty failed.", ex);
}
finally {
group.shutdownGracefully().sync();
}
LOGGER.info("The TCP server has finished.");
}
catch (Exception ex) {
LOGGER.warn("Start the server failed.", ex);
}
};
serverWorkers.submit(serverThread);
}
/**
* Stop the server.
*/
public void stop() {
LOGGER.info("Stop the NetBidibServer instance.");
if (this.channelFuture != null) {
LOGGER.info("Close the channel of the server.");
try {
this.channelFuture.channel().disconnect();
}
catch (Exception ex) {
LOGGER.warn("Disconnect the channel failed.", ex);
}
this.channelFuture = null;
}
else {
LOGGER.info("No channelFuture available.");
}
if (group != null) {
Future> terminate = group.shutdownGracefully(2, 5, TimeUnit.SECONDS);
LOGGER.info("Wait for termination of server.");
try {
terminate.await(10000);
}
catch (InterruptedException ex) {
LOGGER.warn("Wait for termination of server failed.", ex);
}
group = null;
}
LOGGER.info("Shutdown the serverWorker.");
serverWorkers.shutdown();
try {
serverWorkers.awaitTermination(2000, TimeUnit.MILLISECONDS);
}
catch (InterruptedException ex) {
LOGGER.warn("Wait for termination of serverWorker failed.", ex);
}
synchronized (shutdownLock) {
LOGGER.info("Notify the shutdownLock.");
shutdownLock.notifyAll();
}
}
}