public interface ChannelHandler
ChannelPipeline
.
ChannelHandlerAdapter
instead
Because this interface has many methods to implement, you might want to extend ChannelHandlerAdapter
instead.
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 AttributeKey
s) which is specific to the handler.
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 extendsBecause 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:SimpleChannelInboundHandler
<Message> { private boolean loggedIn;@Override
protected void messageReceived(ChannelHandlerContext
ctx, Message message) {Channel
ch = e.getChannel(); if (message instanceof LoginMessage) { authenticate((LoginMessage) message); loggedIn = true; } else (message instanceof GetDataMessage) { if (loggedIn) { ch.write(fetchSecret((GetDataMessage) message)); } else { fail(); } } } ... }
// Create a new handler instance per channel. // SeeChannelInitializer.initChannel(Channel)
. public class DataServerInitializer extendsChannelInitializer
<Channel
> {@Override
public void initChannel(Channel
channel) { channel.pipeline().addLast("handler", new DataServerHandler()); } }
AttributeKey
sAttributeKey
s which are attached to the
ChannelHandlerContext
:
public interface Message { // your methods here }Now that the state of the handler is attached to the@Sharable
public class DataServerHandler extendsSimpleChannelInboundHandler
<Message> { private finalAttributeKey
<Boolean
> auth =AttributeKey.valueOf("auth")
;@Override
protected void messageReceived(ChannelHandlerContext
ctx, Message message) {Attribute
<Boolean
> attr = ctx.attr(auth);Channel
ch = ctx.channel(); if (message instanceof LoginMessage) { authenticate((LoginMessage) o); attr.set(true); } else (message instanceof GetDataMessage) { if (Boolean.TRUE.equals(attr.get())) { ch.write(fetchSecret((GetDataMessage) o)); } else { fail(); } } } ... }
ChannelHandlerContext
, you can add the
same handler instance to different pipelines:
public class DataServerInitializer extendsChannelInitializer
<Channel
> { private static final DataServerHandler SHARED = new DataServerHandler();@Override
public void initChannel(Channel
channel) { channel.pipeline().addLast("handler", SHARED); } }
@Sharable
annotation
In the example above which used an AttributeKey
,
you might have noticed the @Sharable
annotation.
If a ChannelHandler
is annotated with the @Sharable
annotation, it means you can create an instance of the handler just once and
add it to one or more ChannelPipeline
s multiple times without
a race condition.
If this annotation is not specified, 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.
This annotation is provided for documentation purpose, just like the JCIP annotations.
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.
Modifier and Type | Interface and Description |
---|---|
static interface |
ChannelHandler.Sharable
Indicates that the same instance of the annotated
ChannelHandler
can be added to one or more ChannelPipeline s multiple times
without a race condition. |
static interface |
ChannelHandler.Skip
Indicates that the annotated event handler method in
ChannelHandler will not be invoked by
ChannelPipeline . |
Modifier and Type | Method and Description |
---|---|
void |
bind(ChannelHandlerContext ctx,
SocketAddress localAddress,
ChannelPromise promise)
Called once a bind operation is made.
|
void |
channelActive(ChannelHandlerContext ctx)
The
Channel of the ChannelHandlerContext is now active |
void |
channelInactive(ChannelHandlerContext ctx)
The
Channel of the ChannelHandlerContext was registered is now inactive and reached its
end of lifetime. |
void |
channelRead(ChannelHandlerContext ctx,
Object msg)
Invoked when the current
Channel has read a message from the peer. |
void |
channelReadComplete(ChannelHandlerContext ctx)
Invoked when the last message read by the current read operation has been consumed by
channelRead(ChannelHandlerContext, Object) . |
void |
channelRegistered(ChannelHandlerContext ctx)
|
void |
channelUnregistered(ChannelHandlerContext ctx)
|
void |
channelWritabilityChanged(ChannelHandlerContext ctx)
Gets called once the writable state of a
Channel changed. |
void |
close(ChannelHandlerContext ctx,
ChannelPromise promise)
Called once a close operation is made.
|
void |
connect(ChannelHandlerContext ctx,
SocketAddress remoteAddress,
SocketAddress localAddress,
ChannelPromise promise)
Called once a connect operation is made.
|
void |
deregister(ChannelHandlerContext ctx,
ChannelPromise promise)
Called once a deregister operation is made from the current registered
EventLoop . |
void |
disconnect(ChannelHandlerContext ctx,
ChannelPromise promise)
Called once a disconnect operation is made.
|
void |
exceptionCaught(ChannelHandlerContext ctx,
Throwable cause)
Gets called if a
Throwable was thrown. |
void |
flush(ChannelHandlerContext ctx)
Called once a flush operation is made.
|
void |
handlerAdded(ChannelHandlerContext ctx)
Gets called after the
ChannelHandler was added to the actual context and it's ready to handle events. |
void |
handlerRemoved(ChannelHandlerContext ctx)
Gets called after the
ChannelHandler was removed from the actual context and it doesn't handle events
anymore. |
void |
read(ChannelHandlerContext ctx)
Intercepts
ChannelHandlerContext.read() . |
void |
userEventTriggered(ChannelHandlerContext ctx,
Object evt)
Gets called if an user event was triggered.
|
void |
write(ChannelHandlerContext ctx,
Object msg,
ChannelPromise promise)
Called once a write operation is made.
|
void handlerAdded(ChannelHandlerContext ctx) throws Exception
ChannelHandler
was added to the actual context and it's ready to handle events.Exception
void handlerRemoved(ChannelHandlerContext ctx) throws Exception
ChannelHandler
was removed from the actual context and it doesn't handle events
anymore.Exception
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
Throwable
was thrown.Exception
void channelRegistered(ChannelHandlerContext ctx) throws Exception
Exception
void channelUnregistered(ChannelHandlerContext ctx) throws Exception
Exception
void channelActive(ChannelHandlerContext ctx) throws Exception
Channel
of the ChannelHandlerContext
is now activeException
void channelInactive(ChannelHandlerContext ctx) throws Exception
Channel
of the ChannelHandlerContext
was registered is now inactive and reached its
end of lifetime.Exception
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
Channel
has read a message from the peer.Exception
void channelReadComplete(ChannelHandlerContext ctx) throws Exception
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
ChannelHandlerContext.read()
is called.Exception
void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
Exception
void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception
Channel
changed. You can check the state with
Channel.isWritable()
.Exception
void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception
ctx
- the ChannelHandlerContext
for which the bind operation is madelocalAddress
- the SocketAddress
to which it should boundpromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception
ctx
- the ChannelHandlerContext
for which the connect operation is maderemoteAddress
- the SocketAddress
to which it should connectlocalAddress
- the SocketAddress
which is used as source on connectpromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception
ctx
- the ChannelHandlerContext
for which the disconnect operation is madepromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception
ctx
- the ChannelHandlerContext
for which the close operation is madepromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception
EventLoop
.ctx
- the ChannelHandlerContext
for which the close operation is madepromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid read(ChannelHandlerContext ctx) throws Exception
ChannelHandlerContext.read()
.Exception
void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
ChannelPipeline
. Those are then ready to be flushed to the actual Channel
once
Channel.flush()
is calledctx
- the ChannelHandlerContext
for which the write operation is mademsg
- the message to writepromise
- the ChannelPromise
to notify once the operation completesException
- thrown if an error accourvoid flush(ChannelHandlerContext ctx) throws Exception
ctx
- the ChannelHandlerContext
for which the flush operation is madeException
- thrown if an error accourCopyright © 2008–2015 The Netty Project. All rights reserved.