1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.filter.codec.demux;
21
22 import org.apache.mina.core.buffer.IoBuffer;
23 import org.apache.mina.core.session.AttributeKey;
24 import org.apache.mina.core.session.IoSession;
25 import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
26 import org.apache.mina.filter.codec.ProtocolDecoder;
27 import org.apache.mina.filter.codec.ProtocolDecoderException;
28 import org.apache.mina.filter.codec.ProtocolDecoderOutput;
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 public class DemuxingProtocolDecoder extends CumulativeProtocolDecoder {
89
90 private static final AttributeKeyn/AttributeKey.html#AttributeKey">AttributeKey STATE = new AttributeKey(DemuxingProtocolDecoder.class, "state");
91
92 private MessageDecoderFactoryFactory.html#MessageDecoderFactory">MessageDecoderFactory[] decoderFactories = new MessageDecoderFactory[0];
93
94 private static final Class<?>[] EMPTY_PARAMS = new Class[0];
95
96
97
98
99
100
101 public void addMessageDecoder(Class<? extends MessageDecoder> decoderClass) {
102 if (decoderClass == null) {
103 throw new IllegalArgumentException("decoderClass");
104 }
105
106 try {
107 decoderClass.getConstructor(EMPTY_PARAMS);
108 } catch (NoSuchMethodException e) {
109 throw new IllegalArgumentException("The specified class doesn't have a public default constructor.");
110 }
111
112 boolean registered = false;
113 if (MessageDecoder.class.isAssignableFrom(decoderClass)) {
114 addMessageDecoder(new DefaultConstructorMessageDecoderFactory(decoderClass));
115 registered = true;
116 }
117
118 if (!registered) {
119 throw new IllegalArgumentException("Unregisterable type: " + decoderClass);
120 }
121 }
122
123
124
125
126
127
128 public void addMessageDecoder(MessageDecoder decoder) {
129 addMessageDecoder(new SingletonMessageDecoderFactory(decoder));
130 }
131
132
133
134
135
136
137 public void addMessageDecoder(MessageDecoderFactory factory) {
138 if (factory == null) {
139 throw new IllegalArgumentException("factory");
140 }
141
142 MessageDecoderFactorytory.html#MessageDecoderFactory">MessageDecoderFactory[] newDecoderFactories = new MessageDecoderFactory[decoderFactories.length + 1];
143 System.arraycopy(decoderFactories, 0, newDecoderFactories, 0, decoderFactories.length);
144 newDecoderFactories[decoderFactories.length] = factory;
145 this.decoderFactories = newDecoderFactories;
146 }
147
148
149
150
151 @Override
152 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
153 State state = getState(session);
154
155 if (state.currentDecoder == null) {
156 MessageDecoder[] decoders = state.decoders;
157 int undecodables = 0;
158
159 for (int i = decoders.length - 1; i >= 0; i--) {
160 MessageDecoder decoder = decoders[i];
161 int limit = in.limit();
162 int pos = in.position();
163
164 MessageDecoderResult result;
165
166 try {
167 result = decoder.decodable(session, in);
168 } finally {
169 in.position(pos);
170 in.limit(limit);
171 }
172
173 if (result == MessageDecoder.OK) {
174 state.currentDecoder = decoder;
175 break;
176 } else if (result == MessageDecoder.NOT_OK) {
177 undecodables++;
178 } else if (result != MessageDecoder.NEED_DATA) {
179 throw new IllegalStateException("Unexpected decode result (see your decodable()): " + result);
180 }
181 }
182
183 if (undecodables == decoders.length) {
184
185 String dump = in.getHexDump();
186 in.position(in.limit());
187 ProtocolDecoderExceptionolDecoderException.html#ProtocolDecoderException">ProtocolDecoderException e = new ProtocolDecoderException("No appropriate message decoder: " + dump);
188 e.setHexdump(dump);
189 throw e;
190 }
191
192 if (state.currentDecoder == null) {
193
194 return false;
195 }
196 }
197
198 try {
199 MessageDecoderResult result = state.currentDecoder.decode(session, in, out);
200 if (result == MessageDecoder.OK) {
201 state.currentDecoder = null;
202 return true;
203 } else if (result == MessageDecoder.NEED_DATA) {
204 return false;
205 } else if (result == MessageDecoder.NOT_OK) {
206 state.currentDecoder = null;
207 throw new ProtocolDecoderException("Message decoder returned NOT_OK.");
208 } else {
209 state.currentDecoder = null;
210 throw new IllegalStateException("Unexpected decode result (see your decode()): " + result);
211 }
212 } catch (Exception e) {
213 state.currentDecoder = null;
214 throw e;
215 }
216 }
217
218
219
220
221 @Override
222 public void finishDecode(IoSession session, ProtocolDecoderOutput out) throws Exception {
223 super.finishDecode(session, out);
224 State state = getState(session);
225 MessageDecoder currentDecoder = state.currentDecoder;
226 if (currentDecoder == null) {
227 return;
228 }
229
230 currentDecoder.finishDecode(session, out);
231 }
232
233
234
235
236 @Override
237 public void dispose(IoSession session) throws Exception {
238 super.dispose(session);
239 session.removeAttribute(STATE);
240 }
241
242 private State getState(IoSession session) throws Exception {
243 State state = (State) session.getAttribute(STATE);
244
245 if (state == null) {
246 state = new State();
247 State oldState = (State) session.setAttributeIfAbsent(STATE, state);
248
249 if (oldState != null) {
250 state = oldState;
251 }
252 }
253
254 return state;
255 }
256
257 private class State {
258 private final MessageDecoder[] decoders;
259
260 private MessageDecoder currentDecoder;
261
262 private State() throws Exception {
263 MessageDecoderFactory[] factories = DemuxingProtocolDecoder.this.decoderFactories;
264 decoders = new MessageDecoder[factories.length];
265
266 for (int i = factories.length - 1; i >= 0; i--) {
267 decoders[i] = factories[i].getDecoder();
268 }
269 }
270 }
271
272 private static class SingletonMessageDecoderFactory implements MessageDecoderFactory {
273 private final MessageDecoder decoder;
274
275 private SingletonMessageDecoderFactory(MessageDecoder decoder) {
276 if (decoder == null) {
277 throw new IllegalArgumentException("decoder");
278 }
279 this.decoder = decoder;
280 }
281
282
283
284
285 @Override
286 public MessageDecoder getDecoder() {
287 return decoder;
288 }
289 }
290
291 private static class DefaultConstructorMessageDecoderFactory implements MessageDecoderFactory {
292 private final Class<?> decoderClass;
293
294 private DefaultConstructorMessageDecoderFactory(Class<?> decoderClass) {
295 if (decoderClass == null) {
296 throw new IllegalArgumentException("decoderClass");
297 }
298
299 if (!MessageDecoder.class.isAssignableFrom(decoderClass)) {
300 throw new IllegalArgumentException("decoderClass is not assignable to MessageDecoder");
301 }
302 this.decoderClass = decoderClass;
303 }
304
305
306
307
308 @Override
309 public MessageDecoder getDecoder() throws Exception {
310 return (MessageDecoder) decoderClass.newInstance();
311 }
312 }
313 }