org.wenxueliu.netty.client.ClientTest.java Source code

Java tutorial

Introduction

Here is the source code for org.wenxueliu.netty.client.ClientTest.java

Source

/*
 * Copyright 2015 Open Networking Laboratory
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.wenxueliu.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ServerChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.TimeoutException;
import io.netty.util.CharsetUtil;
import io.netty.util.Timer;
import io.netty.util.HashedWheelTimer;

import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.net.InetSocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClientTest {

    protected static final Logger log = LoggerFactory.getLogger(ClientTest.class);

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    private ChannelGroup cg;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    private Timer timer;
    Bootstrap bootstrap = null;
    DefaultChannelInitializer pipelineFactory;

    private static final int MAX_RETRY = 5;
    private static final int IDLE_TIMEOUT_SEC = 10;

    /**
     * Buffer size for sockets
     */
    public static final int SEND_BUFFER_SIZE = 4 * 1024 * 1024;

    /**
     * Connect timeout for client connections
     */
    public static final int CONNECT_TIMEOUT = 500;

    protected volatile boolean succeeded = false;

    public ClientTest() {
        super();
    }

    /**
     * Initialization.
     */
    private void initEventLoopGroup() {
        cg = new DefaultChannelGroup("Cluster Bootstrap", GlobalEventExecutor.INSTANCE);

        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        timer = new HashedWheelTimer();
    }

    /**
     * Accepts incoming connections.
     */
    private void startAcceptingConnections() throws InterruptedException {
        ServerBootstrap b = new ServerBootstrap();

        b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                .childHandler(new CommunicationChannelInitializer());
        b.option(ChannelOption.SO_BACKLOG, 128);
        b.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
        b.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
        b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        b.childOption(ChannelOption.SO_KEEPALIVE, true);
        b.bind(80).sync();
    }

    /**
     * @throws InterruptedException if thread is interrupted
     */
    public void run() throws InterruptedException {
        initEventLoopGroup();
        startAcceptingConnections();
    }

    /**
     * Adds channel pipeline to handle a new connected node.
     */
    private class CommunicationChannelInitializer extends ChannelInitializer<SocketChannel> {
        protected void initChannel(SocketChannel channel) throws Exception {
            log.info("New channel created");
            channel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
            channel.pipeline().addLast(new MessageDecoder());
            handleNewNodeConnection(channel);
        }
    }

    /**
     * Handles the new connection of node.
     *
     * @param channel the channel to use.
     */
    private void handleNewNodeConnection(final Channel channel) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                log.info("Handle new node connection");

                String ipAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
                long port = ((InetSocketAddress) channel.remoteAddress()).getPort();

                log.info("Get connection from ip address {} : {}", ipAddress.toString(), port);

                //specific logic
                DefaultHandler defaultHandler = new DefaultHandler();
                channel.pipeline().addLast(defaultHandler);

                ChannelFuture closeFuture = channel.closeFuture();
                closeFuture.addListener(new ChannelConnectionListener());

                //try {
                //    closeFuture.await();
                //} catch (InterruptedException e) {
                //    log.debug("Interrupted while waiting for bootstrap");
                //}
            }
        });
    }

    /**
     * Starts controller.
     *
     * @param agent OvsdbAgent
     * @param monitorCallback Callback
     */
    public void start() {
        try {
            this.run();
        } catch (InterruptedException e) {
            log.warn("Interrupted while waiting to start");
            Thread.currentThread().interrupt();
        }
    }

    /**
     * Stops controller.
     *
     */
    public void stop() {
        if (cg != null) {
            cg.close().awaitUninterruptibly();
            cg = null;
        }

        bootstrap = null;
        pipelineFactory = null;
        if (workerGroup != null) {
            try {
                workerGroup.shutdownGracefully();
            } catch (TimeoutException e) {
                log.warn("Error waiting for gracefull shutdown of BootstrapClient {}", e);
            }
            workerGroup = null;
        }

        if (bossGroup != null) {
            try {
                bossGroup.shutdownGracefully();
            } catch (TimeoutException e) {
                log.warn("Error waiting for gracefull shutdown of BootstrapClient {}", e);
            }
            bossGroup = null;
        }

        if (timer != null) {
            timer.stop();
            timer = null;
        }
    }

    /**
     * Connect to the ovsdb server with given ip address and port number.
     *
     * @param ip ip address
     * @param port port number
     */
    public void connect(String ip, int port) {
        ChannelFutureListener clientConnectionListener = new ConnectionListener(this, ip, port);
        connectRetry(ip, port, clientConnectionListener);
    }

    private void connectRetry(String ip, int port, ChannelFutureListener clientConnectionListener) {
        try {
            bootstrap = new Bootstrap().group(workerGroup).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.SO_KEEPALIVE, true).option(ChannelOption.SO_SNDBUF, SEND_BUFFER_SIZE)
                    .option(ChannelOption.SO_RCVBUF, SEND_BUFFER_SIZE)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CONNECT_TIMEOUT);

            pipelineFactory = new DefaultChannelInitializer(timer, this);
            bootstrap.handler(pipelineFactory);
            //.handler(new ChannelInitializer<SocketChannel>() {

            //    @Override
            //    protected void initChannel(SocketChannel channel) throws Exception {
            //        ChannelPipeline p = channel.pipeline();
            //        p.addLast(new MessageDecoder(),
            //                  new StringEncoder(CharsetUtil.UTF_8),
            //                  new IdleStateHandler(IDLE_TIMEOUT_SEC, 0, 0),
            //                  new BootstrapTimeoutHandler(timer, 10),
            //                  new ConnectionHandler());
            //    }
            //});
            bootstrap.remoteAddress(ip, port);
            ChannelFuture future = bootstrap.connect();
            future.awaitUninterruptibly();
            future.addListener(clientConnectionListener);
        } catch (Exception e) {
            log.warn("Connection to the server {}:{} failed", ip, port);
        }
    }

    private class ConnectionListener implements ChannelFutureListener {
        private ClientTest controller;
        private String ip;
        private int port;
        private AtomicInteger count = new AtomicInteger();

        public ConnectionListener(ClientTest controller, String ip, int port) {
            this.controller = controller;
            this.ip = ip;
            this.port = port;
        }

        @Override
        public void operationComplete(ChannelFuture channelFuture) throws Exception {
            log.info("operation Complete");
            if (!channelFuture.isSuccess()) {
                channelFuture.channel().close();

                if (count.incrementAndGet() < MAX_RETRY) {
                    final EventLoop loop = channelFuture.channel().eventLoop();

                    //loop.schedule(() -> {
                    //    controller.connectRetry(this.ip, this.port, this);
                    //}, 1L, TimeUnit.SECONDS);
                } else {
                    log.info("Connection to the ovsdb {}:{} failed", this.ip, this.port);
                }
            } else {
                handleNewNodeConnection(channelFuture.channel());
            }
        }
    }

    private class ConnectionHandler extends ChannelDuplexHandler {

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            log.info("event triggerd");
            IdleStateEvent e = (IdleStateEvent) evt;

            if (e.state() == IdleState.READER_IDLE) {
                ctx.close();
            }
        }
    }

    public ChannelGroup getChannelGroup() {
        return cg;
    }
}