org.skfiy.typhon.net.Netty4Connector.java Source code

Java tutorial

Introduction

Here is the source code for org.skfiy.typhon.net.Netty4Connector.java

Source

/*
 * Copyright 2014 The Skfiy Open Association.
 *
 * 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.skfiy.typhon.net;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.compression.ZlibCodecFactory;
import io.netty.handler.codec.compression.ZlibWrapper;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import javax.management.MBeanServer;
import org.skfiy.typhon.AbstractMBeanLifecycle;
import org.skfiy.typhon.Connector;
import org.skfiy.typhon.Container;
import org.skfiy.typhon.Globals;
import static org.skfiy.typhon.Lifecycle.START_EVENT;
import org.skfiy.typhon.LifecycleException;
import org.skfiy.typhon.LifecycleState;
import org.skfiy.typhon.Service;
import org.skfiy.typhon.TyphonException;
import org.skfiy.typhon.Typhons;
import org.skfiy.typhon.util.MBeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Kevin
 */
public class Netty4Connector extends AbstractMBeanLifecycle implements Connector {

    private static final Logger CLOG = LoggerFactory.getLogger(Globals.CONSOLE_LOG_NAME);

    private Service service;
    private String host;
    private int port;
    private boolean logEnabled;
    private long connectionTimeout;

    private Channel channel;
    private ServerBootstrap serverBootstrap;

    @Override
    public Service getService() {
        return service;
    }

    @Override
    public void setService(Service service) {
        this.service = service;
    }

    @Override
    public String getHost() {
        return host;
    }

    @Override
    public void setHost(String host) {
        this.host = host;
    }

    @Override
    public int getPort() {
        return port;
    }

    @Override
    public void setPort(int port) {
        this.port = port;
    }

    @Override
    public boolean isLogEnabled() {
        return logEnabled;
    }

    @Override
    public void setLogEnabled(boolean enabled) {
        this.logEnabled = enabled;
    }

    @Override
    public long getConnectionTimeout() {
        return connectionTimeout;
    }

    @Override
    public void setConnectionTimeout(long connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    @Override
    protected void startInternal() throws LifecycleException {
        setState(LifecycleState.STARTING);
        fireLifecycleListener(START_EVENT);

        System.setProperty("io.netty.noJdkZlibDecoder", "false");

        final byte[] delimiters = new byte[] { '\n' };

        final String compressionMode = Typhons.getProperty("typhon.spi.net.compressionMode");
        final Netty4EndpointHandler handler = new Netty4EndpointHandler();
        final Netty4ConnectionLimitHandler limitHandler = new Netty4ConnectionLimitHandler();

        // ????
        final LengthFieldPrepender lengthFieldPrepender;
        final DelimiterBasedFrameEncoder delimiterBasedFrameEncoder;
        if ("zlib".equals(compressionMode)) {
            lengthFieldPrepender = new LengthFieldPrepender(4);
            delimiterBasedFrameEncoder = null;
        } else {
            lengthFieldPrepender = null;
            delimiterBasedFrameEncoder = new DelimiterBasedFrameEncoder(delimiters);
        }

        // 
        final LoggingHandler loggingHandler;
        if (isLogEnabled()) {
            loggingHandler = new LoggingHandler(LogLevel.DEBUG);
        } else {
            loggingHandler = null;
        }

        serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                .childHandler(new ChannelInitializer() {

                    @Override
                    protected void initChannel(Channel c) throws Exception {
                        ChannelPipeline pipeline = c.pipeline();
                        if ("zlib".equals(compressionMode)) {
                            pipeline.addLast("lengthFieldPrepender", lengthFieldPrepender);
                            pipeline.addLast("lengthFieldBasedFrameDecoder",
                                    new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast("deflater", ZlibCodecFactory.newZlibEncoder(ZlibWrapper.ZLIB));
                        } else {
                            pipeline.addLast("delimiterBasedFrameDecoder", new DelimiterBasedFrameDecoder(65535,
                                    new ByteBuf[] { Unpooled.wrappedBuffer(delimiters) }));
                            pipeline.addLast("delimiterBasedFrameEncoder", delimiterBasedFrameEncoder);
                        }

                        if (isLogEnabled()) {
                            pipeline.addLast(loggingHandler);
                        }

                        pipeline.addLast(new IdleStateHandler(60 * 10, 60 * 10, 0));
                        pipeline.addLast(limitHandler, handler);
                    }
                });

        channel = serverBootstrap.bind(host, port).channel();
        CLOG.debug("Netty4Connector started on port {}", port);

        MBeanServer mbs = MBeanUtils.REGISTRY.getMBeanServer();
        Object obj = null;
        try {
            obj = mbs.invoke(Container.OBJECT_NAME, "getInstance", new Object[] { ProtocolHandler.class },
                    new String[] { Class.class.getName() });
        } catch (Exception ex) {
            CLOG.error("ProtocolHandler", ex);
            throw new TyphonException(ex);
        }
        handler.setProtocolHandler((ProtocolHandler) obj);
    }

    @Override
    protected void stopInternal() throws LifecycleException {
        setState(LifecycleState.STOPPING);

        ChannelFuture channelFuture = channel.closeFuture();
        serverBootstrap.group().shutdownGracefully();
        serverBootstrap.childGroup().shutdownGracefully();

        channelFuture.getNow();

        fireLifecycleListener(STOP_EVENT);
    }

    @Override
    protected String getMBeanDomain() {
        return "Connector";
    }

    @Override
    protected String getObjectNameKeyProperties() {
        return "name=Netty4Connector";
    }
}