Package io.netty.channel

Source Code of io.netty.channel.ChannelHandlerUtil$SingleOutboundMessageHandler

/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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 io.netty.channel;

import io.netty.buffer.BufType;
import io.netty.buffer.BufUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.MessageBuf;
import io.netty.util.Signal;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
* Utility methods for use within your {@link ChannelHandler} implementation.
*/
public final class ChannelHandlerUtil {

    public static final Signal ABORT = new Signal(ChannelHandlerUtil.class.getName() + ".ABORT");

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelHandlerUtil.class);

    public static <T> void handleInboundBufferUpdated(
            ChannelHandlerContext ctx, SingleInboundMessageHandler<T> handler) throws Exception {
        MessageBuf<Object> in = ctx.inboundMessageBuffer();
        if (in.isEmpty() || !handler.beginMessageReceived(ctx)) {
            return;
        }

        MessageBuf<Object> out = ctx.nextInboundMessageBuffer();
        int oldOutSize = out.size();
        try {
            for (;;) {
                Object msg = in.poll();
                if (msg == null) {
                    break;
                }

                if (!handler.acceptInboundMessage(msg)) {
                    out.add(msg);
                    continue;
                }

                @SuppressWarnings("unchecked")
                T imsg = (T) msg;
                try {
                    handler.messageReceived(ctx, imsg);
                } finally {
                    BufUtil.release(imsg);
                }
            }
        } catch (Signal abort) {
            abort.expect(ABORT);
        } finally {
            if (oldOutSize != out.size()) {
                ctx.fireInboundBufferUpdated();
            }

            handler.endMessageReceived(ctx);
        }
    }

    public static <T> void handleFlush(
            ChannelHandlerContext ctx, ChannelPromise promise,
            SingleOutboundMessageHandler<T> handler) throws Exception {

        handleFlush(ctx, promise, true, handler);
    }

    public static <T> void handleFlush(
            ChannelHandlerContext ctx, ChannelPromise promise, boolean closeOnFailedFlush,
            SingleOutboundMessageHandler<T> handler) throws Exception {

        MessageBuf<Object> in = ctx.outboundMessageBuffer();
        final int inSize = in.size();
        if (inSize == 0) {
            ctx.flush(promise);
            return;
        }

        int processed = 0;
        try {
            if (!handler.beginFlush(ctx)) {
                throw new IncompleteFlushException(
                        "beginFlush(..) rejected the flush request by returning false. " +
                        "none of " + inSize + " message(s) fulshed.");
            }
            for (;;) {
                Object msg = in.poll();
                if (msg == null) {
                    break;
                }

                if (!handler.acceptOutboundMessage(msg)) {
                    addToNextOutboundBuffer(ctx, msg);
                    processed ++;
                    continue;
                }

                @SuppressWarnings("unchecked")
                T imsg = (T) msg;
                try {
                    handler.flush(ctx, imsg);
                    processed ++;
                } finally {
                    BufUtil.release(imsg);
                }
            }
        } catch (Throwable t) {
            IncompleteFlushException pfe;
            if (t instanceof IncompleteFlushException) {
                pfe = (IncompleteFlushException) t;
            } else {
                String msg = processed + " out of " + inSize + " message(s) flushed";
                if (t instanceof Signal) {
                    Signal abort = (Signal) t;
                    abort.expect(ABORT);
                    pfe = new IncompleteFlushException("aborted: " + msg);
                } else {
                    pfe = new IncompleteFlushException(msg, t);
                }
            }
            fail(ctx, promise, closeOnFailedFlush, pfe);
        }

        try {
            handler.endFlush(ctx);
        } catch (Throwable t) {
            if (promise.isDone()) {
                logger.warn("endFlush() raised a masked exception due to failed flush().", t);
            } else {
                fail(ctx, promise, closeOnFailedFlush, t);
            }
        }

        if (!promise.isDone()) {
            ctx.flush(promise);
        }
    }

    private static void fail(
            ChannelHandlerContext ctx, ChannelPromise promise, boolean closeOnFailedFlush, Throwable cause) {
        promise.setFailure(cause);
        if (closeOnFailedFlush) {
            ctx.close();
        }
    }

    /**
     * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()}
     * setting into account.
     */
    public static ByteBuf allocate(ChannelHandlerContext ctx) {
        switch(ctx.channel().config().getDefaultHandlerByteBufType()) {
            case DIRECT:
                return ctx.alloc().directBuffer();
            case PREFER_DIRECT:
                return ctx.alloc().ioBuffer();
            case HEAP:
                return ctx.alloc().heapBuffer();
            default:
                throw new IllegalStateException();
        }
    }

    /**
     * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()}
     * setting into account.
     */
    public static ByteBuf allocate(ChannelHandlerContext ctx, int initialCapacity) {
        switch(ctx.channel().config().getDefaultHandlerByteBufType()) {
            case DIRECT:
                return ctx.alloc().directBuffer(initialCapacity);
            case PREFER_DIRECT:
                return ctx.alloc().ioBuffer(initialCapacity);
            case HEAP:
                return ctx.alloc().heapBuffer(initialCapacity);
            default:
                throw new IllegalStateException();
        }
    }

    /**
     * Allocate a {@link ByteBuf} taking the {@link ChannelConfig#getDefaultHandlerByteBufType()}
     * setting into account.
     */
    public static ByteBuf allocate(ChannelHandlerContext ctx, int initialCapacity, int maxCapacity) {
        switch(ctx.channel().config().getDefaultHandlerByteBufType()) {
            case DIRECT:
                return ctx.alloc().directBuffer(initialCapacity, maxCapacity);
            case PREFER_DIRECT:
                return ctx.alloc().ioBuffer(initialCapacity, maxCapacity);
            case HEAP:
                return ctx.alloc().heapBuffer(initialCapacity, maxCapacity);
            default:
                throw new IllegalStateException();
        }
    }

    /**
     * Add the msg to the next outbound buffer in the {@link ChannelPipeline}. This takes special care of
     * msgs that are of type {@link ByteBuf}.
     */
    public static boolean addToNextOutboundBuffer(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof ByteBuf) {
            if (ctx.nextOutboundBufferType() == BufType.BYTE) {
                ctx.nextOutboundByteBuffer().writeBytes((ByteBuf) msg);
                return true;
            }
        }
        return ctx.nextOutboundMessageBuffer().add(msg);
    }

    /**
     * Add the msg to the next inbound buffer in the {@link ChannelPipeline}. This takes special care of
     * msgs that are of type {@link ByteBuf}.
     */
    public static boolean addToNextInboundBuffer(ChannelHandlerContext ctx, Object msg) {
        if (msg instanceof ByteBuf) {
            if (ctx.nextInboundBufferType() == BufType.BYTE) {
                ctx.nextInboundByteBuffer().writeBytes((ByteBuf) msg);
                return true;
            }
        }
        return ctx.nextInboundMessageBuffer().add(msg);
    }

    private ChannelHandlerUtil() { }

    public interface SingleInboundMessageHandler<T> {
        /**
         * Returns {@code true} if and only if the specified message can be handled by this handler.
         *
         * @param msg the message
         */
        boolean acceptInboundMessage(Object msg) throws Exception;

        /**
         * Will get notified once {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext)} was called.
         *
         * If this method returns {@code false} no further processing of the {@link MessageBuf}
         * will be done until the next call of {@link ChannelStateHandler#inboundBufferUpdated(ChannelHandlerContext)}.
         *
         * This will return {@code true} by default, and may get overriden by sub-classes for
         * special handling.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         */
        boolean beginMessageReceived(ChannelHandlerContext ctx) throws Exception;

        /**
         * Is called once a message was received.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         * @param msg           the message to handle
         */
        void messageReceived(ChannelHandlerContext ctx, T msg) throws Exception;

        /**
         * Is called when {@link #messageReceived(ChannelHandlerContext, Object)} returns.
         *
         * Super-classes may-override this for special handling.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         */
        void endMessageReceived(ChannelHandlerContext ctx) throws Exception;
    }

    public interface SingleOutboundMessageHandler<T> {
        /**
         * Returns {@code true} if and only if the specified message can be handled by this handler.
         *
         * @param msg the message
         */
        boolean acceptOutboundMessage(Object msg) throws Exception;

        /**
         * Will get notified once {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)}
         * was called.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         *
         * @return {@code true} to accept the flush request.  {@code false} to reject the flush request and
         *         to fail the promise associated with the flush request with {@link IncompleteFlushException}.
         */
        boolean beginFlush(ChannelHandlerContext ctx) throws Exception;

        /**
         * Is called once a message is being flushed.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         * @param msg           the message to handle
         */
        void flush(ChannelHandlerContext ctx, T msg) throws Exception;

        /**
         * Is called when {@link ChannelOperationHandler#flush(ChannelHandlerContext, ChannelPromise)} returns.
         *
         * Super-classes may-override this for special handling.
         *
         * @param ctx           the {@link ChannelHandlerContext} which this {@link ChannelHandler} belongs to
         */
        void endFlush(ChannelHandlerContext ctx) throws Exception;
    }
}
TOP

Related Classes of io.netty.channel.ChannelHandlerUtil$SingleOutboundMessageHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.