1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.filterchain;
21
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.ConcurrentHashMap;
26
27 import org.apache.mina.core.buffer.IoBuffer;
28 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
29 import org.apache.mina.core.future.ConnectFuture;
30 import org.apache.mina.core.future.IoFuture;
31 import org.apache.mina.core.session.AbstractIoSession;
32 import org.apache.mina.core.session.AttributeKey;
33 import org.apache.mina.core.session.IdleStatus;
34 import org.apache.mina.core.session.IoSession;
35 import org.apache.mina.core.write.WriteRequest;
36 import org.apache.mina.core.write.WriteRequestQueue;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
41
42
43
44
45
46
47 public class DefaultIoFilterChain implements IoFilterChain {
48
49
50
51
52
53
54 public static final AttributeKey SESSION_CREATED_FUTURE = new AttributeKey(DefaultIoFilterChain.class,
55 "connectFuture");
56
57
58 private final AbstractIoSession session;
59
60 private final Map<String, Entry> name2entry = new ConcurrentHashMap<String, Entry>();
61
62
63 private final EntryImpl head;
64
65
66 private final EntryImpl tail;
67
68
69 private final static Logger LOGGER = LoggerFactory.getLogger(DefaultIoFilterChain.class);
70
71
72
73
74
75
76
77 public DefaultIoFilterChain(AbstractIoSession session) {
78 if (session == null) {
79 throw new IllegalArgumentException("session");
80 }
81
82 this.session = session;
83 head = new EntryImpl(null, null, "head", new HeadFilter());
84 tail = new EntryImpl(head, null, "tail", new TailFilter());
85 head.nextEntry = tail;
86 }
87
88 public IoSession getSession() {
89 return session;
90 }
91
92 public Entry getEntry(String name) {
93 Entry e = name2entry.get(name);
94 if (e == null) {
95 return null;
96 }
97 return e;
98 }
99
100 public Entry getEntry(IoFilter filter) {
101 EntryImpl e = head.nextEntry;
102 while (e != tail) {
103 if (e.getFilter() == filter) {
104 return e;
105 }
106 e = e.nextEntry;
107 }
108 return null;
109 }
110
111 public Entry getEntry(Class<? extends IoFilter> filterType) {
112 EntryImpl e = head.nextEntry;
113 while (e != tail) {
114 if (filterType.isAssignableFrom(e.getFilter().getClass())) {
115 return e;
116 }
117 e = e.nextEntry;
118 }
119 return null;
120 }
121
122 public IoFilter get(String name) {
123 Entry e = getEntry(name);
124 if (e == null) {
125 return null;
126 }
127
128 return e.getFilter();
129 }
130
131 public IoFilter get(Class<? extends IoFilter> filterType) {
132 Entry e = getEntry(filterType);
133 if (e == null) {
134 return null;
135 }
136
137 return e.getFilter();
138 }
139
140 public NextFilter getNextFilter(String name) {
141 Entry e = getEntry(name);
142 if (e == null) {
143 return null;
144 }
145
146 return e.getNextFilter();
147 }
148
149 public NextFilter getNextFilter(IoFilter filter) {
150 Entry e = getEntry(filter);
151 if (e == null) {
152 return null;
153 }
154
155 return e.getNextFilter();
156 }
157
158 public NextFilter getNextFilter(Class<? extends IoFilter> filterType) {
159 Entry e = getEntry(filterType);
160 if (e == null) {
161 return null;
162 }
163
164 return e.getNextFilter();
165 }
166
167 public synchronized void addFirst(String name, IoFilter filter) {
168 checkAddable(name);
169 register(head, name, filter);
170 }
171
172 public synchronized void addLast(String name, IoFilter filter) {
173 checkAddable(name);
174 register(tail.prevEntry, name, filter);
175 }
176
177 public synchronized void addBefore(String baseName, String name, IoFilter filter) {
178 EntryImpl baseEntry = checkOldName(baseName);
179 checkAddable(name);
180 register(baseEntry.prevEntry, name, filter);
181 }
182
183 public synchronized void addAfter(String baseName, String name, IoFilter filter) {
184 EntryImpl baseEntry = checkOldName(baseName);
185 checkAddable(name);
186 register(baseEntry, name, filter);
187 }
188
189 public synchronized IoFilter remove(String name) {
190 EntryImpl entry = checkOldName(name);
191 deregister(entry);
192 return entry.getFilter();
193 }
194
195 public synchronized void remove(IoFilter filter) {
196 EntryImpl e = head.nextEntry;
197 while (e != tail) {
198 if (e.getFilter() == filter) {
199 deregister(e);
200 return;
201 }
202 e = e.nextEntry;
203 }
204 throw new IllegalArgumentException("Filter not found: " + filter.getClass().getName());
205 }
206
207 public synchronized IoFilter remove(Class<? extends IoFilter> filterType) {
208 EntryImpl e = head.nextEntry;
209 while (e != tail) {
210 if (filterType.isAssignableFrom(e.getFilter().getClass())) {
211 IoFilter oldFilter = e.getFilter();
212 deregister(e);
213 return oldFilter;
214 }
215 e = e.nextEntry;
216 }
217 throw new IllegalArgumentException("Filter not found: " + filterType.getName());
218 }
219
220 public synchronized IoFilter replace(String name, IoFilter newFilter) {
221 EntryImpl entry = checkOldName(name);
222 IoFilter oldFilter = entry.getFilter();
223 entry.setFilter(newFilter);
224 return oldFilter;
225 }
226
227 public synchronized void replace(IoFilter oldFilter, IoFilter newFilter) {
228 EntryImpl e = head.nextEntry;
229 while (e != tail) {
230 if (e.getFilter() == oldFilter) {
231 e.setFilter(newFilter);
232 return;
233 }
234 e = e.nextEntry;
235 }
236 throw new IllegalArgumentException("Filter not found: " + oldFilter.getClass().getName());
237 }
238
239 public synchronized IoFilter replace(Class<? extends IoFilter> oldFilterType, IoFilter newFilter) {
240 EntryImpl e = head.nextEntry;
241 while (e != tail) {
242 if (oldFilterType.isAssignableFrom(e.getFilter().getClass())) {
243 IoFilter oldFilter = e.getFilter();
244 e.setFilter(newFilter);
245 return oldFilter;
246 }
247 e = e.nextEntry;
248 }
249 throw new IllegalArgumentException("Filter not found: " + oldFilterType.getName());
250 }
251
252 public synchronized void clear() throws Exception {
253 List<IoFilterChain.Entry> l = new ArrayList<IoFilterChain.Entry>(name2entry.values());
254 for (IoFilterChain.Entry entry : l) {
255 try {
256 deregister((EntryImpl) entry);
257 } catch (Exception e) {
258 throw new IoFilterLifeCycleException("clear(): " + entry.getName() + " in " + getSession(), e);
259 }
260 }
261 }
262
263 private void register(EntryImpl prevEntry, String name, IoFilter filter) {
264 EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry, name, filter);
265
266 try {
267 filter.onPreAdd(this, name, newEntry.getNextFilter());
268 } catch (Exception e) {
269 throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':' + filter + " in " + getSession(), e);
270 }
271
272 prevEntry.nextEntry.prevEntry = newEntry;
273 prevEntry.nextEntry = newEntry;
274 name2entry.put(name, newEntry);
275
276 try {
277 filter.onPostAdd(this, name, newEntry.getNextFilter());
278 } catch (Exception e) {
279 deregister0(newEntry);
280 throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':' + filter + " in " + getSession(), e);
281 }
282 }
283
284 private void deregister(EntryImpl entry) {
285 IoFilter filter = entry.getFilter();
286
287 try {
288 filter.onPreRemove(this, entry.getName(), entry.getNextFilter());
289 } catch (Exception e) {
290 throw new IoFilterLifeCycleException("onPreRemove(): " + entry.getName() + ':' + filter + " in "
291 + getSession(), e);
292 }
293
294 deregister0(entry);
295
296 try {
297 filter.onPostRemove(this, entry.getName(), entry.getNextFilter());
298 } catch (Exception e) {
299 throw new IoFilterLifeCycleException("onPostRemove(): " + entry.getName() + ':' + filter + " in "
300 + getSession(), e);
301 }
302 }
303
304 private void deregister0(EntryImpl entry) {
305 EntryImpl prevEntry = entry.prevEntry;
306 EntryImpl nextEntry = entry.nextEntry;
307 prevEntry.nextEntry = nextEntry;
308 nextEntry.prevEntry = prevEntry;
309
310 name2entry.remove(entry.name);
311 }
312
313
314
315
316
317
318 private EntryImpl checkOldName(String baseName) {
319 EntryImpl e = (EntryImpl) name2entry.get(baseName);
320 if (e == null) {
321 throw new IllegalArgumentException("Filter not found:" + baseName);
322 }
323 return e;
324 }
325
326
327
328
329 private void checkAddable(String name) {
330 if (name2entry.containsKey(name)) {
331 throw new IllegalArgumentException("Other filter is using the same name '" + name + "'");
332 }
333 }
334
335 public void fireSessionCreated() {
336 Entry head = this.head;
337 callNextSessionCreated(head, session);
338 }
339
340 private void callNextSessionCreated(Entry entry, IoSession session) {
341 try {
342 IoFilter filter = entry.getFilter();
343 NextFilter nextFilter = entry.getNextFilter();
344 filter.sessionCreated(nextFilter, session);
345 } catch (Throwable e) {
346 fireExceptionCaught(e);
347 }
348 }
349
350 public void fireSessionOpened() {
351 Entry head = this.head;
352 callNextSessionOpened(head, session);
353 }
354
355 private void callNextSessionOpened(Entry entry, IoSession session) {
356 try {
357 IoFilter filter = entry.getFilter();
358 NextFilter nextFilter = entry.getNextFilter();
359 filter.sessionOpened(nextFilter, session);
360 } catch (Throwable e) {
361 fireExceptionCaught(e);
362 }
363 }
364
365 public void fireSessionClosed() {
366
367 try {
368 session.getCloseFuture().setClosed();
369 } catch (Throwable t) {
370 fireExceptionCaught(t);
371 }
372
373
374 Entry head = this.head;
375 callNextSessionClosed(head, session);
376 }
377
378 private void callNextSessionClosed(Entry entry, IoSession session) {
379 try {
380 IoFilter filter = entry.getFilter();
381 NextFilter nextFilter = entry.getNextFilter();
382 filter.sessionClosed(nextFilter, session);
383 } catch (Throwable e) {
384 fireExceptionCaught(e);
385 }
386 }
387
388 public void fireSessionIdle(IdleStatus status) {
389 session.increaseIdleCount(status, System.currentTimeMillis());
390 Entry head = this.head;
391 callNextSessionIdle(head, session, status);
392 }
393
394 private void callNextSessionIdle(Entry entry, IoSession session, IdleStatus status) {
395 try {
396 IoFilter filter = entry.getFilter();
397 NextFilter nextFilter = entry.getNextFilter();
398 filter.sessionIdle(nextFilter, session, status);
399 } catch (Throwable e) {
400 fireExceptionCaught(e);
401 }
402 }
403
404 public void fireMessageReceived(Object message) {
405 if (message instanceof IoBuffer) {
406 session.increaseReadBytes(((IoBuffer) message).remaining(), System.currentTimeMillis());
407 }
408
409 Entry head = this.head;
410 callNextMessageReceived(head, session, message);
411 }
412
413 private void callNextMessageReceived(Entry entry, IoSession session, Object message) {
414 try {
415 IoFilter filter = entry.getFilter();
416 NextFilter nextFilter = entry.getNextFilter();
417 filter.messageReceived(nextFilter, session, message);
418 } catch (Throwable e) {
419 fireExceptionCaught(e);
420 }
421 }
422
423 public void fireMessageSent(WriteRequest request) {
424 session.increaseWrittenMessages(request, System.currentTimeMillis());
425
426 try {
427 request.getFuture().setWritten();
428 } catch (Throwable t) {
429 fireExceptionCaught(t);
430 }
431
432 Entry head = this.head;
433
434 if (!request.isEncoded()) {
435 callNextMessageSent(head, session, request);
436 }
437 }
438
439 private void callNextMessageSent(Entry entry, IoSession session, WriteRequest writeRequest) {
440 try {
441 IoFilter filter = entry.getFilter();
442 NextFilter nextFilter = entry.getNextFilter();
443 filter.messageSent(nextFilter, session, writeRequest);
444 } catch (Throwable e) {
445 fireExceptionCaught(e);
446 }
447 }
448
449 public void fireExceptionCaught(Throwable cause) {
450 Entry head = this.head;
451 callNextExceptionCaught(head, session, cause);
452 }
453
454 private void callNextExceptionCaught(Entry entry, IoSession session, Throwable cause) {
455
456 ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);
457 if (future == null) {
458 try {
459 IoFilter filter = entry.getFilter();
460 NextFilter nextFilter = entry.getNextFilter();
461 filter.exceptionCaught(nextFilter, session, cause);
462 } catch (Throwable e) {
463 LOGGER.warn("Unexpected exception from exceptionCaught handler.", e);
464 }
465 } else {
466
467
468 session.close(true);
469 future.setException(cause);
470 }
471 }
472
473 public void fireFilterWrite(WriteRequest writeRequest) {
474 Entry tail = this.tail;
475 callPreviousFilterWrite(tail, session, writeRequest);
476 }
477
478 private void callPreviousFilterWrite(Entry entry, IoSession session, WriteRequest writeRequest) {
479 try {
480 IoFilter filter = entry.getFilter();
481 NextFilter nextFilter = entry.getNextFilter();
482 filter.filterWrite(nextFilter, session, writeRequest);
483 } catch (Throwable e) {
484 writeRequest.getFuture().setException(e);
485 fireExceptionCaught(e);
486 }
487 }
488
489 public void fireFilterClose() {
490 Entry tail = this.tail;
491 callPreviousFilterClose(tail, session);
492 }
493
494 private void callPreviousFilterClose(Entry entry, IoSession session) {
495 try {
496 IoFilter filter = entry.getFilter();
497 NextFilter nextFilter = entry.getNextFilter();
498 filter.filterClose(nextFilter, session);
499 } catch (Throwable e) {
500 fireExceptionCaught(e);
501 }
502 }
503
504 public List<Entry> getAll() {
505 List<Entry> list = new ArrayList<Entry>();
506 EntryImpl e = head.nextEntry;
507 while (e != tail) {
508 list.add(e);
509 e = e.nextEntry;
510 }
511
512 return list;
513 }
514
515 public List<Entry> getAllReversed() {
516 List<Entry> list = new ArrayList<Entry>();
517 EntryImpl e = tail.prevEntry;
518 while (e != head) {
519 list.add(e);
520 e = e.prevEntry;
521 }
522 return list;
523 }
524
525 public boolean contains(String name) {
526 return getEntry(name) != null;
527 }
528
529 public boolean contains(IoFilter filter) {
530 return getEntry(filter) != null;
531 }
532
533 public boolean contains(Class<? extends IoFilter> filterType) {
534 return getEntry(filterType) != null;
535 }
536
537 @Override
538 public String toString() {
539 StringBuilder buf = new StringBuilder();
540 buf.append("{ ");
541
542 boolean empty = true;
543
544 EntryImpl e = head.nextEntry;
545 while (e != tail) {
546 if (!empty) {
547 buf.append(", ");
548 } else {
549 empty = false;
550 }
551
552 buf.append('(');
553 buf.append(e.getName());
554 buf.append(':');
555 buf.append(e.getFilter());
556 buf.append(')');
557
558 e = e.nextEntry;
559 }
560
561 if (empty) {
562 buf.append("empty");
563 }
564
565 buf.append(" }");
566
567 return buf.toString();
568 }
569
570 private class HeadFilter extends IoFilterAdapter {
571 @SuppressWarnings("unchecked")
572 @Override
573 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
574
575 AbstractIoSession s = (AbstractIoSession) session;
576
577
578 if (writeRequest.getMessage() instanceof IoBuffer) {
579 IoBuffer buffer = (IoBuffer) writeRequest.getMessage();
580
581
582
583 buffer.mark();
584 int remaining = buffer.remaining();
585
586 if (remaining == 0) {
587
588
589 s.increaseScheduledWriteMessages();
590 } else {
591 s.increaseScheduledWriteBytes(remaining);
592 }
593 } else {
594 s.increaseScheduledWriteMessages();
595 }
596
597 WriteRequestQueue writeRequestQueue = s.getWriteRequestQueue();
598
599 if (!s.isWriteSuspended()) {
600 if (writeRequestQueue.size() == 0) {
601
602 s.getProcessor().write(s, writeRequest);
603 } else {
604 s.getWriteRequestQueue().offer(s, writeRequest);
605 s.getProcessor().flush(s);
606 }
607 } else {
608 s.getWriteRequestQueue().offer(s, writeRequest);
609 }
610 }
611
612 @SuppressWarnings("unchecked")
613 @Override
614 public void filterClose(NextFilter nextFilter, IoSession session) throws Exception {
615 ((AbstractIoSession) session).getProcessor().remove(session);
616 }
617 }
618
619 private static class TailFilter extends IoFilterAdapter {
620 @Override
621 public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
622 try {
623 session.getHandler().sessionCreated(session);
624 } finally {
625
626 ConnectFuture future = (ConnectFuture) session.removeAttribute(SESSION_CREATED_FUTURE);
627 if (future != null) {
628 future.setSession(session);
629 }
630 }
631 }
632
633 @Override
634 public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
635 session.getHandler().sessionOpened(session);
636 }
637
638 @Override
639 public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
640 AbstractIoSession s = (AbstractIoSession) session;
641 try {
642 s.getHandler().sessionClosed(session);
643 } finally {
644 try {
645 s.getWriteRequestQueue().dispose(session);
646 } finally {
647 try {
648 s.getAttributeMap().dispose(session);
649 } finally {
650 try {
651
652 session.getFilterChain().clear();
653 } finally {
654 if (s.getConfig().isUseReadOperation()) {
655 s.offerClosedReadFuture();
656 }
657 }
658 }
659 }
660 }
661 }
662
663 @Override
664 public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) throws Exception {
665 session.getHandler().sessionIdle(session, status);
666 }
667
668 @Override
669 public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) throws Exception {
670 AbstractIoSession s = (AbstractIoSession) session;
671 try {
672 s.getHandler().exceptionCaught(s, cause);
673 } finally {
674 if (s.getConfig().isUseReadOperation()) {
675 s.offerFailedReadFuture(cause);
676 }
677 }
678 }
679
680 @Override
681 public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
682 AbstractIoSession s = (AbstractIoSession) session;
683 if (!(message instanceof IoBuffer)) {
684 s.increaseReadMessages(System.currentTimeMillis());
685 } else if (!((IoBuffer) message).hasRemaining()) {
686 s.increaseReadMessages(System.currentTimeMillis());
687 }
688
689 try {
690 session.getHandler().messageReceived(s, message);
691 } finally {
692 if (s.getConfig().isUseReadOperation()) {
693 s.offerReadFuture(message);
694 }
695 }
696 }
697
698 @Override
699 public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
700 session.getHandler().messageSent(session, writeRequest.getMessage());
701 }
702
703 @Override
704 public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception {
705 nextFilter.filterWrite(session, writeRequest);
706 }
707
708 @Override
709 public void filterClose(NextFilter nextFilter, IoSession session) throws Exception {
710 nextFilter.filterClose(session);
711 }
712 }
713
714 private class EntryImpl implements Entry {
715 private EntryImpl prevEntry;
716
717 private EntryImpl nextEntry;
718
719 private final String name;
720
721 private IoFilter filter;
722
723 private final NextFilter nextFilter;
724
725 private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry, String name, IoFilter filter) {
726 if (filter == null) {
727 throw new IllegalArgumentException("filter");
728 }
729 if (name == null) {
730 throw new IllegalArgumentException("name");
731 }
732
733 this.prevEntry = prevEntry;
734 this.nextEntry = nextEntry;
735 this.name = name;
736 this.filter = filter;
737 this.nextFilter = new NextFilter() {
738 public void sessionCreated(IoSession session) {
739 Entry nextEntry = EntryImpl.this.nextEntry;
740 callNextSessionCreated(nextEntry, session);
741 }
742
743 public void sessionOpened(IoSession session) {
744 Entry nextEntry = EntryImpl.this.nextEntry;
745 callNextSessionOpened(nextEntry, session);
746 }
747
748 public void sessionClosed(IoSession session) {
749 Entry nextEntry = EntryImpl.this.nextEntry;
750 callNextSessionClosed(nextEntry, session);
751 }
752
753 public void sessionIdle(IoSession session, IdleStatus status) {
754 Entry nextEntry = EntryImpl.this.nextEntry;
755 callNextSessionIdle(nextEntry, session, status);
756 }
757
758 public void exceptionCaught(IoSession session, Throwable cause) {
759 Entry nextEntry = EntryImpl.this.nextEntry;
760 callNextExceptionCaught(nextEntry, session, cause);
761 }
762
763 public void messageReceived(IoSession session, Object message) {
764 Entry nextEntry = EntryImpl.this.nextEntry;
765 callNextMessageReceived(nextEntry, session, message);
766 }
767
768 public void messageSent(IoSession session, WriteRequest writeRequest) {
769 Entry nextEntry = EntryImpl.this.nextEntry;
770 callNextMessageSent(nextEntry, session, writeRequest);
771 }
772
773 public void filterWrite(IoSession session, WriteRequest writeRequest) {
774 Entry nextEntry = EntryImpl.this.prevEntry;
775 callPreviousFilterWrite(nextEntry, session, writeRequest);
776 }
777
778 public void filterClose(IoSession session) {
779 Entry nextEntry = EntryImpl.this.prevEntry;
780 callPreviousFilterClose(nextEntry, session);
781 }
782
783 public String toString() {
784 return EntryImpl.this.nextEntry.name;
785 }
786 };
787 }
788
789 public String getName() {
790 return name;
791 }
792
793 public IoFilter getFilter() {
794 return filter;
795 }
796
797 private void setFilter(IoFilter filter) {
798 if (filter == null) {
799 throw new IllegalArgumentException("filter");
800 }
801
802 this.filter = filter;
803 }
804
805 public NextFilter getNextFilter() {
806 return nextFilter;
807 }
808
809 @Override
810 public String toString() {
811 StringBuilder sb = new StringBuilder();
812
813
814 sb.append("('").append(getName()).append('\'');
815
816
817 sb.append(", prev: '");
818
819 if (prevEntry != null) {
820 sb.append(prevEntry.name);
821 sb.append(':');
822 sb.append(prevEntry.getFilter().getClass().getSimpleName());
823 } else {
824 sb.append("null");
825 }
826
827
828 sb.append("', next: '");
829
830 if (nextEntry != null) {
831 sb.append(nextEntry.name);
832 sb.append(':');
833 sb.append(nextEntry.getFilter().getClass().getSimpleName());
834 } else {
835 sb.append("null");
836 }
837
838 sb.append("')");
839 return sb.toString();
840 }
841
842 public void addAfter(String name, IoFilter filter) {
843 DefaultIoFilterChain.this.addAfter(getName(), name, filter);
844 }
845
846 public void addBefore(String name, IoFilter filter) {
847 DefaultIoFilterChain.this.addBefore(getName(), name, filter);
848 }
849
850 public void remove() {
851 DefaultIoFilterChain.this.remove(getName());
852 }
853
854 public void replace(IoFilter newFilter) {
855 DefaultIoFilterChain.this.replace(getName(), newFilter);
856 }
857 }
858 }