org.msgpack.rpc.impl.netty.NettyTcpClientTransport.java Source code

Java tutorial

Introduction

Here is the source code for org.msgpack.rpc.impl.netty.NettyTcpClientTransport.java

Source

//
// MessagePack-RPC for Java
//
// Copyright (C) 2010 FURUHASHI Sadayuki
//
//    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.msgpack.rpc.impl.netty;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import org.msgpack.rpc.message.Message;
import org.msgpack.rpc.Session;
import org.msgpack.rpc.config.TcpClientConfig;
import org.msgpack.rpc.transport.ClientTransport;
import org.msgpack.rpc.transport.RpcMessageHandler;

class NettyTcpClientTransport implements ClientTransport {

    private final Session _session;
    private final Bootstrap _bootstrap;
    private final AtomicInteger _availables = new AtomicInteger(1024);
    private final ConcurrentLinkedQueue<Channel> _writables;

    NettyTcpClientTransport(final TcpClientConfig config, final Session session, final NettyEventLoop loop) {
        // TODO check session.getAddress() instanceof IPAddress
        final RpcMessageHandler handler = new RpcMessageHandler(session);

        _bootstrap = new Bootstrap().group(new NioEventLoopGroup(/*2*/)).channel(NioSocketChannel.class)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.round((float) config.getConnectTimeout()))
                .option(ChannelOption.TCP_NODELAY,
                        !Boolean.FALSE.equals(config.getOption(ChannelOption.TCP_NODELAY.name())))
                .option(ChannelOption.SO_KEEPALIVE,
                        !Boolean.FALSE.equals(config.getOption(ChannelOption.SO_KEEPALIVE.name())))
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new MessagePackDecoder(loop.getObjectMapper()),
                                new MessageHandler(handler), new MessagePackEncoder(loop.getObjectMapper()));
                    }
                });

        _session = session;
        _writables = new ConcurrentLinkedQueue<>();
    }

    protected ChannelFuture startConnection() {
        return _bootstrap.connect(_session.getAddress().getSocketAddress());
    }

    public void sendMessage(final Message msg) {
        if (_writables.isEmpty() && _availables.getAndDecrement() > 0) {
            startConnection().addListener(new ChannelFutureListener() {

                public void operationComplete(ChannelFuture future) throws Exception {
                    final Channel connected = future.channel();
                    sendMessageChannel(connected, msg);
                    connected.closeFuture().addListener(new ChannelFutureListener() {
                        public void operationComplete(ChannelFuture channelFuture) throws Exception {
                            _availables.incrementAndGet();
                        }
                    });
                }
            });
        } else {
            final Channel writable = _writables.poll();
            if (writable != null) {
                sendMessageChannel(writable, msg);
            } else {
                Thread.yield();
                sendMessage(msg);
            }
        }
    }

    public void close() {
        while (!_writables.isEmpty()) {
            _writables.poll().close();
        }
    }

    protected ChannelFuture sendMessageChannel(Channel c, Object msg) {
        return c.writeAndFlush(msg).addListener(new ChannelFutureListener() {

            public void operationComplete(ChannelFuture future) throws Exception {
                _writables.offer(future.channel());
            }
        });
    }
}