netty4.1.9 源码片段 - ChannelPipeline

4 篇文章 0 订阅

1、《管道》是双向的
2、《处理器上下文》
3、《处理器上下文》实现Invoker接口
4、《Pipeline》实现Invoker接口
5、《处理器》实现 ChannelInboundHandler 或者 ChannelOutboundHandler 接口

package cn.java.netty4_1_9.raw.server.internal;

import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.annotation.*;
import java.net.SocketAddress;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

/**
 */
@Slf4j
public class DefaultChannelPipelineTest {

    public static void main(String[] args) throws Exception {
        DefaultChannelPipeline defaultChannelPipeline = new DefaultChannelPipeline(null);

        defaultChannelPipeline.addLast(EventExecutorImpl.newCachedThreadPool(), new FooOneChannelInboundHandler());
        defaultChannelPipeline.addLast(EventExecutorImpl.newCachedThreadPool(), new FooOneChannelOutboundHandler());

        defaultChannelPipeline.fireChannelRegistered();
    }

    static class EventExecutorImpl extends ThreadPoolExecutor implements EventLoop {
        public EventExecutorImpl(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public static EventExecutorImpl newCachedThreadPool() {
            return new EventExecutorImpl(0, Integer.MAX_VALUE,
                    60L, TimeUnit.SECONDS,
                    new SynchronousQueue<Runnable>());
        }

        @Override
        public boolean inEventLoop() {
            return true;
        }

        @Override
        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
            return null;
        }

        @Override
        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
            return null;
        }

        @Override
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
            return null;
        }

        @Override
        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
            return null;
        }
    }

    static class FooOneChannelOutboundHandler implements ChannelOutboundHandler {

        @Override
        public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {

        }

        @Override
        public void read(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {

        }

        @Override
        public void flush(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        }

        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

        }
    }

    static class FooOneChannelInboundHandler implements ChannelInboundHandler {

        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            log.info("hello, this is " + getClass().getSimpleName() + ".");
            ctx.fireChannelRegistered();
        }

        @Override
        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        }

        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

        }
    }

    /**
     *
     */
    interface ChannelOutboundHandler extends ChannelHandler {
        void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception;

        void read(ChannelHandlerContext ctx) throws Exception;

        void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception;

        void flush(ChannelHandlerContext ctx) throws Exception;
    }

    interface ChannelInboundHandler extends ChannelHandler {
        void channelRegistered(ChannelHandlerContext ctx) throws Exception;

        void channelUnregistered(ChannelHandlerContext ctx) throws Exception;

        void channelActive(ChannelHandlerContext ctx) throws Exception;

        void channelInactive(ChannelHandlerContext ctx) throws Exception;

        void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

        void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
    }

    /**
     * {@link io.netty.channel.ChannelPipeline}
     */
    public interface ChannelPipeline extends ChannelInboundInvoker, ChannelOutboundInvoker {
        ChannelPipeline addLast(ChannelHandler... handlers);
    }

    /**
     * {@link io.netty.channel.DefaultChannelPipeline}
     */
    static class DefaultChannelPipeline implements ChannelPipeline {

        final AbstractChannelHandlerContext head;
        final AbstractChannelHandlerContext tail;

        private static final String HEAD_NAME = generateName0(HeadContext.class);
        private static final String TAIL_NAME = generateName0(TailContext.class);
        private final Channel channel;

        private static final Map<Class<?>, String> nameCaches = new WeakHashMap<>();

        private boolean registered;
        private PendingHandlerCallback pendingHandlerCallbackHead;

        protected DefaultChannelPipeline(Channel channel) {
            this.channel = channel;

            tail = new TailContext(this);
            head = new HeadContext(this);

            head.next = tail;
            tail.prev = head;
        }

        public final Channel channel() {
            return channel;
        }

        @Override
        public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {
            return null;
        }

        @Override
        public ChannelInboundInvoker fireChannelRegistered() {
            AbstractChannelHandlerContext.invokeChannelRegistered(head);
            return this;
        }

        @Override
        public ChannelInboundInvoker fireChannelUnregistered() {
            AbstractChannelHandlerContext.invokeChannelUnregistered(head);
            return this;
        }

        @Override
        public ChannelInboundInvoker fireChannelActive() {
            AbstractChannelHandlerContext.invokeChannelActive(head);
            return this;
        }

        @Override
        public ChannelInboundInvoker fireChannelInactive() {
            AbstractChannelHandlerContext.invokeChannelInactive(head);
            return this;
        }

        @Override
        public ChannelFuture bind(SocketAddress localAddress) {
            return tail.bind(localAddress);
        }

        @Override
        public ChannelOutboundInvoker read() {
            tail.read();
            return this;
        }

        @Override
        public ChannelFuture write(Object msg) {
            return tail.write(msg);
        }

        @Override
        public ChannelOutboundInvoker flush() {
            tail.flush();
            return this;
        }

        @Override
        public final ChannelPipeline addLast(ChannelHandler... handlers) {
            return addLast(null, handlers);
        }

        public final ChannelPipeline addLast(EventExecutor executor, ChannelHandler... handlers) {
            if (handlers == null) {
                throw new NullPointerException("handlers");
            }

            for (ChannelHandler h : handlers) {
                if (h == null) {
                    break;
                }
                addLast(executor, null, h);
            }

            return this;
        }

        /**
         * {@link io.netty.channel.DefaultChannelPipeline#addLast}
         */
        public final ChannelPipeline addLast(EventExecutor group, String name, ChannelHandler handler) {
            final AbstractChannelHandlerContext newCtx;
            synchronized (this) {
                checkMultiplicity(handler);

                newCtx = newContext(group, filterName(name, handler), handler);

                addLast0(newCtx);

                // If the registered is false it means that the channel was not registered on an eventloop yet.
                // In this case we add the context to the pipeline and add a task that will call
                // ChannelHandler.handlerAdded(...) once the channel is registered.
                if (!registered) {
                    newCtx.setAddPending();
                    callHandlerCallbackLater(newCtx, true);
                    return this;
                }

                EventExecutor executor = newCtx.executor();
                if (!executor.inEventLoop()) {
                    newCtx.setAddPending();
                    executor.execute(new Runnable() {
                        @Override
                        public void run() {
                            callHandlerAdded0(newCtx);
                        }
                    });
                    return this;
                }
            }

            callHandlerAdded0(newCtx);
            return this;
        }

        private AbstractChannelHandlerContext newContext(EventExecutor group, String name, ChannelHandler handler) {
            return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
        }

        private void callHandlerCallbackLater(AbstractChannelHandlerContext ctx, boolean added) {
            assert !registered;

            PendingHandlerCallback task = added ? new PendingHandlerAddedTask(ctx) : new PendingHandlerRemovedTask(ctx);
            PendingHandlerCallback pending = pendingHandlerCallbackHead;
            if (pending == null) {
                pendingHandlerCallbackHead = task;
            } else {
                // Find the tail of the linked-list.
                while (pending.next != null) {
                    pending = pending.next;
                }
                pending.next = task;
            }
        }

        private void addLast0(AbstractChannelHandlerContext newCtx) {
            AbstractChannelHandlerContext prev = tail.prev;
            newCtx.prev = prev;
            newCtx.next = tail;
            prev.next = newCtx;
            tail.prev = newCtx;
        }

        private String filterName(String name, ChannelHandler handler) {
            if (name == null) {
                return generateName(handler);
            }
            checkDuplicateName(name);
            return name;
        }

        private EventExecutor childExecutor(EventExecutor group) {
            return EventExecutorImpl.newCachedThreadPool();
            // return null;
        }

        private void checkDuplicateName(String name) {
            if (context0(name) != null) {
                throw new IllegalArgumentException("Duplicate handler name: " + name);
            }
        }

        private String generateName(ChannelHandler handler) {
            Map<Class<?>, String> cache = nameCaches;
            Class<?> handlerType = handler.getClass();
            String name = cache.get(handlerType);
            if (name == null) {
                name = generateName0(handlerType);
                cache.put(handlerType, name);
            }

            // It's not very likely for a user to put more than one handler of the same type, but make sure to avoid
            // any name conflicts.  Note that we don't cache the names generated here.
            if (context0(name) != null) {
                String baseName = name.substring(0, name.length() - 1); // Strip the trailing '0'.
                for (int i = 1; ; i++) {
                    String newName = baseName + i;
                    if (context0(newName) == null) {
                        name = newName;
                        break;
                    }
                }
            }
            return name;
        }

        private AbstractChannelHandlerContext context0(String name) {
            AbstractChannelHandlerContext context = head.next;
            while (context != tail) {
                if (context.name().equals(name)) {
                    return context;
                }
                context = context.next;
            }
            return null;
        }

        private static void checkMultiplicity(ChannelHandler handler) {
            if (handler instanceof ChannelHandlerAdapter) {
                ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
                if (!h.isSharable() && h.added) {
                    throw new RuntimeException(h.getClass().getName() + " is not a @Sharable handler, so can't be added or removed multiple times.");
                }
                h.added = true;
            }
        }

        private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
            // Notify the complete removal.
            try {
                try {
                    ctx.handler().handlerRemoved(ctx);
                } finally {
                    ctx.setRemoved();
                }
            } catch (Throwable t) {
                fireExceptionCaught(new RuntimeException(
                        ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
            }
        }

        private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
            try {
                ctx.handler().handlerAdded(ctx);
                ctx.setAddComplete();
            } catch (Throwable t) {
                boolean removed = false;
                try {
                    remove0(ctx);
                    try {
                        ctx.handler().handlerRemoved(ctx);
                    } finally {
                        ctx.setRemoved();
                    }
                    removed = true;
                } catch (Throwable t2) {
                    if (log.isWarnEnabled()) {
                        log.warn("Failed to remove a handler: " + ctx.name(), t2);
                    }
                }

                if (removed) {
                    fireExceptionCaught(new RuntimeException(
                            ctx.handler().getClass().getName() +
                                    ".handlerAdded() has thrown an exception; removed.", t));
                } else {
                    fireExceptionCaught(new RuntimeException(
                            ctx.handler().getClass().getName() +
                                    ".handlerAdded() has thrown an exception; also failed to remove.", t));
                }
            }
        }

        private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
            assert ctx != head && ctx != tail;

            synchronized (this) {
                remove0(ctx);

                // If the registered is false it means that the channel was not registered on an eventloop yet.
                // In this case we remove the context from the pipeline and add a task that will call
                // ChannelHandler.handlerRemoved(...) once the channel is registered.
                if (!registered) {
                    callHandlerCallbackLater(ctx, false);
                    return ctx;
                }

                EventExecutor executor = ctx.executor();
                if (!executor.inEventLoop()) {
                    executor.execute(new Runnable() {
                        @Override
                        public void run() {
                            callHandlerRemoved0(ctx);
                        }
                    });
                    return ctx;
                }
            }
            callHandlerRemoved0(ctx);
            return ctx;
        }

        private static void remove0(AbstractChannelHandlerContext ctx) {
            AbstractChannelHandlerContext prev = ctx.prev;
            AbstractChannelHandlerContext next = ctx.next;
            prev.next = next;
            next.prev = prev;
        }

        private static String generateName0(Class<?> handlerType) {
            return handlerType.getSimpleName() + "#0";
        }

        final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
            TailContext(DefaultChannelPipeline pipeline) {
                // super(pipeline, null, TAIL_NAME, true, false);
                super(pipeline, EventExecutorImpl.newCachedThreadPool(), TAIL_NAME, true, false);
                setAddComplete();
            }

            @Override
            public ChannelHandler handler() {
                return this;
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

            }

            @Override
            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            }

            @Override
            public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelInactive(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

            }

            @Override
            public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

            }
        }

        final class HeadContext extends AbstractChannelHandlerContext implements ChannelOutboundHandler, ChannelInboundHandler {
            HeadContext(DefaultChannelPipeline pipeline) {
                super(pipeline, EventExecutorImpl.newCachedThreadPool(), HEAD_NAME, false, true);
                // super(pipeline, null, HEAD_NAME, false, true);
                setAddComplete();
            }

            @Override
            public ChannelHandler handler() {
                return this;
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

            }

            @Override
            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {

            }

            @Override
            public void read(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {

            }

            @Override
            public void flush(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                log.info("hello, this is " + getClass().getSimpleName() + ".");
                ctx.fireChannelRegistered();
            }

            @Override
            public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelActive(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelInactive(ChannelHandlerContext ctx) throws Exception {

            }

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

            }

            @Override
            public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

            }
        }

        abstract class PendingHandlerCallback implements Runnable {
            final AbstractChannelHandlerContext ctx;
            PendingHandlerCallback next;

            PendingHandlerCallback(AbstractChannelHandlerContext ctx) {
                this.ctx = ctx;
            }

            abstract void execute();
        }

        class PendingHandlerAddedTask extends PendingHandlerCallback {
            PendingHandlerAddedTask(AbstractChannelHandlerContext ctx) {
                super(ctx);
            }

            @Override
            public void run() {
                callHandlerAdded0(ctx);
            }

            @Override
            void execute() {
                EventExecutor executor = ctx.executor();
                if (executor.inEventLoop()) {
                    callHandlerAdded0(ctx);
                } else {
                    try {
                        executor.execute(this);
                    } catch (Exception e) {
                        if (log.isWarnEnabled()) {
                            log.warn(
                                    "Can't invoke handlerAdded() as the EventExecutor {} rejected it, removing handler {}.",
                                    executor, ctx.name(), e);
                        }
                        remove0(ctx);
                        ctx.setRemoved();
                    }
                }
            }
        }

        final class PendingHandlerRemovedTask extends PendingHandlerCallback {
            PendingHandlerRemovedTask(AbstractChannelHandlerContext ctx) {
                super(ctx);
            }

            @Override
            public void run() {
                callHandlerRemoved0(ctx);
            }

            @Override
            void execute() {
                EventExecutor executor = ctx.executor();
                if (executor.inEventLoop()) {
                    callHandlerRemoved0(ctx);
                } else {
                    try {
                        executor.execute(this);
                    } catch (Exception e) {
                        if (log.isWarnEnabled()) {
                            log.warn(
                                    "Can't invoke handlerRemoved() as the EventExecutor {} rejected it," +
                                            " removing handler {}.", executor, ctx.name(), e);
                        }
                        // remove0(...) was call before so just call AbstractChannelHandlerContext.setRemoved().
                        ctx.setRemoved();
                    }
                }
            }
        }
    }


    static class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {

        private final ChannelHandler handler;

        DefaultChannelHandlerContext(
                DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
            super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
            if (handler == null) {
                throw new NullPointerException("handler");
            }
            this.handler = handler;
        }

        @Override
        public ChannelHandler handler() {
            return handler;
        }

        private static boolean isInbound(ChannelHandler handler) {
            return handler instanceof ChannelInboundHandler;
        }

        private static boolean isOutbound(ChannelHandler handler) {
            return handler instanceof ChannelOutboundHandler;
        }
    }

    static abstract class ChannelHandlerAdapter {
        boolean added;

        public boolean isSharable() {
            Class<?> clazz = getClass();
            Boolean sharable = clazz.isAnnotationPresent(Sharable.class);
            return sharable;
        }
    }

    interface EventExecutor extends ScheduledExecutorService {
        boolean inEventLoop();
    }

    interface EventLoop extends EventExecutor {

    }

    interface Channel {
        EventLoop eventLoop();
    }

    /**
     * 《ChannelInbound》调用器
     */
    public interface ChannelInboundInvoker {
        /**
         *
         */
        ChannelInboundInvoker fireChannelRegistered();

        /**
         *
         */
        ChannelInboundInvoker fireChannelUnregistered();

        /**
         *
         */
        ChannelInboundInvoker fireChannelActive();

        /**
         *
         */
        ChannelInboundInvoker fireChannelInactive();

        ChannelInboundInvoker fireExceptionCaught(Throwable cause);
    }

    /**
     * 《ChannelOutbound》调用器
     */
    public interface ChannelOutboundInvoker {
        ChannelFuture bind(SocketAddress localAddress);

        ChannelOutboundInvoker read();

        ChannelFuture write(Object msg);

        ChannelOutboundInvoker flush();
    }

    interface ChannelHandlerContext extends ChannelInboundInvoker, ChannelOutboundInvoker {
        EventExecutor executor();

        ChannelHandler handler();

        @Override
        ChannelHandlerContext fireExceptionCaught(Throwable cause);
    }

    /**
     * {@link io.netty.channel.AbstractChannelHandlerContext}
     */
    static abstract class AbstractChannelHandlerContext implements ChannelHandlerContext {
        /**
         * 链
         */
        volatile AbstractChannelHandlerContext next;
        volatile AbstractChannelHandlerContext prev;

        /**
         * ChannelHandler 类型
         */
        private final boolean inbound;
        private final boolean outbound;

        private final DefaultChannelPipeline pipeline;
        private final String name;
        private final boolean ordered;
        final EventExecutor executor;
        private volatile int handlerState = INIT;

        private static final AtomicIntegerFieldUpdater<AbstractChannelHandlerContext> HANDLER_STATE_UPDATER =
                AtomicIntegerFieldUpdater.newUpdater(AbstractChannelHandlerContext.class, "handlerState");

        private Runnable invokeReadTask;

        /**
         * 管道状态
         */
        private static final int ADD_PENDING = 1;
        private static final int ADD_COMPLETE = 2;
        private static final int REMOVE_COMPLETE = 3;
        private static final int INIT = 0;

        AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
                                      boolean inbound, boolean outbound) {
            this.name = name;
            this.pipeline = pipeline;
            this.executor = executor;
            this.inbound = inbound;
            this.outbound = outbound;
            ordered = executor == null;
        }

        public Channel channel() {
            return pipeline.channel();
        }

        public String name() {
            return name;
        }

        final void setRemoved() {
            handlerState = REMOVE_COMPLETE;
        }

        final void setAddComplete() {
            for (; ; ) {
                int oldState = handlerState;
                // Ensure we never update when the handlerState is REMOVE_COMPLETE already.
                // oldState is usually ADD_PENDING but can also be REMOVE_COMPLETE when an EventExecutor is used that is not
                // exposing ordering guarantees.
                if (oldState == REMOVE_COMPLETE || HANDLER_STATE_UPDATER.compareAndSet(this, oldState, ADD_COMPLETE)) {
                    return;
                }
            }
        }

        final void setAddPending() {
            boolean updated = HANDLER_STATE_UPDATER.compareAndSet(this, INIT, ADD_PENDING);
            assert updated; // This should always be true as it MUST be called before setAddComplete() or setRemoved().
        }

        public EventExecutor executor() {
            if (executor == null) {
                return channel().eventLoop();
            } else {
                return executor;
            }
        }

        private AbstractChannelHandlerContext findContextInbound() {
            AbstractChannelHandlerContext ctx = this;
            do {
                ctx = ctx.next;
            } while (!ctx.inbound);
            return ctx;
        }

        private AbstractChannelHandlerContext findContextOutbound() {
            AbstractChannelHandlerContext ctx = this;
            do {
                ctx = ctx.prev;
            } while (!ctx.outbound);
            return ctx;
        }

        static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeChannelRegistered();
            } else {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeChannelRegistered();
                    }
                });
            }
        }

        private boolean invokeHandler() {
            // Store in local variable to reduce volatile reads.
            int handlerState = this.handlerState;
            return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
        }

        private void invokeChannelRegistered() {
            if (invokeHandler()) {
                try {
                    ((ChannelInboundHandler) handler()).channelRegistered(this);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                fireChannelRegistered();
            }
        }

        private void notifyHandlerException(Throwable cause) {
            cause.printStackTrace();
            if (inExceptionCaught(cause)) {
                if (log.isWarnEnabled()) {
                    log.warn("An exception was thrown by a user handler while handling an exceptionCaught event", cause);
                }
                return;
            }

            invokeExceptionCaught(cause);
        }

        private static boolean inExceptionCaught(Throwable cause) {
            do {
                StackTraceElement[] trace = cause.getStackTrace();
                if (trace != null) {
                    for (StackTraceElement t : trace) {
                        if (t == null) {
                            break;
                        }
                        if ("exceptionCaught".equals(t.getMethodName())) {
                            return true;
                        }
                    }
                }

                cause = cause.getCause();
            } while (cause != null);

            return false;
        }

        private void invokeExceptionCaught(final Throwable cause) {
            if (invokeHandler()) {
                try {
                    handler().exceptionCaught(this, cause);
                } catch (Throwable error) {
                    if (log.isDebugEnabled()) {
                        log.debug(
                                "An exception {}" +
                                        "was thrown by a user handler's exceptionCaught() " +
                                        "method while handling the following exception:",
                                ThrowableUtil.stackTraceToString(error), cause);
                    } else if (log.isWarnEnabled()) {
                        log.warn(
                                "An exception '{}' [enable DEBUG level for full stacktrace] " +
                                        "was thrown by a user handler's exceptionCaught() " +
                                        "method while handling the following exception:", error, cause);
                    }
                }
            } else {
                fireExceptionCaught(cause);
            }
        }

        static void invokeExceptionCaught(final AbstractChannelHandlerContext next, final Throwable cause) {
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeExceptionCaught(cause);
            } else {
                try {
                    executor.execute(new Runnable() {
                        @Override
                        public void run() {
                            next.invokeExceptionCaught(cause);
                        }
                    });
                } catch (Throwable t) {
                    if (log.isWarnEnabled()) {
                        log.warn("Failed to submit an exceptionCaught() event.", t);
                        log.warn("The exceptionCaught() event that was failed to submit was:", cause);
                    }
                }
            }
        }

        @Override
        public ChannelHandlerContext fireExceptionCaught(final Throwable cause) {
            invokeExceptionCaught(next, cause);
            return this;
        }

        @Override
        public ChannelInboundInvoker fireChannelRegistered() {
            invokeChannelRegistered(findContextInbound());
            return this;
        }

        @Override
        public ChannelInboundInvoker fireChannelUnregistered() {
            invokeChannelUnregistered(findContextInbound());
            return this;
        }

        static void invokeChannelUnregistered(final AbstractChannelHandlerContext next) {
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeChannelUnregistered();
            } else {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeChannelUnregistered();
                    }
                });
            }
        }

        private void invokeChannelUnregistered() {
            if (invokeHandler()) {
                try {
                    ((ChannelInboundHandler) handler()).channelUnregistered(this);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                fireChannelUnregistered();
            }
        }

        @Override
        public ChannelHandlerContext fireChannelActive() {
            invokeChannelActive(findContextInbound());
            return this;
        }

        static void invokeChannelActive(final AbstractChannelHandlerContext next) {
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeChannelActive();
            } else {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeChannelActive();
                    }
                });
            }
        }

        private void invokeChannelActive() {
            if (invokeHandler()) {
                try {
                    ((ChannelInboundHandler) handler()).channelActive(this);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                fireChannelActive();
            }
        }

        @Override
        public ChannelHandlerContext fireChannelInactive() {
            invokeChannelInactive(findContextInbound());
            return this;
        }

        static void invokeChannelInactive(final AbstractChannelHandlerContext next) {
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeChannelInactive();
            } else {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeChannelInactive();
                    }
                });
            }
        }

        private void invokeChannelInactive() {
            if (invokeHandler()) {
                try {
                    ((ChannelInboundHandler) handler()).channelInactive(this);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                fireChannelInactive();
            }
        }

        @Override
        public ChannelFuture bind(SocketAddress localAddress) {
            return null;
        }

        @Override
        public ChannelOutboundInvoker read() {
            final AbstractChannelHandlerContext next = findContextOutbound();
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeRead();
            } else {
                Runnable task = next.invokeReadTask;
                if (task == null) {
                    next.invokeReadTask = task = new Runnable() {
                        @Override
                        public void run() {
                            next.invokeRead();
                        }
                    };
                }
                executor.execute(task);
            }

            return this;
        }

        private void invokeRead() {
            if (invokeHandler()) {
                try {
                    ((ChannelOutboundHandler) handler()).read(this);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                read();
            }
        }

        @Override
        public ChannelFuture write(Object msg) {
            return null;
        }

        @Override
        public ChannelOutboundInvoker flush() {
            return null;
        }
    }

    interface ChannelHandler {
        void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

        void handlerRemoved(ChannelHandlerContext ctx) throws Exception;

        void handlerAdded(ChannelHandlerContext ctx) throws Exception;
    }

    @Inherited
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Sharable {
        // no value
    }


    public interface ChannelFuture extends java.util.concurrent.Future<Void> {

    }

    public interface ChannelPromise extends java.util.concurrent.Future<Void> {

    }

    static final class ThrowableUtil {

        private ThrowableUtil() {
        }

        /**
         *
         */
        public static <T extends Throwable> T unknownStackTrace(T cause, Class<?> clazz, String method) {
            cause.setStackTrace(new StackTraceElement[]{new StackTraceElement(clazz.getName(), method, null, -1)});
            return cause;
        }

        /**
         *
         */
        public static String stackTraceToString(Throwable cause) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            PrintStream pout = new PrintStream(out);
            cause.printStackTrace(pout);
            pout.flush();
            try {
                return new String(out.toByteArray());
            } finally {
                try {
                    out.close();
                } catch (IOException ignore) {
                    // ignore as should never happen
                }
            }
        }
    }

}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值