diff --git a/src/main/java/org/jboss/netty/channel/ChannelDownstreamHandler.java b/src/main/java/org/jboss/netty/channel/ChannelDownstreamHandler.java index 7b0efe2e87..0500f51080 100644 --- a/src/main/java/org/jboss/netty/channel/ChannelDownstreamHandler.java +++ b/src/main/java/org/jboss/netty/channel/ChannelDownstreamHandler.java @@ -24,6 +24,23 @@ package org.jboss.netty.channel; /** + * Handles or intercepts a downstream {@link ChannelEvent}, and fires a + * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. + *

+ * A downstream event is an event which is supposed to be processed from the + * last handler to the first handler in the {@link ChannelPipeline}. + * For example, all I/O requests made by a user application are downstream + * events. + *

+ * In most common use case of this interface is to intercept an I/O request + * such as {@link Channel#write(Object)} and {@link Channel#close()}. + * + *

Thread safety

+ *

+ * {@link #handleDownstream(ChannelHandlerContext, ChannelEvent) handleDownstream} + * may be invoked by more than one thread simultaneously. If the handler + * accesses a shared resource or stores stateful information, you might need + * proper synchronization in the handler implementation. * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) @@ -33,5 +50,12 @@ package org.jboss.netty.channel; * @apiviz.landmark */ public interface ChannelDownstreamHandler extends ChannelHandler { + + /** + * Handles the specified downstream event. + * + * @param ctx the context object for this handler + * @param e the downstream event to process or intercept + */ void handleDownstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; } diff --git a/src/main/java/org/jboss/netty/channel/ChannelHandler.java b/src/main/java/org/jboss/netty/channel/ChannelHandler.java index d80d99ed4d..25fdab1b90 100644 --- a/src/main/java/org/jboss/netty/channel/ChannelHandler.java +++ b/src/main/java/org/jboss/netty/channel/ChannelHandler.java @@ -23,6 +23,19 @@ package org.jboss.netty.channel; /** + * Handles or intercepts a {@link ChannelEvent}, and fires a new, modified, or + * existing {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. + *

+ * This is a tag interface. There are two sub-interfaces which processes + * a received event actually, one for upstream events and the other for + * downstream events: + *

* * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) diff --git a/src/main/java/org/jboss/netty/channel/ChannelUpstreamHandler.java b/src/main/java/org/jboss/netty/channel/ChannelUpstreamHandler.java index d772559b15..481f26569b 100644 --- a/src/main/java/org/jboss/netty/channel/ChannelUpstreamHandler.java +++ b/src/main/java/org/jboss/netty/channel/ChannelUpstreamHandler.java @@ -22,8 +22,56 @@ */ package org.jboss.netty.channel; +import java.util.concurrent.Executor; + +import org.jboss.netty.handler.execution.ExecutionHandler; +import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor; + /** + * Handles or intercepts a upstream {@link ChannelEvent}, and fires a + * {@link ChannelEvent} to the next handler in a {@link ChannelPipeline}. + *

+ * A upstream event is an event which is supposed to be processed from the + * first handler to the last handler in the {@link ChannelPipeline}. + * For example, all events fired by an I/O thread are upstream events. + *

+ * In most cases, you should use a {@link SimpleChannelHandler} to implement + * this interface more easily. You might want to implement this interface + * directly though, when you want to handle various types of events in more + * generic way. + * + * + *

Thread safety

+ *

+ * If there's no {@link ExecutionHandler} in the {@link ChannelPipeline}, + * {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} + * will be invoked sequentially by the same thread (i.e. an I/O thread). + * Please note that this doesn't necessarily mean that there's a dedicated + * thread per {@link Channel}; the I/O thread of some transport can serve more + * than one {@link Channel} (e.g. NIO transport), while the I/O thread of + * others can serve only one (e.g. OIO transport). + *

+ * If an {@link ExecutionHandler} is added in the {@link ChannelPipeline}, + * {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} + * may be invoked by different threads at the same time, depending on what + * {@link Executor} implementation is used with the {@link ExecutionHandler}. + *

+ * {@link OrderedMemoryAwareThreadPoolExecutor} is provided to guarantee the + * order of {@link ChannelEvent}s. It does not guarantee that the invocation + * will be made by the same thread for the same channel, but it does guarantee + * that the invocation will be made sequentially for the events of the same + * channel. For example, the events can be processed as depicted below: + * + *

+ *           -----------------------------------> Timeline ----------------------------------->
+ *
+ * Thread X: --- Channel A (Event 1) --.   .-- Channel B (Event 2) --- Channel B (Event 3) --->
+ *                                      \ /
+ *                                       X
+ *                                      / \
+ * Thread Y: --- Channel B (Event 1) --'   '-- Channel A (Event 2) --- Channel A (Event 3) --->
+ * 
* * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) @@ -33,5 +81,12 @@ package org.jboss.netty.channel; * @apiviz.landmark */ public interface ChannelUpstreamHandler extends ChannelHandler { + + /** + * Handles the specified upstream event. + * + * @param ctx the context object for this handler + * @param e the upstream event to process or intercept + */ void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception; } diff --git a/src/main/java/org/jboss/netty/channel/SimpleChannelHandler.java b/src/main/java/org/jboss/netty/channel/SimpleChannelHandler.java index 403e71ea80..93a0c3f439 100644 --- a/src/main/java/org/jboss/netty/channel/SimpleChannelHandler.java +++ b/src/main/java/org/jboss/netty/channel/SimpleChannelHandler.java @@ -22,11 +22,122 @@ */ package org.jboss.netty.channel; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.socket.ServerSocketChannel; import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; /** + * Generic {@link ChannelUpstreamHandler} implementation that satisfies most + * use cases. This handler down-casts the received upstream event into more + * meaningful sub-type event and calls an appropriate handler method with the + * down-casted event. The following table shows the provided handler methods: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Handler methodEvent typeInvoked when ...
{@link #messageReceived(ChannelHandlerContext, MessageEvent) messageReceived}{@link MessageEvent}a message object (e.g. {@link ChannelBuffer}) was received from a remote peer
{@link #exceptionCaught(ChannelHandlerContext, ExceptionEvent) exceptionCaught}{@link ExceptionEvent}an exception was raised by an I/O thread or a {@link ChannelHandler}
{@link #channelOpen(ChannelHandlerContext, ChannelStateEvent) channelOpen}{@link ChannelStateEvent}a {@link Channel} is open, but not bound nor connected
{@link #channelOpen(ChannelHandlerContext, ChannelStateEvent) channelOpen}{@link ChannelStateEvent}a {@link Channel} is open, but not bound nor connected
{@link #channelBound(ChannelHandlerContext, ChannelStateEvent) channelBound}{@link ChannelStateEvent}a {@link Channel} is open and bound to a local address, but not connected
{@link #channelConnected(ChannelHandlerContext, ChannelStateEvent) channelConnected}{@link ChannelStateEvent}a {@link Channel} is open, bound to a local address, and connected to a remote address
{@link #channelInterestChanged(ChannelHandlerContext, ChannelStateEvent) channelInterestedChanged}{@link ChannelStateEvent}a {@link Channel}'s {@link Channel#getInterestOps() interestOps} was changed
{@link #channelDisconnected(ChannelHandlerContext, ChannelStateEvent) channelDisconnected}{@link ChannelStateEvent}a {@link Channel} was disconnected from its remote peer
{@link #channelUnbound(ChannelHandlerContext, ChannelStateEvent) channelUnbound}{@link ChannelStateEvent}a {@link Channel} was unbound from the current local address
{@link #channelClosed(ChannelHandlerContext, ChannelStateEvent) channelClosed}{@link ChannelStateEvent}a {@link Channel} was closed and all its related resources were released
+ * + *

+ * These two handler methods are used only for a parent channel which can have + * a child channel (e.g. {@link ServerSocketChannel}). + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Handler methodEvent typeInvoked when ...
{@link #childChannelOpen(ChannelHandlerContext, ChildChannelStateEvent) childChannelOpen}{@link ChildChannelStateEvent}a child {@link Channel} was open (e.g. a server channel accepted a connection.)
{@link #childChannelClosed(ChannelHandlerContext, ChildChannelStateEvent) childChannelClosed}{@link ChildChannelStateEvent}a child {@link Channel} was closed (e.g. the accepted connection was closed.)
+ * + *

Overriding {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} method

+ *

+ * You can override the {@link #handleUpstream(ChannelHandlerContext, ChannelEvent) handleUpstream} + * method just like you can do with other {@link ChannelUpstreamHandler}s. + * However, please make sure that you call {@code super.handleUpstream()} so + * that other handler methods are invoked properly: + *

+ *
public class MyChannelHandler extends SimpleChannelHandler {
+ *
+ *     public void handleUpstream(
+ *             ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
+ *
+ *         // Log all channel state changes.
+ *         if (e instanceof ChannelStateEvent) {
+ *             logger.info("Channel state changed: " + e);
+ *         }
+ *
+ *         super.handleUpstream(ctx, e);
+ *     }
+ * }
+ * + *

Thread safety

+ *

+ * The same rule with {@link ChannelUpstreamHandler} is applied. Please refer + * to the 'thread safety' + * section. + * * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) @@ -38,6 +149,11 @@ public class SimpleChannelHandler implements ChannelUpstreamHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(SimpleChannelHandler.class.getName()); + /** + * {@inheritDoc} Down-casts the received upstream event into more + * meaningful sub-type event and calls an appropriate handler method with + * the down-casted event. + */ public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { @@ -85,46 +201,19 @@ public class SimpleChannelHandler implements ChannelUpstreamHandler { } } - public void channelBound( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelClosed( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelConnected( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelInterestChanged( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelDisconnected( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelOpen( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - - public void channelUnbound( - ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - ctx.sendUpstream(e); - } - + /** + * Invoked when a message object (e.g. {@link ChannelBuffer}) was received + * from a remote peer. + */ public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.sendUpstream(e); } + /** + * Invoked when an exception was raised by an I/O thread or a + * {@link ChannelHandler}. + */ public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { if (this == ctx.getPipeline().getLast()) { @@ -135,13 +224,81 @@ public class SimpleChannelHandler implements ChannelUpstreamHandler { ctx.sendUpstream(e); } - public void childChannelClosed( - ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { + /** + * Invoked when a {@link Channel} is open, but not bound nor connected. + */ + public void channelOpen( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } + /** + * Invoked when a {@link Channel} is open and bound to a local address, + * but not connected. + */ + public void channelBound( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a {@link Channel} is open, bound to a local address, and + * connected to a remote address. + */ + public void channelConnected( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a {@link Channel}'s {@link Channel#getInterestOps() interestOps} + * was changed. + */ + public void channelInterestChanged( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a {@link Channel} was disconnected from its remote peer. + */ + public void channelDisconnected( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a {@link Channel} was unbound from the current local address. + */ + public void channelUnbound( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a {@link Channel} was closed and all its related resources + * were released. + */ + public void channelClosed( + ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } + + /** + * Invoked when a child {@link Channel} was open. + * (e.g. a server channel accepted a connection) + */ public void childChannelOpen( ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { ctx.sendUpstream(e); } + + /** + * Invoked when a child {@link Channel} was closed. + * (e.g. the accepted connection was closed) + */ + public void childChannelClosed( + ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception { + ctx.sendUpstream(e); + } }