/*
 *     Copyright 2016-2026 TinyZ
 *
 * 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.ogcs.netty.impl;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.ogcs.netty.NettyBootstrap;

/**
 * TcpProtocolServer make easy to create tcp server(example : Socket, HTTP and others).
 *
 * The {@link #start()} method use to tcp server bind port.
 * The {@link #stop()} method use to the server shutdown.
 */
public abstract class TcpProtocolServer implements NettyBootstrap<ServerBootstrap> {

    private ServerBootstrap bootstrap;
    private EventLoopGroup parentGroup;
    private EventLoopGroup childGroup;
    protected int port;

    @Override
    public ServerBootstrap createBootstrap() {
        bootstrap = new ServerBootstrap();
        bootstrap.group(parentGroup(), childGroup());
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childHandler(newChannelInitializer());

        bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
//        bootstrap.option(ChannelOption.SO_REUSEADDR, true);
//        bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
        bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

        return bootstrap;
    }

    protected abstract ChannelHandler newChannelInitializer();

    @Override
    public void start() {
        ServerBootstrap sb = bootstrap() != null ? bootstrap() : createBootstrap();
        try {
            sb.bind(port()).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // add shutdown hook
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    stop();
                }
            }));
        }
    }

    @Override
    public void stop() {
        if (parentGroup != null) {
            parentGroup.shutdownGracefully();
            parentGroup = null;
        }
        if (childGroup != null) {
            childGroup.shutdownGracefully();
            childGroup = null;
        }
        bootstrap = null;
        port = 0;
    }

    @Override
    public ServerBootstrap bootstrap() {
        return bootstrap;
    }

    public EventLoopGroup parentGroup() {
        if (null == parentGroup)
            parentGroup = new NioEventLoopGroup();
        return parentGroup;
    }

    public EventLoopGroup childGroup() {
        if (null == childGroup) {
            childGroup = new NioEventLoopGroup();
        }
        return childGroup;
    }

    public int port() {
        return this.port;
    }

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

@@ -822,32 +822,176 @@
 EventLoopGroup;%0A
+import io.netty.channel.epoll.Epoll;%0Aimport io.netty.channel.epoll.EpollEventLoopGroup;%0Aimport io.netty.channel.epoll.EpollServerSocketChannel;%0A
 import io.netty.
@@ -1213,16 +1213,20 @@
 ers).%0A *
+ %3Cp%3E
 %0A * The 
@@ -1577,159 +1577,623 @@
     
-@Override%0A    public ServerBootstrap createBootstrap() %7B%0A        bootstrap = new ServerBootstrap();%0A        bootstrap.group(parentGroup(), childGroup()
+/**%0A     * Is netty transport native epoll.%0A     */%0A    protected static boolean isEpollAvailable = false;%0A%0A    static %7B%0A        isEpollAvailable = Epoll.isAvailable();%0A    %7D%0A%0A    @Override%0A    public ServerBootstrap createBootstrap() %7B%0A        bootstrap = new ServerBootstrap();%0A        if (isEpollAvailable) %7B%0A            this.parentGroup = new EpollEventLoopGroup();%0A            this.childGroup = new EpollEventLoopGroup();%0A            bootstrap.channel(EpollServerSocketChannel.class);%0A        %7D else %7B%0A            this.parentGroup = new NioEventLoopGroup();%0A            this.childGroup = new NioEventLoopGroup(
 );%0A 
@@ -2191,32 +2191,36 @@
 roup();%0A        
+    
 bootstrap.channe
@@ -2244,32 +2244,96 @@
 Channel.class);%0A
+        %7D%0A        bootstrap.group(parentGroup(), childGroup());%0A
         bootstra
@@ -3017,24 +3017,55 @@
 ackTrace();%0A
+            stop();// shutdown%0A
         %7D fi
@@ -3799,253 +3799,75 @@
     
-if (null == parentGroup)%0A            parentGroup = new NioEventLoopGroup();%0A        return parentGroup;%0A    %7D%0A%0A    public EventLoopGroup childGroup() %7B%0A        if (null == childGroup) %7B%0A            childGroup = new NioEventLoopGroup();%0A        %7D
+return parentGroup;%0A    %7D%0A%0A    public EventLoopGroup childGroup() %7B
 %0A   

Modify : 服务器Linux环境缺省使用Epoll模型。