Package org.menacheri.jetclient

Source Code of org.menacheri.jetclient.NettyTCPClient

package org.menacheri.jetclient;

import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.ChannelGroupFuture;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.menacheri.jetclient.event.Event;

/**
* Java client class that provides a TCP transport network connection to remote
* jetserver. Using one instance of this class, multiple tcp connections can be
* made to a remote jetserver. For connection to multiple jetserver's use
* multiple instances of this class.
*
* @author Abraham Menacherry.
*
*/
public class NettyTCPClient
{
  /**
   * The remote server address to which this client should connect.
   */
  private final InetSocketAddress serverAddress;
  /**
   * The instance of {@link NioClientSocketChannelFactory} created by
   * constructor, or the one passed in to constructor.
   */
  private final ChannelFactory channelFactory;
  /**
   * The boss executor which will provide threads to Netty
   * {@link ChannelFactory} for reading from the NIO selectors.
   */
  private final ExecutorService boss;
  /**
   * The worker executor which will provide threads to Netty
   * {@link ChannelFactory} for decoding encoding done on the
   * {@link ChannelPipeline}.
   */
  private final ExecutorService worker;
  private final ClientBootstrap bootstrap;
  /**
   * The amount of time in seconds to wait for this client to close all
   * {@link Channel}s and shutdown gracefully.
   */
  private final int maxShutdownWaitTime;
  /**
   * Any successful TCP connection opened by the client to server is also
   * added to this {@link ChannelGroup}. This will be used for shutting down
   * the client gracefully.
   */
  public static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup(
      "JET-CLIENT-CONNECTIONS");

  /**
   * Creates an instance of a Netty TCP client which can then be used to
   * connect to a remote jet-server. This constructor delegates to
   * {@link #NettyTCPClient(InetSocketAddress)} constructor after creating a
   * {@link InetSocketAddress} instance based on the host and port number
   * passed in.
   *
   * @param jetserverHost
   *            The host name of the remote server on which jetserver is
   *            running.
   * @param port
   *            The port to connect to, on the remote server.
   */
  public NettyTCPClient(String jetserverHost, int port)
  {
    this(new InetSocketAddress(jetserverHost, port));
  }

  public NettyTCPClient(final InetSocketAddress serverAddress)
  {
    this(serverAddress, Executors.newCachedThreadPool(), Executors
        .newCachedThreadPool(), null, 5000);
  }

  /**
   * Creates a new instance of the {@link NettyTCPClient}. This constructor
   * also registers a shutdown hook which will call close on
   * {@link #ALL_CHANNELS} and call bootstrap.releaseExternalResources() to
   * enable a graceful shutdown.
   *
   * @param serverAddress
   *            The remote servers address. This address will be used when any
   *            of the default write/connect methods are used.
   * @param boss
   *            {@link Executor} used for creating the {@link #channelFactory}
   *            instance. Can be <b>null</b> if {@link #channelFactory} is not
   *            null.
   * @param worker
   *            {@link Executor} used for creating the {@link #channelFactory}
   *            instance. Can be <b>null</b> if {@link #channelFactory} is not
   *            null.
   * @param channelFactory
   *            <b>Can be provided as null</b>. If so, it will by default use
   *            {@link NioClientSocketChannelFactory}. If not null, then the
   *            provided factory is set.
   * @param maxShutdownWaitTime
   *            The amount of time in seconds to wait for this client to close
   *            all {@link Channel}s and shutdown gracefully.
   */
  public NettyTCPClient(final InetSocketAddress serverAddress,
      final ExecutorService boss, final ExecutorService worker,
      final ChannelFactory channelFactory, final int maxShutdownWaitTime)
  {
    this.serverAddress = serverAddress;
    this.boss = boss;
    this.worker = worker;
    if (null != channelFactory)
    {
      this.channelFactory = channelFactory;
    }
    else
    {
      this.channelFactory = new NioClientSocketChannelFactory(boss,
          worker);
    }
    this.bootstrap = new ClientBootstrap(this.channelFactory);
    // At client side option is tcpNoDelay and at server child.tcpNoDelay
    this.bootstrap.setOption("tcpNoDelay", true);
    this.bootstrap.setOption("keepAlive", true);
    this.maxShutdownWaitTime = maxShutdownWaitTime;
    Runtime.getRuntime().addShutdownHook(new Thread()
    {
      public void run()
      {
        ChannelGroupFuture future = ALL_CHANNELS.close();
        try
        {
          future.await(NettyTCPClient.this.maxShutdownWaitTime);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
        bootstrap.releaseExternalResources();
      }
    });
  }

  /**
   * This method delegates to the
   * {@link #connect(ChannelPipelineFactory, Event, int, TimeUnit)}
   * method internally. It will pass in a default of 5 seconds wait time to
   * the delegated method.
   *
   * @param pipelineFactory
   *            The factory used to create a pipeline of decoders and encoders
   *            for each {@link Channel} that it creates on connection.
   * @param loginEvent
   *            The event contains the {@link ChannelBuffer} to be transmitted
   *            to jetserver for logging in. Values inside this buffer include
   *            username, password, connection key, <b>optional</b> local
   *            address of the UDP channel used by this session.
   * @return Returns the Netty {@link Channel} which is the connection to the
   *         remote jetserver.
   * @throws InterruptedException
   */
  public Channel connect(final ChannelPipelineFactory pipelineFactory,
      final Event loginEvent)
      throws InterruptedException
  {
    return connect(pipelineFactory, loginEvent, 5, TimeUnit.SECONDS);
  }

  /**
   * Method that is used to create the connection or {@link Channel} to
   * communicated with the remote jetserver.
   *
   * @param pipelineFactory
   *            The factory used to create a pipeline of decoders and encoders
   *            for each {@link Channel} that it creates on connection.
   * @param loginEvent
   *            The event contains the {@link ChannelBuffer} to be transmitted
   *            to jetserver for logging in. Values inside this buffer include
   *            username, password, connection key, <b>optional</b> local
   *            address of the UDP channel used by this session.
   * @param timeout
   *            The amount of time to wait for this connection be created
   *            successfully.
   * @param unit
   *            The unit of timeout SECONDS, MILLISECONDS etc. Default is 5
   *            seconds.
   * @return Returns the Netty {@link Channel} which is the connection to the
   *         remote jetserver.
   * @throws InterruptedException
   */
  public Channel connect(final ChannelPipelineFactory pipelineFactory,
      final Event loginEvent, int timeout, TimeUnit unit)
      throws InterruptedException
  {
    ChannelFuture future;
    synchronized (bootstrap)
    {
      bootstrap.setPipelineFactory(pipelineFactory);
      future = bootstrap.connect(serverAddress);
      future.addListener(new ChannelFutureListener()
      {
        @Override
        public void operationComplete(ChannelFuture future)
            throws Exception
        {
          if (future.isSuccess())
          {
            future.getChannel().write(loginEvent);
          }
          else
          {
            throw new RuntimeException(future.getCause()
                .getMessage());
          }
        }
      });
    }
    return future.getChannel();
  }

  public InetSocketAddress getServerAddress()
  {
    return serverAddress;
  }

  public ChannelFactory getChannelFactory()
  {
    return channelFactory;
  }

  public ExecutorService getBoss()
  {
    return boss;
  }

  public ExecutorService getWorker()
  {
    return worker;
  }

  public ClientBootstrap getBootstrap()
  {
    return bootstrap;
  }

  public int getMaxShutdownWaitTime()
  {
    return maxShutdownWaitTime;
  }

}
TOP

Related Classes of org.menacheri.jetclient.NettyTCPClient

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.