io.flood.rpc.network.ConnectorImpl.java Source code

Java tutorial

Introduction

Here is the source code for io.flood.rpc.network.ConnectorImpl.java

Source

/*
 * Copyright 2015 The RPC Project
 *
 * The RPC Project licenses this file to you 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 io.flood.rpc.network;

import io.flood.common.utils.LogHelper;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

public class ConnectorImpl extends AbstractSocketWapper implements Connector {

    private static final Logger LOG = LoggerFactory.getLogger(ConnectorImpl.class);
    private final Bootstrap boot = new Bootstrap();
    private final AtomicBoolean isConnected = new AtomicBoolean(false);
    private final AtomicBoolean isInitiative = new AtomicBoolean(false);
    private final List<CompleteListener> listenerList = new ArrayList<CompleteListener>();
    private Channel channel;
    private int id = -1;

    public ConnectorImpl(MessageDispatcher<NetPackage> messageDispatcher) {
        super(messageDispatcher);
    }

    public void addCompleteListener(CompleteListener listener) {
        listenerList.add(listener);
    }

    private synchronized void broadcastComplete(ChannelFuture future) {
        for (CompleteListener listener : listenerList) {
            listener.apply(future);
        }
    }

    public ChannelFuture connect(String address, int port, int retryTime) {

        boot.group(bossGroup).option(ChannelOption.TCP_NODELAY, true);
        boot.channel(NioSocketChannel.class);
        boot.handler(new ChannelInitializer<SocketChannel>() {
            protected void initChannel(SocketChannel ch) throws Exception {
                LinkedHashMap<String, ChannelHandler> handlers = getHandlers();
                for (Map.Entry<String, ChannelHandler> entry : handlers.entrySet()) {
                    ch.pipeline().addLast(entry.getKey(), entry.getValue());
                }
                ch.pipeline().addLast("messageDecoder", new MessageDecoder());
                ch.pipeline().addLast("messageEncoder", new MessageEncoder());
                ch.pipeline().addLast("messageHandler", new MessageHandler(ConnectorImpl.this));
            }
        });
        return connect0(new InetSocketAddress(address, port), retryTime);

    }

    private ChannelFuture connect0(final SocketAddress address, final int retryTime) {
        id = SocketIdGenerator.nextId();
        final ChannelFuture future = boot.connect(address);
        future.addListener(new GenericFutureListener<Future<? super Void>>() {
            public void operationComplete(io.netty.util.concurrent.Future<? super Void> completeFuture)
                    throws Exception {

                broadcastComplete(future);

                if (completeFuture.isSuccess()) {
                    channel = future.channel();
                    LOG.info(LogHelper.format(id, "connected to server ({}=>{})"), channel.localAddress(),
                            channel.remoteAddress());
                    ConnectionManager.put(id, Connection.Type.Client, channel);

                    future.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
                        public void operationComplete(Future<? super Void> completeFuture) throws Exception {
                            LOG.info(
                                    LogHelper.format(id,
                                            "connection closed ,after {} millisecond  will be reconnect"),
                                    retryTime);
                            if (!isInitiative.get()) {
                                Thread.sleep(retryTime);
                                connect0(address, retryTime);
                            }
                        }
                    });

                } else {
                    LOG.info(LogHelper.format(id, "connet to server failed({})"), address);
                }
            }
        });
        return future;
    }

    public void shutdown() {
        isInitiative.set(true);
        bossGroup.shutdownGracefully();
    }

    public void writeAndFlush(Object object) throws IOException {

        if (channel == null || !channel.isActive()) {
            throw new IOException("not connected to server or not active!");
        }
        channel.writeAndFlush(object);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        isConnected.set(true);
    }

    @Override
    public boolean isAlived() {
        return isConnected.get();
    }
}