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