All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bidib.jbidibc.netbidib.server.NetBidibServer Maven / Gradle / Ivy

The newest version!
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(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy