net.NettyEngine4.ServerHandler.java Source code

Java tutorial

Introduction

Here is the source code for net.NettyEngine4.ServerHandler.java

Source

/*
 * Copyright (c) 2014. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

package net.NettyEngine4;

import com.dc.gameserver.ServerCore.Controller.AbstractController.IController;
import com.dc.gameserver.ServerCore.Service.character.PlayerInstance;
import com.google.protobuf.ExtensionRegistryLite;
import com.google.protobuf.MessageLite;
import com.google.protobuf.UninitializedMessageException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;

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

/**
 * @author :<br/>
 *         Project:CreazyGameServer1.8
 *         Date: 13-4-12
 *         Time: ?9:19
 *
 *         ChannelStateHandlerAdapter
 *         ChannelInboundByteHandlerAdapter
 *         ChannelDuplexHandler
 *         ChannelInboundHandlerAdapter
 *
 * This implementation just forward the operation to the next {@link io.netty.channel.ChannelHandler} in the
 * {@link io.netty.channel.ChannelPipeline}. Sub-classes may override a method implementation to change this.
 *
 *
 *    I/O?
 *
 *     I/O      ?   ?DB
 *
 *     EVENT_EXECUTORS ??  ServerHandler
 *     ?  ?
 *
 *
 *
 *    channel1.?ChannelRead()inactive?buf
 *                                       2.inactive??? RecyclableArrayList buf ChannelRead()
 *                                       
 *                                       3.  ?channel  RecyclableArrayListchannel?
 *
 *
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    public static final Logger logger = LoggerFactory.getLogger(ServerHandler.class);

    /**?--*/
    private static final AtomicInteger countConnection = new AtomicInteger(0);

    public static BeanFactory springContext; //spring context   manager by spring

    private PlayerInstance player;

    public ServerHandler() {
    }

    /**
     *  ????
     * Calls {@link io.netty.channel.ChannelHandlerContext#fireChannelActive()} to forward
     * to the next {@link io.netty.channel.ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        countConnection.getAndIncrement();// +1
        player = (PlayerInstance) ServerHandler.springContext.getBean("player");
        // player.setChannel(ctx.channel());
        if (logger.isDebugEnabled())
            logger.debug(ctx.channel() + "connect server... Concurrent  connection... " + countConnection.get());
    }

    /**
     * Calls {@link io.netty.channel.ChannelHandlerContext#fireChannelRead(Object)} to forward
     * to the next {@link io.netty.channel.ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
     * ?channel  RecyclableArrayListchannel?
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
        ByteBuf msg = (ByteBuf) message;
        /**
         *     if channel inactive  ,the finally  callback method{@link io.netty.handler.codec.ByteToMessageDecoder#channelInactive(io.netty.channel.ChannelHandlerContext)}
         *     this method will do some clear work ,if Recycle ArrayList is not empty ,so will invoke method channelRead,and release byteBuffer,
         *     every task(byteBuffer data which was store blockingQueue will be executor by the "" ,no matter what it's status)  ,
         *     so if the channel  inactive ,we will clear some buf ,in case of memory crash application,like this :
         */
        if (!ctx.channel().isActive()) { //inactive status , release buffer
            msg.release();
            msg = null;
        } else {
            try {
                /**ID**/
                int ID = msg.readInt();
                /**byte[]pb?**/
                int length = msg.readableBytes();
                if (length != 0) {
                    byte[] array = new byte[length];
                    msg.getBytes(msg.readerIndex(), array, 0, length);
                    msg.release(); //release byte buffer
                    msg = null; //collection by GC directly
                    MessageLite messageLite = IController.MESSAGE_LITE[ID].getParserForType().parseFrom(array, 0,
                            length, ExtensionRegistryLite.getEmptyRegistry());
                    array = null; //collection by GC directly
                    logger.debug("? &( ^___^ )&  -->" + messageLite.toString() + "ID:" + ID);
                    IController.GAME_CONTROLLERS[ID].DispatchMessageLit(messageLite, player);
                } else {
                    msg.release();
                    msg = null;
                    /**?null*/
                    IController.GAME_CONTROLLERS[ID].DispatchMessageLit(null, player);
                }
            } catch (UninitializedMessageException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Calls {@link io.netty.channel.ChannelHandlerContext#fireChannelInactive()} to forward
     * to the next {@link io.netty.channel.Channel} in the {@link io.netty.channel.ChannelPipeline}.
     *
     * Sub-classes may override this method to change behavior.
     *
     * ??
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        try {
            ctx.channel().close();
            //clear and store data!  channel closed!
            // this.player.saveAndDestory();

            countConnection.decrementAndGet();// -1

            if (logger.isDebugEnabled())
                logger.debug(ctx.channel().remoteAddress() + " channelClosed , Concurrent  connection... "
                        + countConnection.get());

            ChannelPipeline channelPipeline = ctx.channel().pipeline();

            if (null == channelPipeline) { // if null ,will be returned
                return;
            }
            //remove pipeline object
            while (channelPipeline.last() != null) {
                channelPipeline.removeLast();
            }
            if (ctx.isRemoved()) {
                ctx.close();
                // Set to null so the GC can collect them directly
                channelPipeline = null;
                ctx = null;
                player = null;
            }
        } catch (NoSuchElementException ee) {
            //do nothing
        } catch (Exception e) {
            if (logger.isDebugEnabled())
                logger.error("", e);
            //do nothing
        }
    }

    /**
     * ?
     * ?
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            //No data was received for a while.
            if (e.state() == IdleState.READER_IDLE) {
                //you can do sth ,such as timeout

                channel.close(); //call back channelInactive(ChannelHandlerContext ctx)
                if (logger.isDebugEnabled())
                    logger.debug(
                            channel.remoteAddress() + "---No data was received for a while ,read time out... ...");
            } //     because we are attaching  more importance to the read_idle time(timeout to rec)
            else if (e.state() == IdleState.WRITER_IDLE) { // No data was sent for a while.

                channel.close();
                if (logger.isDebugEnabled())
                    logger.debug(channel.remoteAddress() + "---No data was sent for a while.write time out... ...");
            }
        }
    }

    /**
     * ?
     * @return player  num
     */
    public static int getOnlinePlayers() {
        return countConnection.get();
    }

    /**
     * Sub-classes may override this method to change behavior.
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        //        try {
        ////            ctx.channel().close();
        ////            ctx.close();
        //        }catch (Exception e){
        //            e.printStackTrace();
        //        }

    }

    /**spring context**/
    public static void setSpringContext(BeanFactory springContext) {
        ServerHandler.springContext = springContext;
    }

}