Package me.jtalk.networking

Source Code of me.jtalk.networking.NettyController

/*
* Copyright (C) 2014 Roman Nazarenko <me@jtalk.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package me.jtalk.networking;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.ejb.Startup;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import javax.ejb.EJB;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Singleton
@Startup
@LocalBean
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class NettyController {
  private static final Logger log = LogManager.getLogger(NettyController.class);

  private static final String LISTENER_THREADS_PROPERTY = "me.jtalk.networking.ListenerThreadCount";
  private static final String WORKER_THREADS_PROPERTY = "me.jtalk.networking.WorkerThreadCount";
  private static final String BACKLOG_SIZE_PROPERTY = "me.jtalk.networking.BacklogSize";
  private static final String IP_PORT_PROPERTY = "me.jtalk.networking.IpsPorts";

  public static final String CHILD_HANDLER_NAME = "NettyChildHandler";

  @EJB(name = CHILD_HANDLER_NAME)
  NettyChannelInitializerFabric childHandler;

  private ServerBootstrap server;

  private NioEventLoopGroup listeners;
  private NioEventLoopGroup workers;

  private void setupServer() throws Exception {
    log.info("Starting Netty Server Controller");

    int listenerThreads = Integer.valueOf(System.getProperty(LISTENER_THREADS_PROPERTY));
    int workerThreads = Integer.valueOf(System.getProperty(WORKER_THREADS_PROPERTY));
    int backlog = Integer.valueOf(System.getProperty(BACKLOG_SIZE_PROPERTY));

    this.listeners = new NioEventLoopGroup(listenerThreads);
    this.workers = new NioEventLoopGroup(workerThreads);

    this.server = new ServerBootstrap();
    this.server.group(this.listeners, this.workers);
    this.server.channel(NioServerSocketChannel.class);

    this.server.childHandler(this.childHandler.get());
    this.server.option(ChannelOption.SO_BACKLOG, backlog);
    this.server.childOption(ChannelOption.SO_KEEPALIVE, true);
  }

  private void bind() {
    log.info("Binding Netty Server Controller");

    Iterable<InetSocketAddress> toBind = this.parseAddressPort();

    GenericFutureListener<ChannelFuture> listener = new GenericFutureListener<ChannelFuture>() {

      @Override
      public void operationComplete(ChannelFuture future) throws Exception {
        Throwable cause = future.cause();
        InetSocketAddress addr = (InetSocketAddress)future.channel().localAddress();
        if (cause == null) {
          log.info("Listening socket is bound to address {} successfully", addr.toString());
        } else {
          log.error("Listening socket for address {} not bound: {}", addr.toString(), cause.getMessage());
        }
      }
    };

    for (InetSocketAddress addr : toBind) {
      ChannelFuture future = this.server.bind(addr);
      future.addListener(listener);
    }
  }

  @PostConstruct
  void start() {
    try {
      this.setupServer();
      this.bind();

      log.info("Netty Controller is successfully initialized");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("unchecked")
  @PreDestroy
  void stop() {
    Future<?> listenersFuture = this.listeners.shutdownGracefully();
    Future<?> workersFuture = this.workers.shutdownGracefully();

    listenersFuture.addListener(new FutureListener() {
      @Override
      public void operationComplete(Future future) throws Exception {
        if (future.isSuccess()) {
          log.info("Listeners are shut down");
        } else {
          log.catching(future.cause());
        }
      }
    });

    workersFuture.addListener(new FutureListener() {
      @Override
      public void operationComplete(Future future) throws Exception {
        if (future.isSuccess()) {
          log.info("Workers are shut down");
        } else {
          log.catching(future.cause());
        }
      }
    });
  }

  private LinkedList<InetSocketAddress> parseAddressPort() {
    String params = System.getProperty(IP_PORT_PROPERTY);
    if (params == null || params.isEmpty())
      throw new RuntimeException("No IPs and ports provided for Netty Controller");

    String[] pairs = params.split(";");
    if (pairs.length <= 0)
      throw new RuntimeException("No data provided for Netty Controller in IP-Port property");

    LinkedList<InetSocketAddress> result = new LinkedList<>();
    for (String s : pairs) {
      if (s.isEmpty()) {
        continue;
      }
      String[] data = s.split(":");
      if (data.length != 2) {
        throw new RuntimeException("Error in IP-Port pairs parsing in Netty Controller: value given is not in format IP:Port");
      }
      try {
        InetAddress addr = Inet4Address.getByName(data[0]);
        int port = Integer.valueOf(data[1]);

        result.add(new InetSocketAddress(addr, port));

      } catch (UnknownHostException | NumberFormatException e) {
        log.catching(e);
        throw new RuntimeException(e);
      }
    }
    if (result.isEmpty()) {
      throw new RuntimeException("IP-Port list provided to Netty Controller consists of empty entries");
    }
    return result;
  }
}
TOP

Related Classes of me.jtalk.networking.NettyController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.