Removed the reference to ChannelPipelineCoverage in the getting started guide. Beginners should simply start from creating a new instance for every new connection, as shown in the guide and all examples which were revised to avoid confusion.

Shared instances are more advanced topic, which will be addressed in another chapter.
This commit is contained in:
Trustin Lee 2010-02-01 23:56:37 +00:00
parent 901b1f099a
commit 2f7c758fe6

View File

@ -73,15 +73,14 @@
</para> </para>
<programlisting>package org.jboss.netty.example.discard; <programlisting>package org.jboss.netty.example.discard;
@&ChannelPipelineCoverage;("all")<co id="example.discard.co1"/> public class DiscardServerHandler extends &SimpleChannelHandler; {<co id="example.discard.co1"/>
public class DiscardServerHandler extends &SimpleChannelHandler; {<co id="example.discard.co2"/>
@Override @Override
public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) {<co id="example.discard.co3"/> public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) {<co id="example.discard.co2"/>
} }
@Override @Override
public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) {<co id="example.discard.co4"/> public void exceptionCaught(&ChannelHandlerContext; ctx, &ExceptionEvent; e) {<co id="example.discard.co3"/>
e.getCause().printStackTrace(); e.getCause().printStackTrace();
&Channel; ch = e.getChannel(); &Channel; ch = e.getChannel();
@ -90,16 +89,6 @@ public class DiscardServerHandler extends &SimpleChannelHandler; {<co id="exampl
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
<callout arearefs="example.discard.co1"> <callout arearefs="example.discard.co1">
<para>
&ChannelPipelineCoverage; annotates a handler type to tell if the
handler instance of the annotated type can be shared by more than
one &Channel; (and its associated &ChannelPipeline;).
<classname>DiscardServerHandler</classname> does not manage any
stateful information, and therefore it is annotated with the value
<literal>"all"</literal>.
</para>
</callout>
<callout arearefs="example.discard.co2">
<para> <para>
<classname>DiscardServerHandler</classname> extends <classname>DiscardServerHandler</classname> extends
&SimpleChannelHandler;, which is an implementation of &SimpleChannelHandler;, which is an implementation of
@ -109,7 +98,7 @@ public class DiscardServerHandler extends &SimpleChannelHandler; {<co id="exampl
the handler interfaces by yourself. the handler interfaces by yourself.
</para> </para>
</callout> </callout>
<callout arearefs="example.discard.co3"> <callout arearefs="example.discard.co2">
<para> <para>
We override the <methodname>messageReceived</methodname> event We override the <methodname>messageReceived</methodname> event
handler method here. This method is called with a &MessageEvent;, handler method here. This method is called with a &MessageEvent;,
@ -118,7 +107,7 @@ public class DiscardServerHandler extends &SimpleChannelHandler; {<co id="exampl
nothing to implement the DISCARD protocol. nothing to implement the DISCARD protocol.
</para> </para>
</callout> </callout>
<callout arearefs="example.discard.co4"> <callout arearefs="example.discard.co3">
<para> <para>
<methodname>exceptionCaught</methodname> event handler method is <methodname>exceptionCaught</methodname> event handler method is
called with an &ExceptionEvent; when an exception was raised by called with an &ExceptionEvent; when an exception was raised by
@ -154,14 +143,14 @@ public class DiscardServer {
bootstrap.setPipelineFactory(new &ChannelPipelineFactory;() {<co id="example.discard2.co3" /> bootstrap.setPipelineFactory(new &ChannelPipelineFactory;() {<co id="example.discard2.co3" />
public &ChannelPipeline; getPipeline() { public &ChannelPipeline; getPipeline() {
return &Channels;.pipeline(new DiscardServerHandler());<co id="example.discard2.co4" /> return &Channels;.pipeline(new DiscardServerHandler());
} }
}); });
bootstrap.setOption("child.tcpNoDelay", true);<co id="example.discard2.co5" /> bootstrap.setOption("child.tcpNoDelay", true);<co id="example.discard2.co4" />
bootstrap.setOption("child.keepAlive", true); bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(8080));<co id="example.discard2.co6" /> bootstrap.bind(new InetSocketAddress(8080));<co id="example.discard2.co5" />
} }
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
@ -200,13 +189,6 @@ public class DiscardServer {
</para> </para>
</callout> </callout>
<callout arearefs="example.discard2.co4"> <callout arearefs="example.discard2.co4">
<para>
Strictly speaking, we do not need to create a new
<classname>DiscardServerHandler</classname> instance for a new
connection because the handler is stateless.
</para>
</callout>
<callout arearefs="example.discard2.co5">
<para> <para>
You can also set the parameters which are specific to the &Channel; You can also set the parameters which are specific to the &Channel;
implementation. We are writing a TCP/IP server, so we are allowed implementation. We are writing a TCP/IP server, so we are allowed
@ -219,7 +201,7 @@ public class DiscardServer {
<programlisting>bootstrap.setOption("reuseAddress", true);</programlisting> <programlisting>bootstrap.setOption("reuseAddress", true);</programlisting>
</para> </para>
</callout> </callout>
<callout arearefs="example.discard2.co6"> <callout arearefs="example.discard2.co5">
<para> <para>
We are ready to go now. What's left is to bind to the port and to We are ready to go now. What's left is to bind to the port and to
start the server. Here, we bind to the port <literal>8080</literal> start the server. Here, we bind to the port <literal>8080</literal>
@ -260,6 +242,7 @@ public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) {
&ChannelBuffer;<co id="example.discard3.co1"/> buf = (ChannelBuffer) e.getMessage(); &ChannelBuffer;<co id="example.discard3.co1"/> buf = (ChannelBuffer) e.getMessage();
while(buf.readable()) { while(buf.readable()) {
System.out.println((char) buf.readByte()); System.out.println((char) buf.readByte());
System.out.flush();
} }
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
@ -353,7 +336,6 @@ public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) {
</para> </para>
<programlisting>package org.jboss.netty.example.time; <programlisting>package org.jboss.netty.example.time;
@&ChannelPipelineCoverage;("all")
public class TimeServerHandler extends &SimpleChannelHandler; { public class TimeServerHandler extends &SimpleChannelHandler; {
@Override @Override
@ -447,7 +429,7 @@ ch.close();</programlisting>
method after the &ChannelFuture;, which was returned by the method after the &ChannelFuture;, which was returned by the
<methodname>write</methodname> method, notifies you when the write <methodname>write</methodname> method, notifies you when the write
operation has been done. Please note that, <methodname>close</methodname> operation has been done. Please note that, <methodname>close</methodname>
might not close the connection immediately, and it returns a also might not close the connection immediately, and it returns a
&ChannelFuture;. &ChannelFuture;.
</para> </para>
</callout> </callout>
@ -545,7 +527,6 @@ public class TimeClient {
import java.util.Date; import java.util.Date;
@&ChannelPipelineCoverage;("all")
public class TimeClientHandler extends &SimpleChannelHandler; { public class TimeClientHandler extends &SimpleChannelHandler; {
@Override @Override
@ -633,17 +614,16 @@ import static org.jboss.netty.buffer.&ChannelBuffers;.*;
import java.util.Date; import java.util.Date;
@&ChannelPipelineCoverage;("one")<co id="example.time3.co1"/>
public class TimeClientHandler extends &SimpleChannelHandler; { public class TimeClientHandler extends &SimpleChannelHandler; {
private final &ChannelBuffer; buf = dynamicBuffer();<co id="example.time3.co2"/> private final &ChannelBuffer; buf = dynamicBuffer();<co id="example.time3.co1"/>
@Override @Override
public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) { public void messageReceived(&ChannelHandlerContext; ctx, &MessageEvent; e) {
&ChannelBuffer; m = (&ChannelBuffer;) e.getMessage(); &ChannelBuffer; m = (&ChannelBuffer;) e.getMessage();
buf.writeBytes(m);<co id="example.time3.co3"/> buf.writeBytes(m);<co id="example.time3.co2"/>
if (buf.readableBytes() &gt;= 4) {<co id="example.time3.co4"/> if (buf.readableBytes() &gt;= 4) {<co id="example.time3.co3"/>
long currentTimeMillis = buf.readInt() * 1000L; long currentTimeMillis = buf.readInt() * 1000L;
System.out.println(new Date(currentTimeMillis)); System.out.println(new Date(currentTimeMillis));
e.getChannel().close(); e.getChannel().close();
@ -658,30 +638,19 @@ public class TimeClientHandler extends &SimpleChannelHandler; {
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
<callout arearefs="example.time3.co1"> <callout arearefs="example.time3.co1">
<para>
This time, <literal>"one"</literal> was used as the value of the
&ChannelPipelineCoverage; annotation. It's because the new
<classname>TimeClientHandler</classname> has to maintain the internal
buffer and therefore cannot serve multiple &Channel;s. If an
instance of <classname>TimeClientHandler</classname> is shared by
multiple &Channel;s (and consequently multiple &ChannelPipeline;s),
the content of the <varname>buf</varname> will be corrupted.
</para>
</callout>
<callout arearefs="example.time3.co2">
<para> <para>
A <firstterm>dynamic buffer</firstterm> is a &ChannelBuffer; which A <firstterm>dynamic buffer</firstterm> is a &ChannelBuffer; which
increases its capacity on demand. It's very useful when you don't increases its capacity on demand. It's very useful when you don't
know the length of the message. know the length of the message.
</para> </para>
</callout> </callout>
<callout arearefs="example.time3.co3"> <callout arearefs="example.time3.co2">
<para> <para>
First, all received data should be cumulated into First, all received data should be cumulated into
<varname>buf</varname>. <varname>buf</varname>.
</para> </para>
</callout> </callout>
<callout arearefs="example.time3.co4"> <callout arearefs="example.time3.co3">
<para> <para>
And then, the handler must check if <varname>buf</varname> has enough And then, the handler must check if <varname>buf</varname> has enough
data, 4 bytes in this example, and proceed to the actual business data, 4 bytes in this example, and proceed to the actual business
@ -729,35 +698,28 @@ public class TimeClientHandler extends &SimpleChannelHandler; {
</para> </para>
<programlisting>package org.jboss.netty.example.time; <programlisting>package org.jboss.netty.example.time;
<co id="example.time4.co1"/>
public class TimeDecoder extends &FrameDecoder; { public class TimeDecoder extends &FrameDecoder; {
@Override @Override
protected Object decode( protected Object decode(
&ChannelHandlerContext; ctx, &Channel; channel, &ChannelBuffer; buffer)<co id="example.time4.co2"/> { &ChannelHandlerContext; ctx, &Channel; channel, &ChannelBuffer; buffer)<co id="example.time4.co1"/> {
if (buffer.readableBytes() &lt; 4) { if (buffer.readableBytes() &lt; 4) {
return null; <co id="example.time4.co3"/> return null; <co id="example.time4.co2"/>
} }
return buffer.readBytes(4);<co id="example.time4.co4"/> return buffer.readBytes(4);<co id="example.time4.co3"/>
} }
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
<callout arearefs="example.time4.co1"> <callout arearefs="example.time4.co1">
<para>
There's no &ChannelPipelineCoverage; annotation this time because
&FrameDecoder; is already annotated with <literal>"one"</literal>.
</para>
</callout>
<callout arearefs="example.time4.co2">
<para> <para>
&FrameDecoder; calls <methodname>decode</methodname> method with &FrameDecoder; calls <methodname>decode</methodname> method with
an internally maintained cumulative buffer whenever new data is an internally maintained cumulative buffer whenever new data is
received. received.
</para> </para>
</callout> </callout>
<callout arearefs="example.time4.co3"> <callout arearefs="example.time4.co2">
<para> <para>
If <literal>null</literal> is returned, it means there's not If <literal>null</literal> is returned, it means there's not
enough data yet. &FrameDecoder; will call again when there is a enough data yet. &FrameDecoder; will call again when there is a
@ -926,27 +888,19 @@ public void channelConnected(&ChannelHandlerContext; ctx, &ChannelStateEvent; e)
import static org.jboss.netty.buffer.&ChannelBuffers;.*; import static org.jboss.netty.buffer.&ChannelBuffers;.*;
@&ChannelPipelineCoverage;("all")<co id="example.time6.co1"/>
public class TimeEncoder extends &SimpleChannelHandler; { public class TimeEncoder extends &SimpleChannelHandler; {
public void writeRequested(&ChannelHandlerContext; ctx, &MessageEvent;<co id="example.time6.co2"/> e) { public void writeRequested(&ChannelHandlerContext; ctx, &MessageEvent;<co id="example.time6.co1"/> e) {
UnixTime time = (UnixTime) e.getMessage(); UnixTime time = (UnixTime) e.getMessage();
&ChannelBuffer; buf = buffer(4); &ChannelBuffer; buf = buffer(4);
buf.writeInt(time.getValue()); buf.writeInt(time.getValue());
&Channels;.write(ctx, e.getFuture(), buf);<co id="example.time6.co3"/> &Channels;.write(ctx, e.getFuture(), buf);<co id="example.time6.co2"/>
} }
}</programlisting> }</programlisting>
<calloutlist> <calloutlist>
<callout arearefs="example.time6.co1"> <callout arearefs="example.time6.co1">
<para>
The &ChannelPipelineCoverage; value of an encoder is usually
<literal>"all"</literal> because this encoder is stateless.
Actually, most encoders are stateless.
</para>
</callout>
<callout arearefs="example.time6.co2">
<para> <para>
An encoder overrides the <methodname>writeRequested</methodname> An encoder overrides the <methodname>writeRequested</methodname>
method to intercept a write request. Please note that the method to intercept a write request. Please note that the
@ -962,7 +916,7 @@ public class TimeEncoder extends &SimpleChannelHandler; {
between a upstream event and a downstream event. between a upstream event and a downstream event.
</para> </para>
</callout> </callout>
<callout arearefs="example.time6.co3"> <callout arearefs="example.time6.co2">
<para> <para>
Once done with transforming a POJO into a &ChannelBuffer;, you should Once done with transforming a POJO into a &ChannelBuffer;, you should
forward the new buffer to the previous &ChannelDownstreamHandler; in forward the new buffer to the previous &ChannelDownstreamHandler; in