From 93f76ce594cb2953f22d072190537f0bd32eeccd Mon Sep 17 00:00:00 2001 From: Trustin Lee Date: Tue, 12 Aug 2008 11:58:15 +0000 Subject: [PATCH] * More comments on examples * Added JavaDoc for ChannelPipelineCoverage which is somewhat difficult to understand. --- .../channel/ChannelPipelineCoverage.java | 36 +++++++++++++++++++ .../netty/example/discard/DiscardClient.java | 3 +- .../example/discard/DiscardClientHandler.java | 5 +++ .../netty/example/discard/DiscardServer.java | 3 +- .../example/discard/DiscardServerHandler.java | 1 + .../example/discard/ThroughputMonitor.java | 12 +++++-- .../jboss/netty/example/echo/EchoClient.java | 13 ++++++- .../jboss/netty/example/echo/EchoHandler.java | 25 +++++++++++-- .../jboss/netty/example/echo/EchoServer.java | 12 ++++++- .../netty/example/echo/ThroughputMonitor.java | 18 +++++++--- .../example/factorial/BigIntegerDecoder.java | 9 ++++- .../example/factorial/FactorialClient.java | 9 +++++ .../factorial/FactorialClientHandler.java | 17 ++++++++- .../FactorialClientPipelineFactory.java | 3 +- .../factorial/FactorialProtocolException.java | 3 +- .../example/factorial/FactorialServer.java | 12 ++++++- .../factorial/FactorialServerHandler.java | 17 ++++++++- .../FactorialServerPipelineFactory.java | 4 +++ .../example/factorial/NumberEncoder.java | 3 ++ .../example/objectecho/ObjectEchoClient.java | 12 ++++++- .../example/objectecho/ObjectEchoHandler.java | 23 ++++++++++-- .../example/objectecho/ObjectEchoServer.java | 12 ++++++- .../example/objectecho/ThroughputMonitor.java | 18 +++++++--- .../example/securechat/SecureChatClient.java | 15 +++++++- .../securechat/SecureChatClientHandler.java | 14 ++++++-- .../securechat/SecureChatKeyStore.java | 4 ++- .../securechat/SecureChatPipelineFactory.java | 5 +++ .../example/securechat/SecureChatServer.java | 12 ++++++- .../securechat/SecureChatServerHandler.java | 11 +++++- .../SecureChatSslContextFactory.java | 7 +++- .../SecureChatTrustManagerFactory.java | 4 ++- .../netty/example/telnet/TelnetClient.java | 15 +++++++- .../example/telnet/TelnetClientHandler.java | 9 +++++ .../example/telnet/TelnetPipelineFactory.java | 5 ++- .../netty/example/telnet/TelnetServer.java | 11 +++++- .../example/telnet/TelnetServerHandler.java | 16 +++++++-- 36 files changed, 357 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/jboss/netty/channel/ChannelPipelineCoverage.java b/src/main/java/org/jboss/netty/channel/ChannelPipelineCoverage.java index 4f30f88092..574e3563f5 100644 --- a/src/main/java/org/jboss/netty/channel/ChannelPipelineCoverage.java +++ b/src/main/java/org/jboss/netty/channel/ChannelPipelineCoverage.java @@ -30,6 +30,31 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** + * Specifies if the same instance of the annotated {@link ChannelHandler} type + * can be added to more than one {@link ChannelPipeline}. + *

+ * All handler types are expected to specify this annotation. Otherwise you + * will be warned in runtime. Only two values are allowed for this annotation: + * {@code "all"} and {@code "one"}. + *

+ * Please note that this annotation doesn't prevent a handler annotated with + * the value {@code "one"} from being added to more than one pipeline. This + * annotation is used for documentation purpose only. + * + *

{@code ChannelPipelineCoverage("all")}

+ * + * {@code "all"} means you can add the same instance of the annotated handler + * type to more than one {@link ChannelPipeline}. It means the member + * variables of the handler instance is shared among multiple channels and it + * is OK to do so. + * + *

{@code ChannelPipelineCoverage("one")}

+ * + * {@code "one"} means you must create a new instance of the annotated handler + * type for each new channel. It means the member variables of the handler + * instance can not be shared at all, and violating this contract will lead + * the handler to a race condition. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @@ -42,8 +67,19 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ChannelPipelineCoverage { + + /** + * {@code "all"} + */ public static final String ALL = "all"; + + /** + * {@code "one"} + */ public static final String ONE = "one"; + /** + * The value of this annotation + */ String value(); } diff --git a/src/main/java/org/jboss/netty/example/discard/DiscardClient.java b/src/main/java/org/jboss/netty/example/discard/DiscardClient.java index a63e665511..d4defc27c8 100644 --- a/src/main/java/org/jboss/netty/example/discard/DiscardClient.java +++ b/src/main/java/org/jboss/netty/example/discard/DiscardClient.java @@ -59,7 +59,7 @@ public class DiscardClient { firstMessageSize = 256; } - // Start client. + // Configure the client. ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), @@ -72,6 +72,7 @@ public class DiscardClient { bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); + // Start the connection attempt. bootstrap.connect(new InetSocketAddress(host, port)); } } diff --git a/src/main/java/org/jboss/netty/example/discard/DiscardClientHandler.java b/src/main/java/org/jboss/netty/example/discard/DiscardClientHandler.java index ef52c64d6e..12876ea6ae 100644 --- a/src/main/java/org/jboss/netty/example/discard/DiscardClientHandler.java +++ b/src/main/java/org/jboss/netty/example/discard/DiscardClientHandler.java @@ -39,6 +39,7 @@ import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** + * Handles a client-side channel. * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) @@ -106,6 +107,10 @@ public class DiscardClientHandler extends SimpleChannelHandler { } private void generateTraffic(ChannelStateEvent e) { + // Keep generating traffic until the channel is unwritable. + // A channel becomes unwritable when its internal buffer is full. + // If you keep writing messages ignoring this property, + // you will end up with an OutOfMemoryError. Channel channel = e.getChannel(); while (channel.isWritable()) { ChannelBuffer m = nextMessage(); diff --git a/src/main/java/org/jboss/netty/example/discard/DiscardServer.java b/src/main/java/org/jboss/netty/example/discard/DiscardServer.java index 6928d15ca9..205c67d172 100644 --- a/src/main/java/org/jboss/netty/example/discard/DiscardServer.java +++ b/src/main/java/org/jboss/netty/example/discard/DiscardServer.java @@ -40,7 +40,7 @@ import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; public class DiscardServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -53,6 +53,7 @@ public class DiscardServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); // Start performance monitor. diff --git a/src/main/java/org/jboss/netty/example/discard/DiscardServerHandler.java b/src/main/java/org/jboss/netty/example/discard/DiscardServerHandler.java index 378e277e2d..33018761ea 100644 --- a/src/main/java/org/jboss/netty/example/discard/DiscardServerHandler.java +++ b/src/main/java/org/jboss/netty/example/discard/DiscardServerHandler.java @@ -36,6 +36,7 @@ import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** + * Handles a server-side channel. * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) diff --git a/src/main/java/org/jboss/netty/example/discard/ThroughputMonitor.java b/src/main/java/org/jboss/netty/example/discard/ThroughputMonitor.java index 618d2ee858..199b30d1dc 100644 --- a/src/main/java/org/jboss/netty/example/discard/ThroughputMonitor.java +++ b/src/main/java/org/jboss/netty/example/discard/ThroughputMonitor.java @@ -22,12 +22,20 @@ */ package org.jboss.netty.example.discard; +/** + * Measures and prints the current throughput every 3 seconds. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class ThroughputMonitor extends Thread { private final DiscardServerHandler handler; - public ThroughputMonitor(DiscardServerHandler echoHandler) { - this.handler = echoHandler; + public ThroughputMonitor(DiscardServerHandler handler) { + this.handler = handler; } @Override diff --git a/src/main/java/org/jboss/netty/example/echo/EchoClient.java b/src/main/java/org/jboss/netty/example/echo/EchoClient.java index 30cfb18ccf..cbeefd9cd3 100644 --- a/src/main/java/org/jboss/netty/example/echo/EchoClient.java +++ b/src/main/java/org/jboss/netty/example/echo/EchoClient.java @@ -29,6 +29,16 @@ import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +/** + * Sends one message when a connection is open and echoes back any received + * data to the server. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + * + */ public class EchoClient { public static void main(String[] args) throws Exception { @@ -51,7 +61,7 @@ public class EchoClient { firstMessageSize = 256; } - // Start client. + // Configure the client. ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), @@ -64,6 +74,7 @@ public class EchoClient { bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); + // Start the connection attempt. bootstrap.connect(new InetSocketAddress(host, port)); // Start performance monitor. diff --git a/src/main/java/org/jboss/netty/example/echo/EchoHandler.java b/src/main/java/org/jboss/netty/example/echo/EchoHandler.java index 2bf2728b0a..d637ee3426 100644 --- a/src/main/java/org/jboss/netty/example/echo/EchoHandler.java +++ b/src/main/java/org/jboss/netty/example/echo/EchoHandler.java @@ -36,6 +36,15 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; +/** + * Handles both client-side and server-side handler depending on which + * constructor was called. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class EchoHandler extends SimpleChannelHandler { @@ -45,12 +54,18 @@ public class EchoHandler extends SimpleChannelHandler { private final ChannelBuffer firstMessage; private final AtomicLong transferredBytes = new AtomicLong(); + /** + * Creates a server-side handler. + */ public EchoHandler() { - this(0); + firstMessage = ChannelBuffer.EMPTY_BUFFER; } + /** + * Creates a client-side handler. + */ public EchoHandler(int firstMessageSize) { - if (firstMessageSize < 0) { + if (firstMessageSize <= 0) { throw new IllegalArgumentException( "firstMessageSize: " + firstMessageSize); } @@ -70,18 +85,23 @@ public class EchoHandler extends SimpleChannelHandler { if (e instanceof ChannelStateEvent) { logger.info(e.toString()); } + + // Let SimpleChannelHandler call actual event handler methods below. super.handleUpstream(ctx, e); } @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) { + // Send the first message. Server will not send anything here + // because the firstMessage's capacity is 0. e.getChannel().write(firstMessage); } @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { + // Send back the received message to the remote peer. transferredBytes.addAndGet(((ChannelBuffer) e.getMessage()).readableBytes()); e.getChannel().write(e.getMessage()); } @@ -89,6 +109,7 @@ public class EchoHandler extends SimpleChannelHandler { @Override public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e) { + // Close the connection when an exception is raised. logger.log( Level.WARNING, "Unexpected exception from downstream.", diff --git a/src/main/java/org/jboss/netty/example/echo/EchoServer.java b/src/main/java/org/jboss/netty/example/echo/EchoServer.java index bd04abc3ce..1eee81d412 100644 --- a/src/main/java/org/jboss/netty/example/echo/EchoServer.java +++ b/src/main/java/org/jboss/netty/example/echo/EchoServer.java @@ -29,10 +29,19 @@ import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +/** + * Echoes back any received data from a client. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + * + */ public class EchoServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -45,6 +54,7 @@ public class EchoServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); // Start performance monitor. diff --git a/src/main/java/org/jboss/netty/example/echo/ThroughputMonitor.java b/src/main/java/org/jboss/netty/example/echo/ThroughputMonitor.java index c484a76bd3..a177edfbee 100644 --- a/src/main/java/org/jboss/netty/example/echo/ThroughputMonitor.java +++ b/src/main/java/org/jboss/netty/example/echo/ThroughputMonitor.java @@ -22,17 +22,25 @@ */ package org.jboss.netty.example.echo; +/** + * Measures and prints the current throughput every 3 seconds. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class ThroughputMonitor extends Thread { - private final EchoHandler echoHandler; + private final EchoHandler handler; - public ThroughputMonitor(EchoHandler echoHandler) { - this.echoHandler = echoHandler; + public ThroughputMonitor(EchoHandler handler) { + this.handler = handler; } @Override public void run() { - long oldCounter = echoHandler.getTransferredBytes(); + long oldCounter = handler.getTransferredBytes(); long startTime = System.currentTimeMillis(); for (;;) { try { @@ -42,7 +50,7 @@ public class ThroughputMonitor extends Thread { } long endTime = System.currentTimeMillis(); - long newCounter = echoHandler.getTransferredBytes(); + long newCounter = handler.getTransferredBytes(); System.err.format( "%4.3f MiB/s%n", (newCounter - oldCounter) * 1000 / (endTime - startTime) / diff --git a/src/main/java/org/jboss/netty/example/factorial/BigIntegerDecoder.java b/src/main/java/org/jboss/netty/example/factorial/BigIntegerDecoder.java index 0fcc859b5a..90efdb068b 100644 --- a/src/main/java/org/jboss/netty/example/factorial/BigIntegerDecoder.java +++ b/src/main/java/org/jboss/netty/example/factorial/BigIntegerDecoder.java @@ -30,28 +30,35 @@ import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.handler.codec.frame.FrameDecoder; /** + * Decodes the binary representation of a {@link BigInteger} with 32-bit + * integer length prefix into a Java {@link BigInteger} instance. For example, + * { 0, 0, 0, 1, 42 } will be decoded into new BigInteger("42"). + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class BigIntegerDecoder extends FrameDecoder { @Override protected Object decode( ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception { + // Wait until the length prefix is available. if (buffer.readableBytes() < 4) { return null; } int dataLength = buffer.getInt(buffer.readerIndex()); + // Wait until the whole data is available. if (buffer.readableBytes() < dataLength + 4) { return null; } + // Skip the length field because we know it already. buffer.skipBytes(4); + // Convert the received data into a new BigInteger. byte[] decoded = new byte[dataLength]; buffer.readBytes(decoded); diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialClient.java b/src/main/java/org/jboss/netty/example/factorial/FactorialClient.java index 7609713168..d32f60a4c2 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialClient.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialClient.java @@ -30,6 +30,15 @@ import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +/** + * Sends a sequence of integers to a {@link FactorialServer} to calculate + * the factorial of the specified integer. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class FactorialClient { public static void main(String[] args) throws Exception { diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialClientHandler.java b/src/main/java/org/jboss/netty/example/factorial/FactorialClientHandler.java index 5bf11b9f58..14779e297e 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialClientHandler.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialClientHandler.java @@ -39,12 +39,27 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; -@ChannelPipelineCoverage("one") +/** + * Handler for a client-side channel. Please note that this handler's + * {@link ChannelPipelineCoverage} annotation value is "one". It means + * this handler maintains some stateful information which is specific to + * a certain channel. Therefore, an instance of this handler can + * cover only one ChannelPipeline and Channel pair. You have to create + * a new handler instance whenever you create a new channel and insert + * this handler to avoid a race condition. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ +@ChannelPipelineCoverage("one") // <-- HERE public class FactorialClientHandler extends SimpleChannelHandler { private static final Logger logger = Logger.getLogger( FactorialClientHandler.class.getName()); + // Stateful properties private int i = 1; private int receivedMessages = 0; private final int count; diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialClientPipelineFactory.java b/src/main/java/org/jboss/netty/example/factorial/FactorialClientPipelineFactory.java index 53db935185..006af7e9a6 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialClientPipelineFactory.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialClientPipelineFactory.java @@ -28,11 +28,12 @@ import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; /** + * Creates a newly configured {@link ChannelPipeline} for a client-side channel. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class FactorialClientPipelineFactory implements ChannelPipelineFactory { diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialProtocolException.java b/src/main/java/org/jboss/netty/example/factorial/FactorialProtocolException.java index 2aacf7fb42..dfea5fde55 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialProtocolException.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialProtocolException.java @@ -23,11 +23,12 @@ package org.jboss.netty.example.factorial; /** + * Thrown when there was a protocol violation during communication. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class FactorialProtocolException extends Exception { diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialServer.java b/src/main/java/org/jboss/netty/example/factorial/FactorialServer.java index d756273b71..5a1a12719b 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialServer.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialServer.java @@ -29,10 +29,19 @@ import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +/** + * Receives a sequence of integers from a {@link FactorialClient} to calculate + * the factorial of the specified integer. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class FactorialServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -44,6 +53,7 @@ public class FactorialServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); } } diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialServerHandler.java b/src/main/java/org/jboss/netty/example/factorial/FactorialServerHandler.java index 2bdf7cf9fb..ad246f9047 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialServerHandler.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialServerHandler.java @@ -35,12 +35,27 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; -@ChannelPipelineCoverage("one") +/** + * Handler for a server-side channel. Please note that this handler's + * {@link ChannelPipelineCoverage} annotation value is "one". It means + * this handler maintains some stateful information which is specific to + * a certain channel. Therefore, an instance of this handler can + * cover only one ChannelPipeline and Channel pair. You have to create + * a new handler instance whenever you create a new channel and insert + * this handler to avoid a race condition. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ +@ChannelPipelineCoverage("one") // <-- HERE public class FactorialServerHandler extends SimpleChannelHandler { private static final Logger logger = Logger.getLogger( FactorialServerHandler.class.getName()); + // Stateful properties. private int lastMultiplier = 1; private BigInteger factorial = new BigInteger(new byte[] { 1 }); diff --git a/src/main/java/org/jboss/netty/example/factorial/FactorialServerPipelineFactory.java b/src/main/java/org/jboss/netty/example/factorial/FactorialServerPipelineFactory.java index 2d23203c37..c38423e087 100644 --- a/src/main/java/org/jboss/netty/example/factorial/FactorialServerPipelineFactory.java +++ b/src/main/java/org/jboss/netty/example/factorial/FactorialServerPipelineFactory.java @@ -28,6 +28,8 @@ import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; /** + * Creates a newly configured {@link ChannelPipeline} for a server-side channel. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @@ -45,6 +47,8 @@ public class FactorialServerPipelineFactory implements pipeline.addLast("encoder", new NumberEncoder()); // and then business logic. + // Please note we create a handler for every new channel + // because it has stateful properties. pipeline.addLast("handler", new FactorialServerHandler()); return pipeline; diff --git a/src/main/java/org/jboss/netty/example/factorial/NumberEncoder.java b/src/main/java/org/jboss/netty/example/factorial/NumberEncoder.java index aa8d671f93..df97c0e65c 100644 --- a/src/main/java/org/jboss/netty/example/factorial/NumberEncoder.java +++ b/src/main/java/org/jboss/netty/example/factorial/NumberEncoder.java @@ -35,6 +35,9 @@ import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.MessageEvent; /** + * Encodes a {@link Number} into the binary representation with a 32-bit length + * prefix. For example, 42 will be encoded to { 0, 0, 0, 1, 42 }. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * diff --git a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoClient.java b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoClient.java index 62be25bc17..cf8aea53b6 100644 --- a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoClient.java +++ b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoClient.java @@ -28,7 +28,16 @@ import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.example.echo.EchoClient; +/** + * Modification of {@link EchoClient} which utilizes Java object serialization. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class ObjectEchoClient { public static void main(String[] args) throws Exception { @@ -51,7 +60,7 @@ public class ObjectEchoClient { firstMessageSize = 256; } - // Start client. + // Configure the client. ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), @@ -64,6 +73,7 @@ public class ObjectEchoClient { bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); + // Start the connection attempt. bootstrap.connect(new InetSocketAddress(host, port)); // Start performance monitor. diff --git a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoHandler.java b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoHandler.java index 6129928c50..27be5bb115 100644 --- a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoHandler.java +++ b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoHandler.java @@ -39,6 +39,15 @@ import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder; +/** + * Handles both client-side and server-side handler depending on which + * constructor was called. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class ObjectEchoHandler extends SimpleChannelHandler { @@ -48,12 +57,18 @@ public class ObjectEchoHandler extends SimpleChannelHandler { private final List firstMessage; private final AtomicLong transferredMessages = new AtomicLong(); + /** + * Creates a server-side handler. + */ public ObjectEchoHandler() { - this(0); + firstMessage = new ArrayList(); } + /** + * Creates a client-side handler. + */ public ObjectEchoHandler(int firstMessageSize) { - if (firstMessageSize < 0) { + if (firstMessageSize <= 0) { throw new IllegalArgumentException( "firstMessageSize: " + firstMessageSize); } @@ -80,6 +95,8 @@ public class ObjectEchoHandler extends SimpleChannelHandler { @Override public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + // Add encoder and decoder as soon as a new channel is created so that + // a Java object is serialized and deserialized. e.getChannel().getPipeline().addFirst("encoder", new ObjectEncoder()); e.getChannel().getPipeline().addFirst("decoder", new ObjectDecoder()); } @@ -87,6 +104,7 @@ public class ObjectEchoHandler extends SimpleChannelHandler { @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) { + // Send the first message if this handler is a client-side handler. if (!firstMessage.isEmpty()) { e.getChannel().write(firstMessage); } @@ -95,6 +113,7 @@ public class ObjectEchoHandler extends SimpleChannelHandler { @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { + // Echo back the received object to the client. transferredMessages.incrementAndGet(); e.getChannel().write(e.getMessage()); } diff --git a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoServer.java b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoServer.java index 07cfc95038..656954f933 100644 --- a/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoServer.java +++ b/src/main/java/org/jboss/netty/example/objectecho/ObjectEchoServer.java @@ -28,11 +28,20 @@ import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +import org.jboss.netty.example.echo.EchoServer; +/** + * Modification of {@link EchoServer} which utilizes Java object serialization. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class ObjectEchoServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -45,6 +54,7 @@ public class ObjectEchoServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); // Start performance monitor. diff --git a/src/main/java/org/jboss/netty/example/objectecho/ThroughputMonitor.java b/src/main/java/org/jboss/netty/example/objectecho/ThroughputMonitor.java index 1404421128..1a8baaebd9 100644 --- a/src/main/java/org/jboss/netty/example/objectecho/ThroughputMonitor.java +++ b/src/main/java/org/jboss/netty/example/objectecho/ThroughputMonitor.java @@ -22,17 +22,25 @@ */ package org.jboss.netty.example.objectecho; +/** + * Measures and prints the current throughput every 3 seconds. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class ThroughputMonitor extends Thread { - private final ObjectEchoHandler echoHandler; + private final ObjectEchoHandler handler; - public ThroughputMonitor(ObjectEchoHandler echoHandler) { - this.echoHandler = echoHandler; + public ThroughputMonitor(ObjectEchoHandler handler) { + this.handler = handler; } @Override public void run() { - long oldCounter = echoHandler.getTransferredMessages(); + long oldCounter = handler.getTransferredMessages(); long startTime = System.currentTimeMillis(); for (;;) { try { @@ -42,7 +50,7 @@ public class ThroughputMonitor extends Thread { } long endTime = System.currentTimeMillis(); - long newCounter = echoHandler.getTransferredMessages(); + long newCounter = handler.getTransferredMessages(); System.err.format( "%4.3f msgs/s%n", (newCounter - oldCounter) * 1000 / (double) (endTime - startTime)); diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatClient.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatClient.java index 5b0e428415..4f95b6568c 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatClient.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatClient.java @@ -32,7 +32,17 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.example.telnet.TelnetClient; +/** + * Simple SSL chat client modified from {@link TelnetClient}. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + * + */ public class SecureChatClient { public static void main(String[] args) throws Exception { @@ -48,7 +58,7 @@ public class SecureChatClient { String host = args[0]; int port = Integer.parseInt(args[1]); - // Start client. + // Configure the client. ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), @@ -61,6 +71,7 @@ public class SecureChatClient { bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); + // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. @@ -86,6 +97,8 @@ public class SecureChatClient { lastWriteFuture.awaitUninterruptibly(); } + // Close the connection. Make sure the close operation ends because + // all I/O operations are asynchronous in Netty. channel.close().awaitUninterruptibly(); // We should shut down all thread pools here to exit normally. diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatClientHandler.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatClientHandler.java index 075d9d83db..899b13e715 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatClientHandler.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatClientHandler.java @@ -34,6 +34,14 @@ import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.ssl.SslHandler; +/** + * Handles a client-side channel. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class SecureChatClientHandler extends SimpleChannelHandler { @@ -52,9 +60,11 @@ public class SecureChatClientHandler extends SimpleChannelHandler { @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - - // Get the SslHandler and begin handshake ASAP. + // Get the SslHandler from the pipeline + // which were added in SecureChatPipelineFactory. SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); + + // Begin handshake. sslHandler.handshake(e.getChannel()); } diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatKeyStore.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatKeyStore.java index c9a0e3c747..957c747f2f 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatKeyStore.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatKeyStore.java @@ -26,11 +26,13 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; /** + * A bogus key store which provides all the required information to + * create an example SSL connection. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class SecureChatKeyStore { private static final short[] DATA = new short[] { diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatPipelineFactory.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatPipelineFactory.java index c459d3da5d..9ade1b6af0 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatPipelineFactory.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatPipelineFactory.java @@ -36,6 +36,8 @@ import org.jboss.netty.handler.codec.string.StringEncoder; import org.jboss.netty.handler.ssl.SslHandler; /** + * Creates a newly configured {@link ChannelPipeline} for a new channel. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @@ -55,8 +57,11 @@ public class SecureChatPipelineFactory implements ChannelPipeline pipeline = pipeline(); // Add SSL handler first to encrypt and decrypt everything. + // In this example, we use a bogus certificate in the server side + // and accept any invalid certificates in the client side. // You will need something more complicated to identify both // and server in the real world. + SSLEngine engine; if (handler instanceof SecureChatClientHandler) { engine = SecureChatSslContextFactory.getClientContext().createSSLEngine(); diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatServer.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatServer.java index 4d1c69665b..0ee189cb94 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatServer.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatServer.java @@ -28,11 +28,20 @@ import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +import org.jboss.netty.example.telnet.TelnetServer; +/** + * Simple SSL chat server modified from {@link TelnetServer}. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class SecureChatServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -45,6 +54,7 @@ public class SecureChatServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); } } diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatServerHandler.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatServerHandler.java index 91dd6d29ec..fcb3289fa5 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatServerHandler.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatServerHandler.java @@ -41,6 +41,14 @@ import org.jboss.netty.channel.SimpleChannelHandler; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.util.MapBackedSet; +/** + * Handles a server-side channel. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class SecureChatServerHandler extends SimpleChannelHandler { @@ -64,6 +72,7 @@ public class SecureChatServerHandler extends SimpleChannelHandler { ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { // Get the SslHandler in the current pipeline. + // We added it in SecureChatPipelineFactory. final SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); // Get notified when SSL handshake is done. @@ -113,7 +122,7 @@ public class SecureChatServerHandler extends SimpleChannelHandler { } } - // Close the connection if the client sent 'bye'. + // Close the connection if the client has sent 'bye'. if (request.toLowerCase().equals("bye")) { e.getChannel().close(); } diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatSslContextFactory.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatSslContextFactory.java index 521347b969..f81ba85a67 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatSslContextFactory.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatSslContextFactory.java @@ -29,11 +29,16 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; /** + * Creates a bogus {@link SSLContext}. A client-side context created by this + * factory accepts any certificate even if it's invalid. A server-side context + * created by this factory sends a bogus certificate defined in {@link SecureChatKeyStore}. + * + * You will have to create your context differently in a real world application. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class SecureChatSslContextFactory { diff --git a/src/main/java/org/jboss/netty/example/securechat/SecureChatTrustManagerFactory.java b/src/main/java/org/jboss/netty/example/securechat/SecureChatTrustManagerFactory.java index 790a552252..a17d2695e1 100644 --- a/src/main/java/org/jboss/netty/example/securechat/SecureChatTrustManagerFactory.java +++ b/src/main/java/org/jboss/netty/example/securechat/SecureChatTrustManagerFactory.java @@ -34,11 +34,13 @@ import javax.net.ssl.TrustManagerFactorySpi; import javax.net.ssl.X509TrustManager; /** + * Bogus {@link TrustManagerFactorySpi} which accepts any certificate + * even if it's invalid. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * * @version $Rev$, $Date$ - * */ public class SecureChatTrustManagerFactory extends TrustManagerFactorySpi { diff --git a/src/main/java/org/jboss/netty/example/telnet/TelnetClient.java b/src/main/java/org/jboss/netty/example/telnet/TelnetClient.java index 96ae62a254..01cf881ce4 100644 --- a/src/main/java/org/jboss/netty/example/telnet/TelnetClient.java +++ b/src/main/java/org/jboss/netty/example/telnet/TelnetClient.java @@ -33,6 +33,14 @@ import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +/** + * Simplistic telnet client. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class TelnetClient { public static void main(String[] args) throws Exception { @@ -48,7 +56,7 @@ public class TelnetClient { String host = args[0]; int port = Integer.parseInt(args[1]); - // Start client. + // Configure the client. ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(), @@ -61,6 +69,7 @@ public class TelnetClient { bootstrap.setOption("tcpNoDelay", true); bootstrap.setOption("keepAlive", true); + // Start the connection attempt. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port)); // Wait until the connection attempt succeeds or fails. @@ -78,6 +87,8 @@ public class TelnetClient { if (line == null) { break; } + + // Sends the received line to the server. lastWriteFuture = channel.write(line + '\n'); } @@ -86,6 +97,8 @@ public class TelnetClient { lastWriteFuture.awaitUninterruptibly(); } + // Close the connection. Make sure the close operation ends because + // all I/O operations are asynchronous in Netty. channel.close().awaitUninterruptibly(); // We should shut down all thread pools here to exit normally. diff --git a/src/main/java/org/jboss/netty/example/telnet/TelnetClientHandler.java b/src/main/java/org/jboss/netty/example/telnet/TelnetClientHandler.java index 00f5fdac73..fe072afd10 100644 --- a/src/main/java/org/jboss/netty/example/telnet/TelnetClientHandler.java +++ b/src/main/java/org/jboss/netty/example/telnet/TelnetClientHandler.java @@ -33,6 +33,14 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; +/** + * Handles a client-side channel. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class TelnetClientHandler extends SimpleChannelHandler { @@ -51,6 +59,7 @@ public class TelnetClientHandler extends SimpleChannelHandler { @Override public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { + // Print out the line received from the server. System.err.println(e.getMessage()); } diff --git a/src/main/java/org/jboss/netty/example/telnet/TelnetPipelineFactory.java b/src/main/java/org/jboss/netty/example/telnet/TelnetPipelineFactory.java index a9e0a5355f..f05cd8f7de 100644 --- a/src/main/java/org/jboss/netty/example/telnet/TelnetPipelineFactory.java +++ b/src/main/java/org/jboss/netty/example/telnet/TelnetPipelineFactory.java @@ -33,6 +33,8 @@ import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /** + * Creates a newly configured {@link ChannelPipeline} for a new channel. + * * @author The Netty Project (netty-dev@lists.jboss.org) * @author Trustin Lee (tlee@redhat.com) * @@ -49,9 +51,10 @@ public class TelnetPipelineFactory implements } public ChannelPipeline getPipeline() throws Exception { + // Create a default pipeline implementation. ChannelPipeline pipeline = pipeline(); - // Add the text line codec first, + // Add the text line codec combination first, pipeline.addLast("framer", new DelimiterBasedFrameDecoder( 8192, Delimiters.lineDelimiter())); pipeline.addLast("decoder", new StringDecoder()); diff --git a/src/main/java/org/jboss/netty/example/telnet/TelnetServer.java b/src/main/java/org/jboss/netty/example/telnet/TelnetServer.java index 81fe8702ec..5a0d302e9a 100644 --- a/src/main/java/org/jboss/netty/example/telnet/TelnetServer.java +++ b/src/main/java/org/jboss/netty/example/telnet/TelnetServer.java @@ -29,10 +29,18 @@ import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +/** + * Simplistic telnet server. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ public class TelnetServer { public static void main(String[] args) throws Exception { - // Start server. + // Configure the server. ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(), @@ -45,6 +53,7 @@ public class TelnetServer { bootstrap.setOption("child.tcpNoDelay", true); bootstrap.setOption("child.keepAlive", true); + // Bind and start to accept incoming connections. bootstrap.bind(new InetSocketAddress(8080)); } } diff --git a/src/main/java/org/jboss/netty/example/telnet/TelnetServerHandler.java b/src/main/java/org/jboss/netty/example/telnet/TelnetServerHandler.java index 15a77f9ade..42bb51c728 100644 --- a/src/main/java/org/jboss/netty/example/telnet/TelnetServerHandler.java +++ b/src/main/java/org/jboss/netty/example/telnet/TelnetServerHandler.java @@ -37,6 +37,14 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; +/** + * Handles a server-side channel. + * + * @author The Netty Project (netty-dev@lists.jboss.org) + * @author Trustin Lee (tlee@redhat.com) + * + * @version $Rev$, $Date$ + */ @ChannelPipelineCoverage("all") public class TelnetServerHandler extends SimpleChannelHandler { @@ -55,7 +63,7 @@ public class TelnetServerHandler extends SimpleChannelHandler { @Override public void channelConnected( ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - // Send greeting. + // Send greeting for a new connection. e.getChannel().write( "Welcome to " + InetAddress.getLocalHost().getHostName() + "!\n"); e.getChannel().write("It's " + new Date() + " now.\n"); @@ -65,7 +73,8 @@ public class TelnetServerHandler extends SimpleChannelHandler { public void messageReceived( ChannelHandlerContext ctx, MessageEvent e) { - // Convert to a String first. + // Cast to a String first. + // We know it's a String because we put some codec in TelnetPipelineFactory. String request = (String) e.getMessage(); // Generate and write a response. @@ -80,9 +89,12 @@ public class TelnetServerHandler extends SimpleChannelHandler { response = "Did you say '" + request + "'?\n"; } + // We don't need to write a ChannelBuffer here. + // We know the encoder inserted at TelnetPipelineFactory will do the conversion. ChannelFuture future = e.getChannel().write(response); // Close the connection after sending 'Have a good day!' + // if the client has sent 'bye'. if (close) { future.addListener(ChannelFutureListener.CLOSE); }