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);
}