Add a lot of javadocs to make usage more clear

This commit is contained in:
Norman Maurer 2012-12-21 22:22:40 +01:00
parent b004066f37
commit 8a7bc2c606
25 changed files with 486 additions and 73 deletions

View File

@ -15,6 +15,9 @@
*/ */
package io.netty.buffer; package io.netty.buffer;
/**
* A buffer to operate on
*/
public interface Buf { public interface Buf {
/** /**
* The BufType which will be handled by the Buf implementation * The BufType which will be handled by the Buf implementation

View File

@ -26,6 +26,9 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder; import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult; import java.nio.charset.CoderResult;
/**
* Utility class for operate on a {@link ByteBuf}
*/
public final class ByteBufUtil { public final class ByteBufUtil {
private static final char[] HEXDUMP_TABLE = new char[256 * 4]; private static final char[] HEXDUMP_TABLE = new char[256 * 4];

View File

@ -20,30 +20,171 @@ import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
/**
* A {@link ByteBuf} which is composed out of other {@link ByteBuf}s.
*/
public interface CompositeByteBuf extends ByteBuf, Iterable<ByteBuf> { public interface CompositeByteBuf extends ByteBuf, Iterable<ByteBuf> {
/**
* Add the given {@link ByteBuf}.
*
* @param buffer the {@link ByteBuf} to add
* @return self this instance
*/
CompositeByteBuf addComponent(ByteBuf buffer); CompositeByteBuf addComponent(ByteBuf buffer);
/**
* Add the given {@link ByteBuf} on the specific index.
*
* @param cIndex
* the index on which the {@link ByteBuf} will be added
* @param buffer
* the {@link ByteBuf} to add
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*/
CompositeByteBuf addComponent(int cIndex, ByteBuf buffer); CompositeByteBuf addComponent(int cIndex, ByteBuf buffer);
/**
* Add the given {@link ByteBuf}s.
*
* @param buffers the {@link ByteBuf}s to add
* @return self this instance
*/
CompositeByteBuf addComponents(ByteBuf... buffers); CompositeByteBuf addComponents(ByteBuf... buffers);
/**
* Add the given {@link ByteBuf}s.
*
* @param buffers the {@link ByteBuf}s to add
* @return self this instance
*/
CompositeByteBuf addComponents(Iterable<ByteBuf> buffers); CompositeByteBuf addComponents(Iterable<ByteBuf> buffers);
/**
* Add the given {@link ByteBuf}s on the specific index
*
* @param cIndex
* the index on which the {@link ByteBuf} will be added.
* @param buffers
* the {@link ByteBuf}s to add
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*
*/
CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers); CompositeByteBuf addComponents(int cIndex, ByteBuf... buffers);
/**
* Add the given {@link ByteBuf}s on the specific index
*
* @param cIndex
* the index on which the {@link ByteBuf} will be added.
* @param buffers
* the {@link ByteBuf}s to add
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*/
CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers); CompositeByteBuf addComponents(int cIndex, Iterable<ByteBuf> buffers);
/**
* Remove the {@link ByteBuf} from the given index.
*
* @param cIndex
* the index on from which the {@link ByteBuf} will be remove
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*/
CompositeByteBuf removeComponent(int cIndex); CompositeByteBuf removeComponent(int cIndex);
/**
* Remove the number of {@link ByteBuf}s starting from the given index.
*
* @param cIndex
* the index on which the {@link ByteBuf}s will be started to removed
* @param numComponents
* the number of components to remove
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*/
CompositeByteBuf removeComponents(int cIndex, int numComponents); CompositeByteBuf removeComponents(int cIndex, int numComponents);
/**
* Return the current number of {@link ByteBuf}'s that are composed in this instance
*/
int numComponents(); int numComponents();
/**
* Return the max number of {@link ByteBuf}'s that are composed in this instance
*/
int maxNumComponents(); int maxNumComponents();
/**
* Return the {@link ByteBuf} on the specified index
*
* @param cIndex
* the index for which the {@link ByteBuf} should be returned
* @return buf
* the {@link ByteBuf} on the specified index
* @thows {@link IndexOutOfBoundsException}
* if the index is invalid
*/
ByteBuf component(int cIndex); ByteBuf component(int cIndex);
/**
* Return the {@link ByteBuf} on the specified index
*
* @param offset
* the offset for which the {@link ByteBuf} should be returned
* @return buf
* the {@link ByteBuf} on the specified index
* @thows {@link IndexOutOfBoundsException}
* if the offset is invalid
*/
ByteBuf componentAtOffset(int offset); ByteBuf componentAtOffset(int offset);
/**
* Discard all {@link ByteBuf}s which are read.
*
* @return self this instance
*/
CompositeByteBuf discardReadComponents(); CompositeByteBuf discardReadComponents();
/**
* Consolidate the composed {@link ByteBuf}s
*
* @return self this instance
*/
CompositeByteBuf consolidate(); CompositeByteBuf consolidate();
/**
* Consolidate the composed {@link ByteBuf}s
*
* @param cIndex
* the index on which to start to compose
* @param numComponents
* the number of components to compose
* @return self
* this instance
* @thows {@link IndexOutOfBoundsException}
* if the offset is invalid
*/
CompositeByteBuf consolidate(int cIndex, int numComponents); CompositeByteBuf consolidate(int cIndex, int numComponents);
/**
* Return the index for the given offset
*/
int toComponentIndex(int offset); int toComponentIndex(int offset);
int toByteIndex(int cIndex); int toByteIndex(int cIndex);
/** /**

View File

@ -19,6 +19,10 @@ import java.util.ArrayDeque;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
/**
* Default {@link MessageBuf} implementation
*
*/
final class DefaultMessageBuf<T> extends ArrayDeque<T> implements MessageBuf<T> { final class DefaultMessageBuf<T> extends ArrayDeque<T> implements MessageBuf<T> {
private static final long serialVersionUID = 1229808623624907552L; private static final long serialVersionUID = 1229808623624907552L;

View File

@ -19,11 +19,26 @@ import java.util.Collection;
import java.util.Queue; import java.util.Queue;
/** /**
* Buf which operates on messages * Buf which operates on messages.
* *
* @param <T> * @param <T> the type of the messages that are hold by this {@link MessageBuf}
*/ */
public interface MessageBuf<T> extends Buf, Queue<T> { public interface MessageBuf<T> extends Buf, Queue<T> {
/**
* Drain the content of te {@link MessageBuf} to the given {@link Collection}.
*
* @param c the {@link Collection} to drain the content to
* @return number the number of objects which was transfered
*/
int drainTo(Collection<? super T> c); int drainTo(Collection<? super T> c);
/**
* Drain the content of te {@link MessageBuf} to the given {@link Collection}.
*
* @param c the {@link Collection} to drain the content to
* @param maxElements the max number of elements to drain
* @return number the number of objects which was transfered
*/
int drainTo(Collection<? super T> c, int maxElements); int drainTo(Collection<? super T> c, int maxElements);
} }

View File

@ -23,6 +23,36 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandler; import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelOutboundByteHandler; import io.netty.channel.ChannelOutboundByteHandler;
/**
* A Codec for on-the-fly encoding/decoding of bytes.
*
* This can be though of an combination of {@link ByteToByteDecoder} and {@link ByteToByteEncoder}.
*
* Here is an example of a {@link ByteToByteCodec} which just square {@link Integer} read from a {@link ByteBuf}.
* <pre>
* public class SquareCodec extends {@link ByteToByteCodec} {
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
*
* {@code @Overrride}
* public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value / value);
* }
* }
* </pre>
*/
public abstract class ByteToByteCodec public abstract class ByteToByteCodec
extends ChannelHandlerAdapter extends ChannelHandlerAdapter
implements ChannelInboundByteHandler, ChannelOutboundByteHandler { implements ChannelInboundByteHandler, ChannelOutboundByteHandler {
@ -76,10 +106,16 @@ public abstract class ByteToByteCodec
encoder.freeOutboundBuffer(ctx, buf); encoder.freeOutboundBuffer(ctx, buf);
} }
/**
* @see {@link ByteToByteEncoder#encode(ChannelHandlerContext, ByteBuf, ByteBuf)}
*/
public abstract void encode( public abstract void encode(
ChannelHandlerContext ctx, ChannelHandlerContext ctx,
ByteBuf in, ByteBuf out) throws Exception; ByteBuf in, ByteBuf out) throws Exception;
/**
* @see {@link ByteToByteDecoder#decode(ChannelHandlerContext, ByteBuf, ByteBuf)}
*/
public abstract void decode( public abstract void decode(
ChannelHandlerContext ctx, ChannelHandlerContext ctx,
ByteBuf in, ByteBuf out) throws Exception; ByteBuf in, ByteBuf out) throws Exception;

View File

@ -19,6 +19,29 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundByteHandlerAdapter; import io.netty.channel.ChannelInboundByteHandlerAdapter;
/**
* {@link ChannelInboundByteHandlerAdapter} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an
* other.
*
* This kind of decoder is often useful for doing on-the-fly processiing like i.e. compression.
*
* But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from
* the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}.
*
* <pre>
* public class SquareDecoder extends {@link ByteToByteDecoder} {
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
* }
* </pre>
*/
public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter { public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter {
@Override @Override
@ -52,6 +75,9 @@ public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter
ctx.fireChannelInactive(); ctx.fireChannelInactive();
} }
/**
* Call the {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} method until it is done.
*/
private void callDecode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) { private void callDecode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) {
int oldOutSize = out.readableBytes(); int oldOutSize = out.readableBytes();
while (in.readable()) { while (in.readable()) {
@ -76,8 +102,24 @@ public abstract class ByteToByteDecoder extends ChannelInboundByteHandlerAdapter
} }
} }
/**
* Decode the from one {@link ByteBuf} to an other. This method will be called till either the input
* {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @param out the {@link ByteBuf} to which the decoded data will be written
* @throws Exception is thrown if an error accour
*/
public abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; public abstract void decode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
/**
* Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the
* {@link #channelInactive(ChannelHandlerContext)} was triggered.
*
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf, ByteBuf)} but sub-classes may
* override this for some special cleanup operation.
*/
public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { public void decodeLast(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception {
decode(ctx, in, out); decode(ctx, in, out);
} }

View File

@ -20,6 +20,29 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundByteHandlerAdapter; import io.netty.channel.ChannelOutboundByteHandlerAdapter;
/**
* {@link ChannelOutboundByteHandlerAdapter} which encodes bytes in a stream-like fashion from one {@link ByteBuf} to an
* other.
*
* This kind of decoder is often useful for doing on-the-fly processing like i.e. compression.
*
* But you can also do other things with it. For example here is an implementation which reads {@link Integer}s from
* the input {@link ByteBuf} and square them before write them to the output {@link ByteBuf}.
*
* <pre>
* public class SquareEncoder extends {@link ByteToByteEncoder} {
* {@code @Override}
* public void encode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in, {@link ByteBuf} out)
* throws {@link Exception} {
* if (in.readableBytes() < 4) {
* return;
* }
* int value = in.readInt();
* out.writeInt(value * value);
* }
* }
* </pre>
*/
public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapter { public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapter {
@Override @Override
@ -47,5 +70,14 @@ public abstract class ByteToByteEncoder extends ChannelOutboundByteHandlerAdapte
ctx.flush(future); ctx.flush(future);
} }
/**
* Encodes the from one {@link ByteBuf} to an other. This method will be called till either the input
* {@link ByteBuf} has nothing to read anymore or till nothing was read from the input {@link ByteBuf}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @param out the {@link ByteBuf} to which the decoded data will be written
* @throws Exception is thrown if an error accour
*/
public abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception; public abstract void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception;
} }

View File

@ -22,6 +22,23 @@ import io.netty.channel.ChannelInboundByteHandler;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
/**
* {@link ChannelInboundByteHandler} which decodes bytes in a stream-like fashion from one {@link ByteBuf} to an other
* Message type.
*
* For example here is an implementation which reads all readable bytes from
* the input {@link ByteBuf} and create a new {@link ByteBuf}.
*
* <pre>
* public class SquareDecoder extends {@link ByteToMessageDecoder}&lt;{@link ByteBuf}&gt; {
* {@code @Override}
* public {@link ByteBuf} decode({@link ChannelHandlerContext} ctx, {@link ByteBuf} in)
* throws {@link Exception} {
* return in.readBytes(in.readableBytes());
* }
* }
* </pre>
*/
public abstract class ByteToMessageDecoder<O> public abstract class ByteToMessageDecoder<O>
extends ChannelInboundHandlerAdapter implements ChannelInboundByteHandler { extends ChannelInboundHandlerAdapter implements ChannelInboundByteHandler {
@ -138,8 +155,26 @@ public abstract class ByteToMessageDecoder<O>
} }
} }
/**
* Decode the from one {@link ByteBuf} to an other. This method will be called till either the input
* {@link ByteBuf} has nothing to read anymore, till nothing was read from the input {@link ByteBuf} or till
* this method returns {@code null}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link ByteToByteDecoder} belongs to
* @param in the {@link ByteBuf} from which to read data
* @return message the message to which the content of the {@link ByteBuf} was decoded, or {@code null} if
* there was not enough data left in the {@link ByteBuf} to decode.
* @throws Exception is thrown if an error accour
*/
public abstract O decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception; public abstract O decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception;
/**
* Is called one last time when the {@link ChannelHandlerContext} goes in-active. Which means the
* {@link #channelInactive(ChannelHandlerContext)} was triggered.
*
* By default this will just call {@link #decode(ChannelHandlerContext, ByteBuf)} but sub-classes may
* override this for some special cleanup operation.
*/
public O decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception { public O decodeLast(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
return decode(ctx, in); return decode(ctx, in);
} }

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
/** /**
* An {@link Exception} which is thrown when the received frame data could not be decoded by * An {@link DecoderException} which is thrown when the received frame data could not be decoded by
* an inbound handler. * an inbound handler.
* *
* @apiviz.exclude * @apiviz.exclude

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
/** /**
* An {@link Exception} which is thrown by an encoder. * An {@link CodecException} which is thrown by a dencoder.
* *
* @apiviz.exclude * @apiviz.exclude
*/ */

View File

@ -39,7 +39,7 @@ import io.netty.channel.ChannelHandlerContext;
* | ABC\nDEF\r\n | * | ABC\nDEF\r\n |
* +--------------+ * +--------------+
* </pre> * </pre>
* a {@link DelimiterBasedFrameDecoder}{@code (}{@link Delimiters#lineDelimiter() Delimiters.lineDelimiter()}{@code )} * a {@link DelimiterBasedFrameDecoder}({@link Delimiters#lineDelimiter() Delimiters.lineDelimiter()})
* will choose {@code '\n'} as the first delimiter and produce two frames: * will choose {@code '\n'} as the first delimiter and produce two frames:
* <pre> * <pre>
* +-----+-----+ * +-----+-----+

View File

@ -16,7 +16,7 @@
package io.netty.handler.codec; package io.netty.handler.codec;
/** /**
* An {@link Exception} which is thrown by an encoder. * An {@link CodecException} which is thrown by an encoder.
* *
* @apiviz.exclude * @apiviz.exclude
*/ */

View File

@ -411,14 +411,10 @@ public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder<Object> {
} }
/** /**
* Extract the sub-region of the specified buffer. This method is called by * Extract the sub-region of the specified buffer.
* {@link #decode(ChannelInboundHandlerContext, ByteBuf)} for each
* frame. The default implementation returns a copy of the sub-region.
* For example, you could override this method to use an alternative
* {@link ByteBufFactory}.
* <p> * <p>
* If you are sure that the frame and its content are not accessed after * If you are sure that the frame and its content are not accessed after
* the current {@link #decode(ChannelInboundHandlerContext, ByteBuf)} * the current {@link #decode(ChannelHandlerContext, ByteBuf)}
* call returns, you can even avoid memory copy by returning the sliced * call returns, you can even avoid memory copy by returning the sliced
* sub-region (i.e. <tt>return buffer.slice(index, length)</tt>). * sub-region (i.e. <tt>return buffer.slice(index, length)</tt>).
* It's often useful when you convert the extracted frame into an object. * It's often useful when you convert the extracted frame into an object.

View File

@ -19,13 +19,10 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable; import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.nio.ByteOrder;
/** /**
* An encoder that prepends the length of the message. The length value is * An encoder that prepends the length of the message. The length value is
* prepended as a binary form. It is encoded in either big endian or little * prepended as a binary form.
* endian depending on the default {@link ByteOrder} of the current
* {@link ByteBufFactory}.
* <p> * <p>
* For example, <tt>{@link LengthFieldPrepender}(2)</tt> will encode the * For example, <tt>{@link LengthFieldPrepender}(2)</tt> will encode the
* following 12-bytes string: * following 12-bytes string:

View File

@ -22,6 +22,24 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundMessageHandlerAdapter; import io.netty.channel.ChannelOutboundMessageHandlerAdapter;
import io.netty.channel.ChannelHandlerUtil; import io.netty.channel.ChannelHandlerUtil;
/**
* {@link ChannelOutboundMessageHandlerAdapter} which encodes message in a stream-like fashion from one message to an
* {@link ByteBuf}.
*
*
* Example implementation which encodes {@link Integer}s to a {@link ByteBuf}.
*
* <pre>
* public class IntegerEncoder extends {@link MessageToByteEncoder}&lt;{@link Integer}&gt; {
* {@code @Override}
* public void encode({@link ChannelHandlerContext} ctx, {@link Integer} msg, {@link ByteBuf} out)
* throws {@link Exception} {
* out.writeInt(msg);
* }
* }
* </pre>
*/
public abstract class MessageToByteEncoder<I> extends ChannelOutboundMessageHandlerAdapter<I> { public abstract class MessageToByteEncoder<I> extends ChannelOutboundMessageHandlerAdapter<I> {
private final Class<?>[] acceptedMsgTypes; private final Class<?>[] acceptedMsgTypes;
@ -71,5 +89,14 @@ public abstract class MessageToByteEncoder<I> extends ChannelOutboundMessageHand
return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg); return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg);
} }
/**
* Encode a message into a {@link ByteBuf}. This method will be called till the {@link MessageBuf} has
* nothing left.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to
* @param msg the message to encode
* @param out the {@link ByteBuf} into which the encoded message will be written
* @throws Exception is thrown if an error accour
*/
public abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception; public abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;
} }

View File

@ -24,6 +24,30 @@ import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandler; import io.netty.channel.ChannelOutboundMessageHandler;
/**
* A Codec for on-the-fly encoding/decoding of message.
*
* This can be though of an combination of {@link MessageToMessageDecoder} and {@link MessageToMessageEncoder}.
*
* Here is an example of a {@link MessageToMessageCodec} which just decode from {@link Integer} to {@link Long}
* and encode from {@link Long} to {@link Integer}.
* <pre>
* public class NumberCodec extends
* {@link MessageToMessageCodec}&lt;{@link Integer}, {@link Long}, {@link Long}, {@link Integer}&gt; {
* {@code @Override}
* public {@link Long} decode({@link ChannelHandlerContext} ctx, {@link Integer} msg)
* throws {@link Exception} {
* return msg.longValue();
* }
*
* {@code @Overrride}
* public {@link Integer} encode({@link ChannelHandlerContext} ctx, {@link Long} msg)
* throws {@link Exception} {
* return msg.intValue();
* }
* }
* </pre>
*/
public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN, OUTBOUND_OUT> public abstract class MessageToMessageCodec<INBOUND_IN, INBOUND_OUT, OUTBOUND_IN, OUTBOUND_OUT>
extends ChannelHandlerAdapter extends ChannelHandlerAdapter
implements ChannelInboundMessageHandler<INBOUND_IN>, implements ChannelInboundMessageHandler<INBOUND_IN>,

View File

@ -21,12 +21,38 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil; import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInboundMessageHandler; import io.netty.channel.ChannelInboundMessageHandler;
import io.netty.channel.ChannelPipeline;
/**
* {@link ChannelInboundMessageHandler} which decodes from one message to an other message
*
* For example here is an implementation which decodes a {@link String} to an {@link Integer} which represent
* the length of the {@link String}.
*
* <pre>
* public class StringToIntegerDecoder extends
* {@link MessageToMessageDecoder}&lt;{@link String},{@link Integer}&gt; {
* public StringToIntegerDecoder() {
* super(String.class);
* }
*
* {@code @Override}
* public {@link Integer} decode({@link ChannelHandlerContext} ctx, {@link String} message)
* throws {@link Exception} {
* return message.length());
* }
* }
* </pre>
*/
public abstract class MessageToMessageDecoder<I, O> public abstract class MessageToMessageDecoder<I, O>
extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler<I> { extends ChannelInboundHandlerAdapter implements ChannelInboundMessageHandler<I> {
private final Class<?>[] acceptedMsgTypes; private final Class<?>[] acceptedMsgTypes;
/**
* The types which will be accepted by the decoder. If a received message is an other type it will be just forwared
* to the next {@link ChannelInboundMessageHandler} in the {@link ChannelPipeline}
*/
protected MessageToMessageDecoder(Class<?>... acceptedMsgTypes) { protected MessageToMessageDecoder(Class<?>... acceptedMsgTypes) {
this.acceptedMsgTypes = ChannelHandlerUtil.acceptedMessageTypes(acceptedMsgTypes); this.acceptedMsgTypes = ChannelHandlerUtil.acceptedMessageTypes(acceptedMsgTypes);
} }
@ -80,12 +106,20 @@ public abstract class MessageToMessageDecoder<I, O>
/** /**
* Returns {@code true} if and only if the specified message can be decoded by this decoder. * Returns {@code true} if and only if the specified message can be decoded by this decoder.
*
* @param msg the message
*/ */
public boolean isDecodable(Object msg) throws Exception { public boolean isDecodable(Object msg) throws Exception {
return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg); return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg);
} }
/**
* Decode from one message to an other. This method will be called till either the {@link MessageBuf} has
* nothing left or till this method returns {@code null}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to
* @param msg the message to decode to an other one
* @return message the decoded message or {@code null} if more messages are needed be cause the implementation
* needs to do some kind of aggragation
* @throws Exception is thrown if an error accour
*/
public abstract O decode(ChannelHandlerContext ctx, I msg) throws Exception; public abstract O decode(ChannelHandlerContext ctx, I msg) throws Exception;
} }

View File

@ -18,13 +18,39 @@ package io.netty.handler.codec;
import io.netty.buffer.MessageBuf; import io.netty.buffer.MessageBuf;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundMessageHandler;
import io.netty.channel.ChannelOutboundMessageHandlerAdapter; import io.netty.channel.ChannelOutboundMessageHandlerAdapter;
import io.netty.channel.ChannelHandlerUtil; import io.netty.channel.ChannelHandlerUtil;
import io.netty.channel.ChannelPipeline;
/**
* {@link ChannelOutboundMessageHandlerAdapter} which encodes from one message to an other message
*
* For example here is an implementation which decodes an {@link Integer} to an {@link String}.
*
* <pre>
* public class IntegerToStringEncoder extends
* {@link MessageToMessageEncoder}&lt;{@link Integer},{@link String}&gt; {
* public StringToIntegerDecoder() {
* super(String.class);
* }
*
* {@code @Override}
* public {@link String} encode({@link ChannelHandlerContext} ctx, {@link Integer} message)
* throws {@link Exception} {
* return message.toString();
* }
* }
* </pre>
*/
public abstract class MessageToMessageEncoder<I, O> extends ChannelOutboundMessageHandlerAdapter<I> { public abstract class MessageToMessageEncoder<I, O> extends ChannelOutboundMessageHandlerAdapter<I> {
private final Class<?>[] acceptedMsgTypes; private final Class<?>[] acceptedMsgTypes;
/**
* The types which will be accepted by the decoder. If a received message is an other type it will be just forwared
* to the next {@link ChannelOutboundMessageHandler} in the {@link ChannelPipeline}
*/
protected MessageToMessageEncoder(Class<?>... acceptedMsgTypes) { protected MessageToMessageEncoder(Class<?>... acceptedMsgTypes) {
this.acceptedMsgTypes = ChannelHandlerUtil.acceptedMessageTypes(acceptedMsgTypes); this.acceptedMsgTypes = ChannelHandlerUtil.acceptedMessageTypes(acceptedMsgTypes);
} }
@ -75,5 +101,15 @@ public abstract class MessageToMessageEncoder<I, O> extends ChannelOutboundMessa
return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg); return ChannelHandlerUtil.acceptMessage(acceptedMsgTypes, msg);
} }
/**
* Encode from one message to an other. This method will be called till either the {@link MessageBuf} has nothing
* left or till this method returns {@code null}.
*
* @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageEncoder} belongs to
* @param msg the message to encode to an other one
* @return message the encoded message or {@code null} if more messages are needed be cause the implementation
* needs to do some kind of aggragation
* @throws Exception is thrown if an error accour
*/
public abstract O encode(ChannelHandlerContext ctx, I msg) throws Exception; public abstract O encode(ChannelHandlerContext ctx, I msg) throws Exception;
} }

View File

@ -16,7 +16,6 @@
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelHandlerUtil; import io.netty.channel.ChannelHandlerUtil;
@ -28,44 +27,41 @@ import io.netty.util.internal.Signal;
* of a non-blocking decoder in the blocking I/O paradigm. * of a non-blocking decoder in the blocking I/O paradigm.
* <p> * <p>
* The biggest difference between {@link ReplayingDecoder} and * The biggest difference between {@link ReplayingDecoder} and
* {@link FrameDecoder} is that {@link ReplayingDecoder} allows you to * {@link ByteToMessageDecoder} is that {@link ReplayingDecoder} allows you to
* implement the {@code decode()} and {@code decodeLast()} methods just like * implement the {@code decode()} and {@code decodeLast()} methods just like
* all required bytes were received already, rather than checking the * all required bytes were received already, rather than checking the
* availability of the required bytes. For example, the following * availability of the required bytes. For example, the following
* {@link FrameDecoder} implementation: * {@link ByteToByteDecoder} implementation:
* <pre> * <pre>
* public class IntegerHeaderFrameDecoder extends {@link FrameDecoder} { * public class IntegerHeaderFrameDecoder extends {@link ByteToMessageDecoder}&lt;{@link ByteBuf}&gt; {
* *
* {@code @Override} * {@code @Override}
* protected Object decode({@link ChannelHandlerContext} ctx, * protected ByteBuf decode({@link ChannelHandlerContext} ctx,
* {@link Channel} channel, * {@link ByteBuf} in) throws Exception {
* {@link ByteBuf} buf) throws Exception {
* *
* if (buf.readableBytes() &lt; 4) { * if (in.readableBytes() &lt; 4) {
* return <strong>null</strong>; * return <strong>null</strong>;
* } * }
* *
* buf.markReaderIndex(); * in.markReaderIndex();
* int length = buf.readInt(); * int length = in.readInt();
* *
* if (buf.readableBytes() &lt; length) { * if (in.readableBytes() &lt; length) {
* buf.resetReaderIndex(); * in.resetReaderIndex();
* return <strong>null</strong>; * return <strong>null</strong>;
* } * }
* *
* return buf.readBytes(length); * return in.readBytes(length);
* } * }
* } * }
* </pre> * </pre>
* is simplified like the following with {@link ReplayingDecoder}: * is simplified like the following with {@link ReplayingDecoder}:
* <pre> * <pre>
* public class IntegerHeaderFrameDecoder * public class IntegerHeaderFrameDecoder
* extends {@link ReplayingDecoder}&lt;{@link VoidEnum}&gt; { * extends {@link ReplayingDecoder}&lt;{@link ByteBuf},{@link Void}&gt; {
* *
* protected Object decode({@link ChannelHandlerContext} ctx, * protected Object decode({@link ChannelHandlerContext} ctx,
* {@link Channel} channel, * {@link ByteBuf} buf) throws Exception {
* {@link ByteBuf} buf,
* {@link VoidEnum} state) throws Exception {
* *
* return buf.readBytes(buf.readInt()); * return buf.readBytes(buf.readInt());
* } * }
@ -104,12 +100,12 @@ import io.netty.util.internal.Signal;
* <li>You must keep in mind that {@code decode(..)} method can be called many * <li>You must keep in mind that {@code decode(..)} method can be called many
* times to decode a single message. For example, the following code will * times to decode a single message. For example, the following code will
* not work: * not work:
* <pre> public class MyDecoder extends {@link ReplayingDecoder}&lt;{@link Void}&gt; { * <pre> public class MyDecoder extends {@link ReplayingDecoder}&lt;{@link Integer}, {@link Void}&gt; {
* *
* private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;(); * private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;();
* *
* {@code @Override} * {@code @Override}
* public Object decode(.., {@link ByteBuf} buffer, ..) throws Exception { * public {@link Integer} decode(.., {@link ByteBuf} in) throws Exception {
* *
* // A message contains 2 integers. * // A message contains 2 integers.
* values.offer(buffer.readInt()); * values.offer(buffer.readInt());
@ -124,12 +120,12 @@ import io.netty.util.internal.Signal;
* The correct implementation looks like the following, and you can also * The correct implementation looks like the following, and you can also
* utilize the 'checkpoint' feature which is explained in detail in the * utilize the 'checkpoint' feature which is explained in detail in the
* next section. * next section.
* <pre> public class MyDecoder extends {@link ReplayingDecoder}&lt;{@link Void}&gt; { * <pre> public class MyDecoder extends {@link ReplayingDecoder}&lt;{@link Integer}, {@link Void}&gt; {
* *
* private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;(); * private final Queue&lt;Integer&gt; values = new LinkedList&lt;Integer&gt;();
* *
* {@code @Override} * {@code @Override}
* public Object decode(.., {@link ByteBuf} buffer, ..) throws Exception { * public {@link Integer} decode(.., {@link ByteBuf} buffer) throws Exception {
* *
* // Revert the state of the variable that might have been changed * // Revert the state of the variable that might have been changed
* // since the last partial decode. * // since the last partial decode.
@ -171,7 +167,7 @@ import io.netty.util.internal.Signal;
* } * }
* *
* public class IntegerHeaderFrameDecoder * public class IntegerHeaderFrameDecoder
* extends {@link ReplayingDecoder}&lt;<strong>MyDecoderState</strong>&gt; { * extends {@link ReplayingDecoder}&lt;{@link ByteBuf}, <strong>MyDecoderState</strong>&gt; {
* *
* private int length; * private int length;
* *
@ -181,16 +177,14 @@ import io.netty.util.internal.Signal;
* } * }
* *
* {@code @Override} * {@code @Override}
* protected Object decode({@link ChannelHandlerContext} ctx, * protected {@link ByteBuf} decode({@link ChannelHandlerContext} ctx,
* {@link Channel} channel, * {@link ByteBuf} in) throws Exception {
* {@link ByteBuf} buf, * switch (state()) {
* <b>MyDecoderState</b> state) throws Exception {
* switch (state) {
* case READ_LENGTH: * case READ_LENGTH:
* length = buf.readInt(); * length = buf.readInt();
* <strong>checkpoint(MyDecoderState.READ_CONTENT);</strong> * <strong>checkpoint(MyDecoderState.READ_CONTENT);</strong>
* case READ_CONTENT: * case READ_CONTENT:
* ChannelBuffer frame = buf.readBytes(length); * ByteBuf frame = buf.readBytes(length);
* <strong>checkpoint(MyDecoderState.READ_LENGTH);</strong> * <strong>checkpoint(MyDecoderState.READ_LENGTH);</strong>
* return frame; * return frame;
* default: * default:
@ -205,16 +199,14 @@ import io.netty.util.internal.Signal;
* An alternative way to manage the decoder state is to manage it by yourself. * An alternative way to manage the decoder state is to manage it by yourself.
* <pre> * <pre>
* public class IntegerHeaderFrameDecoder * public class IntegerHeaderFrameDecoder
* extends {@link ReplayingDecoder}&lt;<strong>{@link Void}</strong>&gt; { * extends {@link ReplayingDecoder}&lt;{@link ByteBuf},<strong>{@link Void}</strong>&gt; {
* *
* <strong>private boolean readLength;</strong> * <strong>private boolean readLength;</strong>
* private int length; * private int length;
* *
* {@code @Override} * {@code @Override}
* protected Object decode({@link ChannelHandlerContext} ctx, * protected {@link ByteBuf} decode({@link ChannelHandlerContext} ctx,
* {@link Channel} channel, * {@link ByteBuf} in) throws Exception {
* {@link ByteBuf} buf,
* {@link Void} state) throws Exception {
* if (!readLength) { * if (!readLength) {
* length = buf.readInt(); * length = buf.readInt();
* <strong>readLength = true;</strong> * <strong>readLength = true;</strong>
@ -222,7 +214,7 @@ import io.netty.util.internal.Signal;
* } * }
* *
* if (readLength) { * if (readLength) {
* ChannelBuffer frame = buf.readBytes(length); * ByteBuf frame = buf.readBytes(length);
* <strong>readLength = false;</strong> * <strong>readLength = false;</strong>
* <strong>checkpoint();</strong> * <strong>checkpoint();</strong>
* return frame; * return frame;
@ -235,31 +227,26 @@ import io.netty.util.internal.Signal;
* <p> * <p>
* If you are going to write a protocol multiplexer, you will probably want to * If you are going to write a protocol multiplexer, you will probably want to
* replace a {@link ReplayingDecoder} (protocol detector) with another * replace a {@link ReplayingDecoder} (protocol detector) with another
* {@link ReplayingDecoder} or {@link FrameDecoder} (actual protocol decoder). * {@link ReplayingDecoder}, {@link ByteToByteDecoder}, {@link ByteToMessageDecoder} or {@link MessageToMessageDecoder}
* (actual protocol decoder).
* It is not possible to achieve this simply by calling * It is not possible to achieve this simply by calling
* {@link ChannelPipeline#replace(ChannelHandler, String, ChannelHandler)}, but * {@link ChannelPipeline#replace(ChannelHandler, String, ChannelHandler)}, but
* some additional steps are required: * some additional steps are required:
* <pre> * <pre>
* public class FirstDecoder extends {@link ReplayingDecoder}&lt;{@link Void}&gt; { * public class FirstDecoder extends {@link ReplayingDecoder}&lt;{@link Object}, {@link Void}&gt; {
*
* public FirstDecoder() {
* super(true); // Enable unfold
* }
* *
* {@code @Override} * {@code @Override}
* protected Object decode({@link ChannelHandlerContext} ctx, * protected Object decode({@link ChannelHandlerContext} ctx,
* {@link Channel} ch, * {@link ByteBuf} in) {
* {@link ByteBuf} buf,
* {@link Void} state) {
* ... * ...
* // Decode the first message * // Decode the first message
* Object firstMessage = ...; * Object firstMessage = ...;
* *
* // Add the second decoder * // Add the second decoder
* ctx.getPipeline().addLast("second", new SecondDecoder()); * ctx.pipeline().addLast("second", new SecondDecoder());
* *
* // Remove the first decoder (me) * // Remove the first decoder (me)
* ctx.getPipeline().remove(this); * ctx.pipeline().remove(this);
* *
* if (buf.readable()) { * if (buf.readable()) {
* // Hand off the remaining data to the second decoder * // Hand off the remaining data to the second decoder

View File

@ -31,6 +31,9 @@ import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/**
* Special {@link ByteBuf} implementation which is used by the {@link ReplayingDecoder}
*/
final class ReplayingDecoderBuffer implements ByteBuf { final class ReplayingDecoderBuffer implements ByteBuf {
private static final Signal REPLAY = ReplayingDecoder.REPLAY; private static final Signal REPLAY = ReplayingDecoder.REPLAY;

View File

@ -16,8 +16,8 @@
package io.netty.handler.codec; package io.netty.handler.codec;
/** /**
* An {@link Exception} which is thrown when the length of the frame * An {@link DecoderException} which is thrown when the length of the frame
* decoded by {@link DelimiterBasedFrameDecoder} is greater than the maximum. * decoded is greater than the allowed maximum.
* *
* @apiviz.exclude * @apiviz.exclude
*/ */

View File

@ -15,11 +15,9 @@
*/ */
package io.netty.handler.codec; package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
/** /**
* An {@link Exception} which is thrown when a user calls an unsupported * An {@link UnsupportedOperationException} which is thrown when a user calls an unsupported
* operation on a {@link ByteBuf} in a {@link ReplayingDecoder} * operation on a {@link ReplayingDecoderBuffer} in a {@link ReplayingDecoder}
* implementation. * implementation.
*/ */
public class UnreplayableOperationException extends UnsupportedOperationException { public class UnreplayableOperationException extends UnsupportedOperationException {

View File

@ -15,6 +15,9 @@
*/ */
package io.netty.handler.codec; package io.netty.handler.codec;
/**
* Thrown if an unsupported message is received by an codec.
*/
public class UnsupportedMessageTypeException extends CodecException { public class UnsupportedMessageTypeException extends CodecException {
private static final long serialVersionUID = 2799598826487038726L; private static final long serialVersionUID = 2799598826487038726L;

View File

@ -28,9 +28,7 @@ import java.net.SocketAddress;
/** /**
* A {@link ChannelHandler} that logs all events via {@link InternalLogger}. * A {@link ChannelHandler} that logs all events via {@link InternalLogger}.
* By default, all events are logged at <tt>DEBUG</tt> level. You can extend * By default, all events are logged at <tt>DEBUG</tt> level.
* this class and override {@link #log(ChannelEvent)} to change the default
* behavior.
* @apiviz.landmark * @apiviz.landmark
*/ */
@Sharable @Sharable
@ -118,7 +116,6 @@ public class LoggingHandler extends ChannelHandlerAdapter {
/** /**
* Returns the {@link InternalLogLevel} that this handler uses to log * Returns the {@link InternalLogLevel} that this handler uses to log
* a {@link ChannelEvent}.
*/ */
public LogLevel level() { public LogLevel level() {
return level; return level;