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