Repository: netty/netty
File: transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java (Java)

Code before:
    public ChannelFuture disconnect() {
        return disconnect(newPromise());
    }

    @Override
    public ChannelFuture close() {
        return close(newPromise());
    }

    @Override
    public ChannelFuture deregister() {
        return deregister(newPromise());
    }

    /**
     * If possible check if the given {@link ChannelPromise} is using the same {@link EventExecutor} as this
     * {@link ChannelHandlerContext} and if not return a new {@link ChannelPromise} that runs on the same
     * {@link EventExecutor} as this {@link ChannelHandlerContext}. The result of the new {@link ChannelPromise} is
     * cascaded to the old {@link ChannelPromise}.
     *
     * This is done to ensure that {@link ChannelFutureListener}s that are added to the {@link ChannelPromise} by an
     * {@link ChannelOutboundHandler} are executed in the same thread as the handler itself. By doing so we can
     * ensure that there are not issues even if fields etc that are stored in the handler are modified by the listener.
     */
    private ChannelPromise ensurePromiseUseCorrectExecutor(ChannelPromise promise) {
        if (promise instanceof DefaultChannelPromise && !((DefaultChannelPromise) promise).executor().inEventLoop()) {
            ChannelPromise newPromise = newPromise();
            PromiseNotifier.cascade(newPromise, promise);
            return newPromise;
        }
        return promise;
    }
    @Override
    public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        ObjectUtil.checkNotNull(localAddress, "localAddress");
        if (isNotValidPromise(promise, false)) {
            // cancelled
            return promise;
        }

        final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeBind(localAddress, promise);
        } else {
            safeExecute(executor, new Runnable() {
                @Override
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null, false);

Review comment (suggestion):
if we merge https://github.com/netty/netty/pull/16039 we can do this without a cast in 5.0 and so make it work for any `Promise` implementation.

Code after:
    public ChannelFuture disconnect() {
        return disconnect(newPromise());
    }

    @Override
    public ChannelFuture close() {
        return close(newPromise());
    }

    @Override
    public ChannelFuture deregister() {
        return deregister(newPromise());
    }

    /**
     * If possible check if the given {@link ChannelPromise} is using the same {@link EventExecutor} as this
     * {@link ChannelHandlerContext} and if not return a new {@link ChannelPromise} that runs on the same
     * {@link EventExecutor} as this {@link ChannelHandlerContext}. The result of the new {@link ChannelPromise} is
     * cascaded to the old {@link ChannelPromise}.
     *
     * This is done to ensure that {@link ChannelFutureListener}s that are added to the {@link ChannelPromise} by an
     * {@link ChannelOutboundHandler} are executed in the same thread as the handler itself. By doing so we can
     * ensure that there are not issues even if fields etc that are stored in the handler are modified by the listener.
     */
    private ChannelPromise ensurePromiseUseCorrectExecutor(ChannelPromise promise) {
        if (promise instanceof DefaultChannelPromise && !((DefaultChannelPromise) promise).executor().inEventLoop()) {
            ChannelPromise newPromise = newPromise();
            PromiseNotifier.cascade(newPromise, promise);
            return newPromise;
        }
        return promise;
    }

    @Override
    public ChannelFuture bind(final SocketAddress localAddress, ChannelPromise promise) {
        ObjectUtil.checkNotNull(localAddress, "localAddress");
        if (isNotValidPromise(promise, false)) {
            // cancelled
            return promise;
        }

        final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            if (next.invokeHandler()) {
                promise = ensurePromiseUseCorrectExecutor(promise);
                try {
                    // DON'T CHANGE
                    // Duplex handlers implements both out/in interfaces causing a scalability issue
                    // see https://bugs.openjdk.org/browse/JDK-8180450
                    final ChannelHandler handler = next.handler();