1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.codec;
17
18 import io.netty5.channel.ChannelHandlerAdapter;
19 import io.netty5.channel.ChannelHandlerContext;
20 import io.netty5.util.ReferenceCounted;
21 import io.netty5.util.concurrent.Future;
22 import io.netty5.util.internal.TypeParameterMatcher;
23
24 import java.util.List;
25
26 import static io.netty5.util.internal.SilentDispose.autoClosing;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public abstract class MessageToMessageCodec<INBOUND_IN, OUTBOUND_IN> extends ChannelHandlerAdapter {
58
59 private final MessageToMessageEncoder<Object> encoder = new MessageToMessageEncoder<>() {
60
61 @Override
62 public boolean acceptOutboundMessage(Object msg) throws Exception {
63 return MessageToMessageCodec.this.acceptOutboundMessage(msg);
64 }
65
66 @Override
67 @SuppressWarnings("unchecked")
68 protected void encodeAndClose(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
69 MessageToMessageCodec.this.encodeAndClose(ctx, (OUTBOUND_IN) msg, out);
70 }
71 };
72
73 private final MessageToMessageDecoder<Object> decoder = new MessageToMessageDecoder<>() {
74
75 @Override
76 public boolean acceptInboundMessage(Object msg) throws Exception {
77 return MessageToMessageCodec.this.acceptInboundMessage(msg);
78 }
79
80 @Override
81 @SuppressWarnings("unchecked")
82 protected void decodeAndClose(ChannelHandlerContext ctx, Object msg) throws Exception {
83 MessageToMessageCodec.this.decodeAndClose(ctx, (INBOUND_IN) msg);
84 }
85 };
86
87 private final TypeParameterMatcher inboundMsgMatcher;
88 private final TypeParameterMatcher outboundMsgMatcher;
89
90
91
92
93
94 protected MessageToMessageCodec() {
95 inboundMsgMatcher = TypeParameterMatcher.find(this, MessageToMessageCodec.class, "INBOUND_IN");
96 outboundMsgMatcher = TypeParameterMatcher.find(this, MessageToMessageCodec.class, "OUTBOUND_IN");
97 }
98
99
100
101
102
103
104
105 protected MessageToMessageCodec(
106 Class<? extends INBOUND_IN> inboundMessageType, Class<? extends OUTBOUND_IN> outboundMessageType) {
107 inboundMsgMatcher = TypeParameterMatcher.get(inboundMessageType);
108 outboundMsgMatcher = TypeParameterMatcher.get(outboundMessageType);
109 }
110
111 @Override
112 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
113 decoder.channelRead(ctx, msg);
114 }
115
116 @Override
117 public Future<Void> write(ChannelHandlerContext ctx, Object msg) {
118 return encoder.write(ctx, msg);
119 }
120
121
122
123
124
125
126 public boolean acceptInboundMessage(Object msg) throws Exception {
127 return inboundMsgMatcher.match(msg);
128 }
129
130
131
132
133
134
135 public boolean acceptOutboundMessage(Object msg) throws Exception {
136 return outboundMsgMatcher.match(msg);
137 }
138
139
140
141
142 protected void encode(ChannelHandlerContext ctx, OUTBOUND_IN msg, List<Object> out)
143 throws Exception {
144 throw new CodecException(getClass().getName() + " must override either encode() or encodeAndClose().");
145 }
146
147
148
149
150 protected void encodeAndClose(ChannelHandlerContext ctx, OUTBOUND_IN msg, List<Object> out) throws Exception {
151 try (AutoCloseable ignore = autoClosing(msg)) {
152 encode(ctx, msg, out);
153 }
154 }
155
156
157
158
159 protected void decode(ChannelHandlerContext ctx, INBOUND_IN msg) throws Exception {
160 throw new CodecException(getClass().getName() + " must override either decode() or decodeAndClose().");
161 }
162
163
164
165
166 protected void decodeAndClose(ChannelHandlerContext ctx, INBOUND_IN msg) throws Exception {
167 try (AutoCloseable ignore = autoClosing(msg)) {
168 decode(ctx, msg);
169 }
170 }
171 }