Top Description Methods
io.netty5.channel

public Interface ChannelHandler

Known Direct Implementers
io.netty5.channel.ChannelHandlerAdapter, io.netty5.channel.ChannelInitializer, io.netty5.channel.SimpleChannelInboundHandler, io.netty5.channel.SimpleUserEventChannelHandler, io.netty5.channel.DefaultChannelPipeline.TailHandler, io.netty5.channel.DefaultChannelPipeline.HeadHandler, io.netty5.bootstrap.ServerBootstrap.ServerBootstrapAcceptor
Imports
io.netty5.buffer.Buffer, io.netty5.channel.ChannelHandlerMask.Skip, io.netty5.util.Attribute, .AttributeKey, io.netty5.util.concurrent.Future, java.net.SocketAddress

Handles an I/O event or intercepts an I/O operation, and forwards it to its next handler in its ChannelPipeline.

The context object

A ChannelHandler is provided with a ChannelHandlerContext object. A ChannelHandler is supposed to interact with the ChannelPipeline it belongs to via a context object. Using the context object, the ChannelHandler can pass events upstream or downstream, modify the pipeline dynamically, or store the information (using AttributeKeys) which is specific to the handler.

State management

A ChannelHandler often needs to store some stateful information. The simplest and recommended approach is to use member variables:
public interface Message {
    // your methods here
}

public class DataServerHandler extends SimpleChannelInboundHandler<Message> {

    private boolean loggedIn;

    @Override
    public void messageReceived(ChannelHandlerContext ctx, Message message) {
        if (message instanceof LoginMessage) {
            authenticate((LoginMessage) message);
            loggedIn = true;
        } else (message instanceof GetDataMessage) {
            if (loggedIn) {
                ctx.writeAndFlush(fetchSecret((GetDataMessage) message));
            } else {
                fail();
            }
        }
    }
    ...
}
Because the handler instance has a state variable which is dedicated to one connection, you have to create a new handler instance for each new channel to avoid a race condition where a unauthenticated client can get the confidential information:
// Create a new handler instance per channel.
// See ChannelInitializer#initChannel(Channel).
public class DataServerInitializer extends ChannelInitializer<Channel> {
    @Override
    public void initChannel(Channel channel) {
        channel.pipeline().addLast("handler", new DataServerHandler());
    }
}

Using AttributeKeys

Although it's recommended to use member variables to store the state of a handler, for some reason you might not want to create many handler instances. In such a case, you can use AttributeKeys which is provided by ChannelHandlerContext:
public interface Message {
    // your methods here
}

public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
    private final AttributeKey<Boolean> auth =
          AttributeKey.valueOf("auth");

    @Override
    public boolean isSharable() {
        return true;
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Message message) {
        Attribute<Boolean> attr = ctx.attr(auth);
        if (message instanceof LoginMessage) {
            authenticate((LoginMessage) o);
            attr.set(true);
        } else (message instanceof GetDataMessage) {
            if (Boolean.TRUE.equals(attr.get())) {
                ctx.writeAndFlush(fetchSecret((GetDataMessage) o));
            } else {
                fail();
            }
        }
    }
    ...
}
Now that the state of the handler is attached to the ChannelHandlerContext, you can add the same handler instance to different pipelines:
public class DataServerInitializer extends ChannelInitializer<Channel> {

    private static final DataServerHandler SHARED = new DataServerHandler();

    @Override
    public void initChannel(Channel channel) {
        channel.pipeline().addLast("handler", SHARED);
    }
}

The isSharable() method

In the example above which used an AttributeKey, you might have noticed the isSharable() method is override to return true.

If the ChannelHandler#isSharable() is returningtrue, it means you can create an instance of the handler just once and add it to one or more ChannelPipelines multiple times without a race condition.

If this method is not implemented and return false, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.

Additional resources worth reading

Please refer to the ChannelHandler, and ChannelPipeline to find out more about inbound and outbound operations, what fundamental differences they have, how they flow in a pipeline, and how to handle the operation in your application.

Method Summary

Modifier and TypeMethod and Description
public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
bind
(ChannelHandlerContext
the ChannelHandlerContext for which the bind operation is made
ctx
,
SocketAddress
the SocketAddress to which it should bound
localAddress
)

Called once a bind operation is made.

public default void
public default void
channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause)

Gets called if a Throwable was thrown when handling inbound events.

public default void
channelInactive(ChannelHandlerContext ctx)

The Channel of the ChannelHandlerContext was registered is now inactive and reached its end of lifetime.

public default void
channelInboundEvent(ChannelHandlerContext ctx, Object evt)

Gets called if a custom inbound event happened.

public default void
channelRead(ChannelHandlerContext ctx, Object msg)

Invoked when the current Channel has read a message from the peer.

public default void
channelReadComplete(ChannelHandlerContext ctx)

Invoked when the last message read by the current read operation has been consumed by channelRead(ChannelHandlerContext, Object).

public default void
public default void
channelShutdown(ChannelHandlerContext
the ChannelHandlerContext for which we notify about the completed shutdown.
ctx
,
ChannelShutdownDirection
the ChannelShutdownDirection of the completed shutdown.
direction
)

The Channel of the ChannelHandlerContext was shutdown in one direction.

public default void
public default void
channelWritabilityChanged(ChannelHandlerContext ctx)

Gets called once the writable state of a Channel changed.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
close
(ChannelHandlerContext
the ChannelHandlerContext for which the close operation is made
ctx
)

Called once a close operation is made.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
connect
(ChannelHandlerContext
the ChannelHandlerContext for which the connect operation is made
ctx
,
SocketAddress
the SocketAddress to which it should connect
remoteAddress
,
SocketAddress
the SocketAddress which is used as source on connect
localAddress
)

Called once a connect operation is made.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
deregister
(ChannelHandlerContext
the ChannelHandlerContext for which the deregister operation is made
ctx
)

Called once a deregister operation is made from the current registered EventLoop.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
disconnect
(ChannelHandlerContext
the ChannelHandlerContext for which the disconnect operation is made
ctx
)

Called once a disconnect operation is made.

public default void
flush(ChannelHandlerContext
the ChannelHandlerContext for which the flush operation is made
ctx
)

Called once a flush operation is made.

public default void
handlerAdded(ChannelHandlerContext ctx)

Gets called after the ChannelHandler was added to the actual context and it's ready to handle events.

public default void
handlerRemoved(ChannelHandlerContext ctx)

Gets called after the ChannelHandler was removed from the actual context and it doesn't handle events anymore.

public default boolean
isSharable()

Returns true if this handler is sharable and thus can be added to more than one ChannelPipeline.

public default long

Returns:

the number of buffered / queued bytes.
pendingOutboundBytes
(ChannelHandlerContext
the ChannelHandlerContext for which the operation is made.
ctx
)

The number of the outbound bytes that are buffered / queued in this ChannelHandler.

public default void
read(ChannelHandlerContext
the ChannelHandlerContext for which the read operation is made
ctx
,
ReadBufferAllocator
The ReadBufferAllocator that should be used to allocate a Buffer if needed (for reading the data).
readBufferAllocator
)

Called once a read operation is made from the current registered EventLoop.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
register
(ChannelHandlerContext
the ChannelHandlerContext for which the register operation is made
ctx
)

Called once a register operation is made to register for IO on the EventLoop.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
sendOutboundEvent
(ChannelHandlerContext
the ChannelHandlerContext for which the operation is made.
ctx
,
Object
the event.
event
)

Called once a custom defined outbound event was sent.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
shutdown
(ChannelHandlerContext
the ChannelHandlerContext for which the shutdown operation is made
ctx
,
ChannelShutdownDirection
the ChannelShutdownDirection that is used.
direction
)

Called once a shutdown operation was requested and should be executed.

public default Future<Void>

Returns:

the Future which will be notified once the operation completes.
write
(ChannelHandlerContext
the ChannelHandlerContext for which the write operation is made
ctx
,
Object
the message to write
msg
)

Called once a write operation is made.

Method Detail

bindback to summary
public default Future<Void> bind(ChannelHandlerContext ctx, SocketAddress localAddress)

Called once a bind operation is made.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the bind operation is made

localAddress:SocketAddress

the SocketAddress to which it should bound

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
channelActiveback to summary
public default void channelActive(ChannelHandlerContext ctx) throws Exception

The Channel of the ChannelHandlerContext is now active

Annotations
@Skip
channelExceptionCaughtback to summary
public default void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception

Gets called if a Throwable was thrown when handling inbound events.

Annotations
@Skip
channelInactiveback to summary
public default void channelInactive(ChannelHandlerContext ctx) throws Exception

The Channel of the ChannelHandlerContext was registered is now inactive and reached its end of lifetime.

Annotations
@Skip
channelInboundEventback to summary
public default void channelInboundEvent(ChannelHandlerContext ctx, Object evt) throws Exception

Gets called if a custom inbound event happened.

Annotations
@Skip
channelReadback to summary
public default void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception

Invoked when the current Channel has read a message from the peer.

Annotations
@Skip
channelReadCompleteback to summary
public default void channelReadComplete(ChannelHandlerContext ctx) throws Exception

Invoked when the last message read by the current read operation has been consumed by channelRead(ChannelHandlerContext, Object). If ChannelOption#AUTO_READ is off, no further attempt to read an inbound data from the current Channel will be made until ChannelOutboundInvoker#read(ReadBufferAllocator) is called.

Annotations
@Skip
channelRegisteredback to summary
public default void channelRegistered(ChannelHandlerContext ctx) throws Exception

The Channel of the ChannelHandlerContext was registered with its EventLoop

Annotations
@Skip
channelShutdownback to summary
public default void channelShutdown(ChannelHandlerContext ctx, ChannelShutdownDirection direction) throws Exception

The Channel of the ChannelHandlerContext was shutdown in one direction. This might either be because the remote peer did cause a shutdown of one direction or the shutdown was requested explicit by us and was executed.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which we notify about the completed shutdown.

direction:ChannelShutdownDirection

the ChannelShutdownDirection of the completed shutdown.

Annotations
@Skip
channelUnregisteredback to summary
public default void channelUnregistered(ChannelHandlerContext ctx) throws Exception

The Channel of the ChannelHandlerContext was unregistered from its EventLoop

Annotations
@Skip
channelWritabilityChangedback to summary
public default void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception

Gets called once the writable state of a Channel changed. You can check the state with Channel#writableBytes() or Channel#isWritable().

Annotations
@Skip
closeback to summary
public default Future<Void> close(ChannelHandlerContext ctx)

Called once a close operation is made.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the close operation is made

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
connectback to summary
public default Future<Void> connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress)

Called once a connect operation is made.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the connect operation is made

remoteAddress:SocketAddress

the SocketAddress to which it should connect

localAddress:SocketAddress

the SocketAddress which is used as source on connect

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
deregisterback to summary
public default Future<Void> deregister(ChannelHandlerContext ctx)

Called once a deregister operation is made from the current registered EventLoop.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the deregister operation is made

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
disconnectback to summary
public default Future<Void> disconnect(ChannelHandlerContext ctx)

Called once a disconnect operation is made.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the disconnect operation is made

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
flushback to summary
public default void flush(ChannelHandlerContext ctx)

Called once a flush operation is made. The flush operation will try to flush out all previous written messages that are pending.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the flush operation is made

Annotations
@Skip
handlerAddedback to summary
public default void handlerAdded(ChannelHandlerContext ctx) throws Exception

Gets called after the ChannelHandler was added to the actual context and it's ready to handle events.

handlerRemovedback to summary
public default void handlerRemoved(ChannelHandlerContext ctx) throws Exception

Gets called after the ChannelHandler was removed from the actual context and it doesn't handle events anymore.

isSharableback to summary
public default boolean isSharable()

Returns true if this handler is sharable and thus can be added to more than one ChannelPipeline. By default, this method returns false. If this method returns false, you have to create a new handler instance every time you add it to a pipeline because it has unshared state such as member variables.

pendingOutboundBytesback to summary
public default long pendingOutboundBytes(ChannelHandlerContext ctx)

The number of the outbound bytes that are buffered / queued in this ChannelHandler. This number will affect the writability of the Channel together the buffered / queued bytes in the Channel itself. By default this methods returns 0. If the ChannelHandler implementation buffers / queues outbound data this methods should be implemented to return the correct value.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the operation is made.

Returns:long

the number of buffered / queued bytes.

Annotations
@Skip
readback to summary
public default void read(ChannelHandlerContext ctx, ReadBufferAllocator readBufferAllocator)

Called once a read operation is made from the current registered EventLoop. If the ChannelHandler implementation queues the read and another read happens it is free to drop the first ReadBufferAllocator and just use the last one.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the read operation is made

readBufferAllocator:ReadBufferAllocator

The ReadBufferAllocator that should be used to allocate a Buffer if needed (for reading the data).

Annotations
@Skip
registerback to summary
public default Future<Void> register(ChannelHandlerContext ctx)

Called once a register operation is made to register for IO on the EventLoop.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the register operation is made

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
sendOutboundEventback to summary
public default Future<Void> sendOutboundEvent(ChannelHandlerContext ctx, Object event)

Called once a custom defined outbound event was sent. This operation will pass the event through the ChannelPipeline in the outbound direction.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the operation is made.

event:Object

the event.

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
shutdownback to summary
public default Future<Void> shutdown(ChannelHandlerContext ctx, ChannelShutdownDirection direction)

Called once a shutdown operation was requested and should be executed.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the shutdown operation is made

direction:ChannelShutdownDirection

the ChannelShutdownDirection that is used.

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip
writeback to summary
public default Future<Void> write(ChannelHandlerContext ctx, Object msg)

Called once a write operation is made. The write operation will write the messages through the ChannelPipeline. Those are then ready to be flushed to the actual Channel once Channel#flush() is called.

Parameters
ctx:ChannelHandlerContext

the ChannelHandlerContext for which the write operation is made

msg:Object

the message to write

Returns:Future<Void>

the Future which will be notified once the operation completes.

Annotations
@Skip