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;
21
22 import java.net.SocketAddress;
23 import java.util.Queue;
24
25 import org.apache.mina.core.buffer.IoBuffer;
26 import org.apache.mina.core.file.FileRegion;
27 import org.apache.mina.core.filterchain.IoFilter;
28 import org.apache.mina.core.filterchain.IoFilterAdapter;
29 import org.apache.mina.core.filterchain.IoFilterChain;
30 import org.apache.mina.core.future.DefaultWriteFuture;
31 import org.apache.mina.core.future.WriteFuture;
32 import org.apache.mina.core.session.AttributeKey;
33 import org.apache.mina.core.session.IoSession;
34 import org.apache.mina.core.write.DefaultWriteRequest;
35 import org.apache.mina.core.write.NothingWrittenException;
36 import org.apache.mina.core.write.WriteRequest;
37 import org.apache.mina.core.write.WriteRequestWrapper;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41
42
43
44
45
46
47
48
49
50 public class ProtocolCodecFilter extends IoFilterAdapter {
51
52 private static final Class<?>[] EMPTY_PARAMS = new Class[0];
53 private static final IoBuffer EMPTY_BUFFER = IoBuffer.wrap(new byte[0]);
54
55 private final AttributeKey ENCODER = new AttributeKey(getClass(), "encoder");
56 private final AttributeKey DECODER = new AttributeKey(getClass(), "decoder");
57 private final AttributeKey DECODER_OUT = new AttributeKey(getClass(), "decoderOut");
58 private final AttributeKey ENCODER_OUT = new AttributeKey(getClass(), "encoderOut");
59
60
61 private final ProtocolCodecFactory factory;
62
63 private final Logger logger = LoggerFactory.getLogger(getClass());
64
65
66
67
68
69
70
71
72 public ProtocolCodecFilter(ProtocolCodecFactory factory) {
73 if (factory == null) {
74 throw new NullPointerException("factory");
75 }
76 this.factory = factory;
77 }
78
79
80
81
82
83
84
85
86
87
88 public ProtocolCodecFilter(final ProtocolEncoder encoder,
89 final ProtocolDecoder decoder) {
90 if (encoder == null) {
91 throw new NullPointerException("encoder");
92 }
93 if (decoder == null) {
94 throw new NullPointerException("decoder");
95 }
96
97
98 this.factory = new ProtocolCodecFactory() {
99 public ProtocolEncoder getEncoder(IoSession session) {
100 return encoder;
101 }
102
103 public ProtocolDecoder getDecoder(IoSession session) {
104 return decoder;
105 }
106 };
107 }
108
109
110
111
112
113
114
115
116
117
118 public ProtocolCodecFilter(
119 final Class<? extends ProtocolEncoder> encoderClass,
120 final Class<? extends ProtocolDecoder> decoderClass) {
121 if (encoderClass == null) {
122 throw new NullPointerException("encoderClass");
123 }
124 if (decoderClass == null) {
125 throw new NullPointerException("decoderClass");
126 }
127 if (!ProtocolEncoder.class.isAssignableFrom(encoderClass)) {
128 throw new IllegalArgumentException("encoderClass: "
129 + encoderClass.getName());
130 }
131 if (!ProtocolDecoder.class.isAssignableFrom(decoderClass)) {
132 throw new IllegalArgumentException("decoderClass: "
133 + decoderClass.getName());
134 }
135 try {
136 encoderClass.getConstructor(EMPTY_PARAMS);
137 } catch (NoSuchMethodException e) {
138 throw new IllegalArgumentException(
139 "encoderClass doesn't have a public default constructor.");
140 }
141 try {
142 decoderClass.getConstructor(EMPTY_PARAMS);
143 } catch (NoSuchMethodException e) {
144 throw new IllegalArgumentException(
145 "decoderClass doesn't have a public default constructor.");
146 }
147
148
149
150 this.factory = new ProtocolCodecFactory() {
151 public ProtocolEncoder getEncoder(IoSession session) throws Exception {
152 return encoderClass.newInstance();
153 }
154
155 public ProtocolDecoder getDecoder(IoSession session) throws Exception {
156 return decoderClass.newInstance();
157 }
158 };
159 }
160
161
162
163
164
165
166
167
168 public ProtocolEncoder getEncoder(IoSession session) {
169 return (ProtocolEncoder) session.getAttribute(ENCODER);
170 }
171
172 @Override
173 public void onPreAdd(IoFilterChain parent, String name,
174 NextFilter nextFilter) throws Exception {
175 if (parent.contains(this)) {
176 throw new IllegalArgumentException(
177 "You can't add the same filter instance more than once. Create another instance and add it.");
178 }
179
180
181 initCodec(parent.getSession());
182 }
183
184 @Override
185 public void onPostRemove(IoFilterChain parent, String name,
186 NextFilter nextFilter) throws Exception {
187
188 disposeCodec(parent.getSession());
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203 @Override
204 public void messageReceived(NextFilter nextFilter, IoSession session,
205 Object message) throws Exception {
206 if (!(message instanceof IoBuffer)) {
207 nextFilter.messageReceived(session, message);
208 return;
209 }
210
211 IoBuffer in = (IoBuffer) message;
212 ProtocolDecoder decoder = getDecoder(session);
213 ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
214
215
216
217
218
219 while (in.hasRemaining()) {
220 int oldPos = in.position();
221 try {
222 synchronized (decoderOut) {
223
224 decoder.decode(session, in, decoderOut);
225 }
226
227
228 decoderOut.flush(nextFilter, session);
229 } catch (Throwable t) {
230 ProtocolDecoderException pde;
231 if (t instanceof ProtocolDecoderException) {
232 pde = (ProtocolDecoderException) t;
233 } else {
234 pde = new ProtocolDecoderException(t);
235 }
236
237 if (pde.getHexdump() == null) {
238
239 int curPos = in.position();
240 in.position(oldPos);
241 pde.setHexdump(in.getHexDump());
242 in.position(curPos);
243 }
244
245
246 decoderOut.flush(nextFilter, session);
247 nextFilter.exceptionCaught(session, pde);
248
249
250
251
252
253 if (!(t instanceof RecoverableProtocolDecoderException) ||
254 (in.position() == oldPos)) {
255 break;
256 }
257 }
258 }
259 }
260
261 @Override
262 public void messageSent(NextFilter nextFilter, IoSession session,
263 WriteRequest writeRequest) throws Exception {
264 if (writeRequest instanceof EncodedWriteRequest) {
265 return;
266 }
267
268 if (!(writeRequest instanceof MessageWriteRequest)) {
269 nextFilter.messageSent(session, writeRequest);
270 return;
271 }
272
273 MessageWriteRequest wrappedRequest = (MessageWriteRequest) writeRequest;
274 nextFilter.messageSent(session, wrappedRequest.getParentRequest());
275 }
276
277 @Override
278 public void filterWrite(NextFilter nextFilter, IoSession session,
279 WriteRequest writeRequest) throws Exception {
280 Object message = writeRequest.getMessage();
281
282
283
284 if (message instanceof IoBuffer || message instanceof FileRegion) {
285 nextFilter.filterWrite(session, writeRequest);
286 return;
287 }
288
289
290 ProtocolEncoder encoder = getEncoder(session);
291
292 ProtocolEncoderOutput encoderOut = getEncoderOut(session,
293 nextFilter, writeRequest);
294
295 try {
296
297 encoder.encode(session, message, encoderOut);
298
299
300 ((ProtocolEncoderOutputImpl)encoderOut).flushWithoutFuture();
301
302
303 nextFilter.filterWrite(session, new MessageWriteRequest(
304 writeRequest));
305 } catch (Throwable t) {
306 ProtocolEncoderException pee;
307
308
309 if (t instanceof ProtocolEncoderException) {
310 pee = (ProtocolEncoderException) t;
311 } else {
312 pee = new ProtocolEncoderException(t);
313 }
314
315 throw pee;
316 }
317 }
318
319
320
321
322
323
324
325
326
327
328
329
330 @Override
331 public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
332
333 initCodec(session);
334
335
336 nextFilter.sessionCreated(session);
337 }
338
339 @Override
340 public void sessionClosed(NextFilter nextFilter, IoSession session)
341 throws Exception {
342
343 ProtocolDecoder decoder = getDecoder(session);
344 ProtocolDecoderOutput decoderOut = getDecoderOut(session, nextFilter);
345
346 try {
347 decoder.finishDecode(session, decoderOut);
348 } catch (Throwable t) {
349 ProtocolDecoderException pde;
350 if (t instanceof ProtocolDecoderException) {
351 pde = (ProtocolDecoderException) t;
352 } else {
353 pde = new ProtocolDecoderException(t);
354 }
355 throw pde;
356 } finally {
357
358 disposeCodec(session);
359 decoderOut.flush(nextFilter, session);
360 }
361
362
363 nextFilter.sessionClosed(session);
364 }
365
366 private static class EncodedWriteRequest extends DefaultWriteRequest {
367 private EncodedWriteRequest(Object encodedMessage,
368 WriteFuture future, SocketAddress destination) {
369 super(encodedMessage, future, destination);
370 }
371 }
372
373 private static class MessageWriteRequest extends WriteRequestWrapper {
374 private MessageWriteRequest(WriteRequest writeRequest) {
375 super(writeRequest);
376 }
377
378 @Override
379 public Object getMessage() {
380 return EMPTY_BUFFER;
381 }
382 }
383
384 private static class ProtocolDecoderOutputImpl extends
385 AbstractProtocolDecoderOutput {
386 public ProtocolDecoderOutputImpl() {
387 }
388
389 public void flush(NextFilter nextFilter, IoSession session) {
390 Queue<Object> messageQueue = getMessageQueue();
391 while (!messageQueue.isEmpty()) {
392 nextFilter.messageReceived(session, messageQueue.poll());
393 }
394 }
395 }
396
397 private static class ProtocolEncoderOutputImpl extends
398 AbstractProtocolEncoderOutput {
399 private final IoSession session;
400
401 private final NextFilter nextFilter;
402
403 private final WriteRequest writeRequest;
404
405 public ProtocolEncoderOutputImpl(IoSession session,
406 NextFilter nextFilter, WriteRequest writeRequest) {
407 this.session = session;
408 this.nextFilter = nextFilter;
409 this.writeRequest = writeRequest;
410 }
411
412 public WriteFuture flush() {
413 Queue<Object> bufferQueue = getMessageQueue();
414 WriteFuture future = null;
415 for (;;) {
416 Object encodedMessage = bufferQueue.poll();
417 if (encodedMessage == null) {
418 break;
419 }
420
421
422 if (!(encodedMessage instanceof IoBuffer) ||
423 ((IoBuffer) encodedMessage).hasRemaining()) {
424 future = new DefaultWriteFuture(session);
425 nextFilter.filterWrite(session, new EncodedWriteRequest(encodedMessage,
426 future, writeRequest.getDestination()));
427 }
428 }
429
430 if (future == null) {
431 future = DefaultWriteFuture.newNotWrittenFuture(
432 session, new NothingWrittenException(writeRequest));
433 }
434
435 return future;
436 }
437
438 public void flushWithoutFuture() {
439 Queue<Object> bufferQueue = getMessageQueue();
440 for (;;) {
441 Object encodedMessage = bufferQueue.poll();
442 if (encodedMessage == null) {
443 break;
444 }
445
446
447 if (!(encodedMessage instanceof IoBuffer) ||
448 ((IoBuffer) encodedMessage).hasRemaining()) {
449 SocketAddress destination = writeRequest.getDestination();
450 WriteRequest writeRequest = new EncodedWriteRequest(
451 encodedMessage, null, destination);
452 nextFilter.filterWrite(session, writeRequest);
453 }
454 }
455 }
456 }
457
458
459
460
461
462
463 private void initCodec(IoSession session) throws Exception {
464
465 ProtocolDecoder decoder = factory.getDecoder(session);
466 session.setAttribute(DECODER, decoder);
467
468
469 ProtocolEncoder encoder = factory.getEncoder(session);
470 session.setAttribute(ENCODER, encoder);
471 }
472
473
474
475
476
477 private void disposeCodec(IoSession session) {
478
479
480 disposeEncoder(session);
481 disposeDecoder(session);
482
483
484 disposeDecoderOut(session);
485 }
486
487
488
489
490
491
492 private void disposeEncoder(IoSession session) {
493 ProtocolEncoder encoder = (ProtocolEncoder) session
494 .removeAttribute(ENCODER);
495 if (encoder == null) {
496 return;
497 }
498
499 try {
500 encoder.dispose(session);
501 } catch (Throwable t) {
502 logger.warn(
503 "Failed to dispose: " + encoder.getClass().getName() + " (" + encoder + ')');
504 }
505 }
506
507
508
509
510
511
512
513 private ProtocolDecoder getDecoder(IoSession session) {
514 return (ProtocolDecoder) session.getAttribute(DECODER);
515 }
516
517
518
519
520
521
522 private void disposeDecoder(IoSession session) {
523 ProtocolDecoder decoder = (ProtocolDecoder) session
524 .removeAttribute(DECODER);
525 if (decoder == null) {
526 return;
527 }
528
529 try {
530 decoder.dispose(session);
531 } catch (Throwable t) {
532 logger.warn(
533 "Falied to dispose: " + decoder.getClass().getName() + " (" + decoder + ')');
534 }
535 }
536
537
538
539
540
541 private ProtocolDecoderOutput getDecoderOut(IoSession session,
542 NextFilter nextFilter) {
543 ProtocolDecoderOutput out = (ProtocolDecoderOutput) session.getAttribute(DECODER_OUT);
544
545 if (out == null) {
546
547 out = new ProtocolDecoderOutputImpl();
548 session.setAttribute(DECODER_OUT, out);
549 }
550
551 return out;
552 }
553
554 private ProtocolEncoderOutput getEncoderOut(IoSession session,
555 NextFilter nextFilter, WriteRequest writeRequest) {
556 ProtocolEncoderOutput out = (ProtocolEncoderOutput) session.getAttribute(ENCODER_OUT);
557
558 if (out == null) {
559
560 out = new ProtocolEncoderOutputImpl(session, nextFilter, writeRequest);
561 session.setAttribute(ENCODER_OUT, out);
562 }
563
564 return out;
565 }
566
567
568
569
570 private void disposeDecoderOut(IoSession session) {
571 session.removeAttribute(DECODER_OUT);
572 }
573 }