View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec;
17  
18  import io.netty.channel.ChannelHandlerAdapter;
19  import io.netty.channel.ChannelHandlerContext;
20  import io.netty.channel.ChannelPromise;
21  import io.netty.util.ReferenceCounted;
22  import io.netty.util.internal.TypeParameterMatcher;
23  
24  import java.util.List;
25  
26  /**
27   * A Codec for on-the-fly encoding/decoding of message.
28   *
29   * This can be thought of as a combination of {@link MessageToMessageDecoder} and {@link MessageToMessageEncoder}.
30   *
31   * Here is an example of a {@link MessageToMessageCodec} which just decode from {@link Integer} to {@link Long}
32   * and encode from {@link Long} to {@link Integer}.
33   *
34   * <pre>
35   *     public class NumberCodec extends
36   *             {@link MessageToMessageCodec}&lt;{@link Integer}, {@link Long}&gt; {
37   *         {@code @Override}
38   *         public {@link Long} decode({@link ChannelHandlerContext} ctx, {@link Integer} msg, List&lt;Object&gt; out)
39   *                 throws {@link Exception} {
40   *             out.add(msg.longValue());
41   *         }
42   *
43   *         {@code @Overrride}
44   *         public {@link Integer} encode({@link ChannelHandlerContext} ctx, {@link Long} msg, List&lt;Object&gt; out)
45   *                 throws {@link Exception} {
46   *             out.add(msg.intValue());
47   *         }
48   *     }
49   * </pre>
50   *
51   * Be aware that you need to call {@link ReferenceCounted#retain()} on messages that are just passed through if they
52   * are of type {@link ReferenceCounted}. This is needed as the {@link MessageToMessageCodec} will call
53   * {@link ReferenceCounted#release()} on encoded / decoded messages.
54   */
55  public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends ChannelHandlerAdapter {
56  
57      private final MessageToMessageEncoder<Object> encoder = new MessageToMessageEncoder<Object>() {
58  
59          @Override
60          public boolean acceptOutboundMessage(Object msg) throws Exception {
61              return MessageToMessageCodec.this.acceptOutboundMessage(msg);
62          }
63  
64          @Override
65          @SuppressWarnings("unchecked")
66          protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
67              MessageToMessageCodec.this.encode(ctx, (OUTBOUND_IN) msg, out);
68          }
69      };
70  
71      private final MessageToMessageDecoder<Object> decoder = new MessageToMessageDecoder<Object>() {
72  
73          @Override
74          public boolean acceptInboundMessage(Object msg) throws Exception {
75              return MessageToMessageCodec.this.acceptInboundMessage(msg);
76          }
77  
78          @Override
79          @SuppressWarnings("unchecked")
80          protected void decode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
81              MessageToMessageCodec.this.decode(ctx, (INBOUND_IN) msg, out);
82          }
83      };
84  
85      private final TypeParameterMatcher inboundMsgMatcher;
86      private final TypeParameterMatcher outboundMsgMatcher;
87  
88      /**
89       * Create a new instance which will try to detect the types to decode and encode out of the type parameter
90       * of the class.
91       */
92      protected MessageToMessageCodec() {
93          inboundMsgMatcher = TypeParameterMatcher.find(this, MessageToMessageCodec.class, "INBOUND_IN");
94          outboundMsgMatcher = TypeParameterMatcher.find(this, MessageToMessageCodec.class, "OUTBOUND_IN");
95      }
96  
97      /**
98       * Create a new instance.
99       *
100      * @param inboundMessageType    The type of messages to decode
101      * @param outboundMessageType   The type of messages to encode
102      */
103     protected MessageToMessageCodec(
104             Class<? extends INBOUND_IN> inboundMessageType, Class<? extends OUTBOUND_IN> outboundMessageType) {
105         inboundMsgMatcher = TypeParameterMatcher.get(inboundMessageType);
106         outboundMsgMatcher = TypeParameterMatcher.get(outboundMessageType);
107     }
108 
109     @Override
110     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
111         decoder.channelRead(ctx, msg);
112     }
113 
114     @Override
115     public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
116         encoder.write(ctx, msg, promise);
117     }
118 
119     /**
120      * Returns {@code true} if and only if the specified message can be decoded by this codec.
121      *
122      * @param msg the message
123      */
124     public boolean acceptInboundMessage(Object msg) throws Exception {
125         return inboundMsgMatcher.match(msg);
126     }
127 
128     /**
129      * Returns {@code true} if and only if the specified message can be encoded by this codec.
130      *
131      * @param msg the message
132      */
133     public boolean acceptOutboundMessage(Object msg) throws Exception {
134         return outboundMsgMatcher.match(msg);
135     }
136 
137     /**
138      * @see MessageToMessageEncoder#encode(ChannelHandlerContext, Object, List)
139      */
140     protected abstract void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, List<Object> out)
141             throws Exception;
142 
143     /**
144      * @see MessageToMessageDecoder#decode(ChannelHandlerContext, Object, List)
145      */
146     protected abstract void decode(ChannelHandlerContext ctx, INBOUND_IN msg, List<Object> out)
147             throws Exception;
148 }