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.List;
25 import java.util.Map;
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.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39
40
41
42
43
44
45
46 public class DefaultIoFilterChain implements IoFilterChain {
47
48
49
50
51
52
53 public static final AttributeKey SESSION_CREATED_FUTURE = new AttributeKey(
54 DefaultIoFilterChain.class, "connectFuture");
55
56
57 private final AbstractIoSession session;
58
59 private final Map<String, Entry> name2entry = new HashMap<String, Entry>();
60
61
62 private final EntryImpl head;
63
64
65 private final EntryImpl tail;
66
67
68 private final static Logger LOGGER = LoggerFactory.getLogger(DefaultIoFilterChain.class);
69
70
71
72
73
74
75
76
77 public DefaultIoFilterChain(AbstractIoSession session) {
78 if (session == null) {
79 throw new NullPointerException("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,
178 IoFilter filter) {
179 EntryImpl baseEntry = checkOldName(baseName);
180 checkAddable(name);
181 register(baseEntry.prevEntry, name, filter);
182 }
183
184 public synchronized void addAfter(String baseName, String name,
185 IoFilter filter) {
186 EntryImpl baseEntry = checkOldName(baseName);
187 checkAddable(name);
188 register(baseEntry, name, filter);
189 }
190
191 public synchronized IoFilter remove(String name) {
192 EntryImpl entry = checkOldName(name);
193 deregister(entry);
194 return entry.getFilter();
195 }
196
197 public synchronized void remove(IoFilter filter) {
198 EntryImpl e = head.nextEntry;
199 while (e != tail) {
200 if (e.getFilter() == filter) {
201 deregister(e);
202 return;
203 }
204 e = e.nextEntry;
205 }
206 throw new IllegalArgumentException("Filter not found: "
207 + filter.getClass().getName());
208 }
209
210 public synchronized IoFilter remove(Class<? extends IoFilter> filterType) {
211 EntryImpl e = head.nextEntry;
212 while (e != tail) {
213 if (filterType.isAssignableFrom(e.getFilter().getClass())) {
214 IoFilter oldFilter = e.getFilter();
215 deregister(e);
216 return oldFilter;
217 }
218 e = e.nextEntry;
219 }
220 throw new IllegalArgumentException("Filter not found: "
221 + filterType.getName());
222 }
223
224 public synchronized IoFilter replace(String name, IoFilter newFilter) {
225 EntryImpl entry = checkOldName(name);
226 IoFilter oldFilter = entry.getFilter();
227 entry.setFilter(newFilter);
228 return oldFilter;
229 }
230
231 public synchronized void replace(IoFilter oldFilter, IoFilter newFilter) {
232 EntryImpl e = head.nextEntry;
233 while (e != tail) {
234 if (e.getFilter() == oldFilter) {
235 e.setFilter(newFilter);
236 return;
237 }
238 e = e.nextEntry;
239 }
240 throw new IllegalArgumentException("Filter not found: "
241 + oldFilter.getClass().getName());
242 }
243
244 public synchronized IoFilter replace(
245 Class<? extends IoFilter> oldFilterType, IoFilter newFilter) {
246 EntryImpl e = head.nextEntry;
247 while (e != tail) {
248 if (oldFilterType.isAssignableFrom(e.getFilter().getClass())) {
249 IoFilter oldFilter = e.getFilter();
250 e.setFilter(newFilter);
251 return oldFilter;
252 }
253 e = e.nextEntry;
254 }
255 throw new IllegalArgumentException("Filter not found: "
256 + oldFilterType.getName());
257 }
258
259 public synchronized void clear() throws Exception {
260 List<IoFilterChain.Entry> l = new ArrayList<IoFilterChain.Entry>(
261 name2entry.values());
262 for (IoFilterChain.Entry entry : l) {
263 try {
264 deregister((EntryImpl) entry);
265 } catch (Exception e) {
266 throw new IoFilterLifeCycleException("clear(): "
267 + entry.getName() + " in " + getSession(), e);
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 private class HeadFilter extends IoFilterAdapter {
595 @SuppressWarnings("unchecked")
596 @Override
597 public void filterWrite(NextFilter nextFilter, IoSession session,
598 WriteRequest writeRequest) throws Exception {
599
600 AbstractIoSession s = (AbstractIoSession) session;
601
602
603 if (writeRequest.getMessage() instanceof IoBuffer) {
604 IoBuffer buffer = (IoBuffer) writeRequest.getMessage();
605
606
607
608 buffer.mark();
609 int remaining = buffer.remaining();
610 if (remaining == 0) {
611
612
613 s.increaseScheduledWriteMessages();
614 } else {
615 s.increaseScheduledWriteBytes(remaining);
616 }
617 } else {
618 s.increaseScheduledWriteMessages();
619 }
620
621 s.getWriteRequestQueue().offer(s, writeRequest);
622 if (!s.isWriteSuspended()) {
623 s.getProcessor().flush(s);
624 }
625 }
626
627 @SuppressWarnings("unchecked")
628 @Override
629 public void filterClose(NextFilter nextFilter, IoSession session)
630 throws Exception {
631 ((AbstractIoSession) session).getProcessor().remove(((AbstractIoSession) session));
632 }
633 }
634
635 private static class TailFilter extends IoFilterAdapter {
636 @Override
637 public void sessionCreated(NextFilter nextFilter, IoSession session)
638 throws Exception {
639 try {
640 session.getHandler().sessionCreated(session);
641 } finally {
642
643 ConnectFuture future = (ConnectFuture) session
644 .removeAttribute(SESSION_CREATED_FUTURE);
645 if (future != null) {
646 future.setSession(session);
647 }
648 }
649 }
650
651 @Override
652 public void sessionOpened(NextFilter nextFilter, IoSession session)
653 throws Exception {
654 session.getHandler().sessionOpened(session);
655 }
656
657 @Override
658 public void sessionClosed(NextFilter nextFilter, IoSession session)
659 throws Exception {
660 AbstractIoSession s = (AbstractIoSession) session;
661 try {
662 s.getHandler().sessionClosed(session);
663 } finally {
664 try {
665 s.getWriteRequestQueue().dispose(session);
666 } finally {
667 try {
668 s.getAttributeMap().dispose(session);
669 } finally {
670 try {
671
672 session.getFilterChain().clear();
673 } finally {
674 if (s.getConfig().isUseReadOperation()) {
675 s.offerClosedReadFuture();
676 }
677 }
678 }
679 }
680 }
681 }
682
683 @Override
684 public void sessionIdle(NextFilter nextFilter, IoSession session,
685 IdleStatus status) throws Exception {
686 session.getHandler().sessionIdle(session, status);
687 }
688
689 @Override
690 public void exceptionCaught(NextFilter nextFilter, IoSession session,
691 Throwable cause) throws Exception {
692 AbstractIoSession s = (AbstractIoSession) session;
693 try {
694 s.getHandler().exceptionCaught(s, cause);
695 } finally {
696 if (s.getConfig().isUseReadOperation()) {
697 s.offerFailedReadFuture(cause);
698 }
699 }
700 }
701
702 @Override
703 public void messageReceived(NextFilter nextFilter, IoSession session,
704 Object message) throws Exception {
705 AbstractIoSession s = (AbstractIoSession) session;
706 if (!(message instanceof IoBuffer)) {
707 s.increaseReadMessages(System.currentTimeMillis());
708 } else if (!((IoBuffer) message).hasRemaining()) {
709 s.increaseReadMessages(System.currentTimeMillis());
710 }
711
712 try {
713 session.getHandler().messageReceived(s, message);
714 } finally {
715 if (s.getConfig().isUseReadOperation()) {
716 s.offerReadFuture(message);
717 }
718 }
719 }
720
721 @Override
722 public void messageSent(NextFilter nextFilter, IoSession session,
723 WriteRequest writeRequest) throws Exception {
724 session.getHandler()
725 .messageSent(session, writeRequest.getMessage());
726 }
727
728 @Override
729 public void filterWrite(NextFilter nextFilter, IoSession session,
730 WriteRequest writeRequest) throws Exception {
731 nextFilter.filterWrite(session, writeRequest);
732 }
733
734 @Override
735 public void filterClose(NextFilter nextFilter, IoSession session)
736 throws Exception {
737 nextFilter.filterClose(session);
738 }
739 }
740
741 private class EntryImpl implements Entry {
742 private EntryImpl prevEntry;
743
744 private EntryImpl nextEntry;
745
746 private final String name;
747
748 private IoFilter filter;
749
750 private final NextFilter nextFilter;
751
752 private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry,
753 String name, IoFilter filter) {
754 if (filter == null) {
755 throw new NullPointerException("filter");
756 }
757 if (name == null) {
758 throw new NullPointerException("name");
759 }
760
761 this.prevEntry = prevEntry;
762 this.nextEntry = nextEntry;
763 this.name = name;
764 this.filter = filter;
765 this.nextFilter = new NextFilter() {
766 public void sessionCreated(IoSession session) {
767 Entry nextEntry = EntryImpl.this.nextEntry;
768 callNextSessionCreated(nextEntry, session);
769 }
770
771 public void sessionOpened(IoSession session) {
772 Entry nextEntry = EntryImpl.this.nextEntry;
773 callNextSessionOpened(nextEntry, session);
774 }
775
776 public void sessionClosed(IoSession session) {
777 Entry nextEntry = EntryImpl.this.nextEntry;
778 callNextSessionClosed(nextEntry, session);
779 }
780
781 public void sessionIdle(IoSession session, IdleStatus status) {
782 Entry nextEntry = EntryImpl.this.nextEntry;
783 callNextSessionIdle(nextEntry, session, status);
784 }
785
786 public void exceptionCaught(IoSession session, Throwable cause) {
787 Entry nextEntry = EntryImpl.this.nextEntry;
788 callNextExceptionCaught(nextEntry, session, cause);
789 }
790
791 public void messageReceived(IoSession session, Object message) {
792 Entry nextEntry = EntryImpl.this.nextEntry;
793 callNextMessageReceived(nextEntry, session, message);
794 }
795
796 public void messageSent(IoSession session,
797 WriteRequest writeRequest) {
798 Entry nextEntry = EntryImpl.this.nextEntry;
799 callNextMessageSent(nextEntry, session, writeRequest);
800 }
801
802 public void filterWrite(IoSession session,
803 WriteRequest writeRequest) {
804 Entry nextEntry = EntryImpl.this.prevEntry;
805 callPreviousFilterWrite(nextEntry, session, writeRequest);
806 }
807
808 public void filterClose(IoSession session) {
809 Entry nextEntry = EntryImpl.this.prevEntry;
810 callPreviousFilterClose(nextEntry, session);
811 }
812
813 public String toString() {
814 return EntryImpl.this.nextEntry.name;
815 }
816 };
817 }
818
819 public String getName() {
820 return name;
821 }
822
823 public IoFilter getFilter() {
824 return filter;
825 }
826
827 private void setFilter(IoFilter filter) {
828 if (filter == null) {
829 throw new NullPointerException("filter");
830 }
831
832 this.filter = filter;
833 }
834
835 public NextFilter getNextFilter() {
836 return nextFilter;
837 }
838
839 @Override
840 public String toString() {
841 StringBuilder sb = new StringBuilder();
842
843
844 sb.append("('").append(getName()).append('\'');
845
846
847 sb.append(", prev: '");
848
849 if (prevEntry != null) {
850 sb.append(prevEntry.name);
851 sb.append(':');
852 sb.append(prevEntry.getFilter().getClass().getSimpleName());
853 } else {
854 sb.append("null");
855 }
856
857
858 sb.append("', next: '");
859
860 if (nextEntry != null) {
861 sb.append(nextEntry.name);
862 sb.append(':');
863 sb.append(nextEntry.getFilter().getClass().getSimpleName());
864 } else {
865 sb.append("null");
866 }
867
868 sb.append("')");
869 return sb.toString();
870 }
871
872 public void addAfter(String name, IoFilter filter) {
873 DefaultIoFilterChain.this.addAfter(getName(), name, filter);
874 }
875
876 public void addBefore(String name, IoFilter filter) {
877 DefaultIoFilterChain.this.addBefore(getName(), name, filter);
878 }
879
880 public void remove() {
881 DefaultIoFilterChain.this.remove(getName());
882 }
883
884 public void replace(IoFilter newFilter) {
885 DefaultIoFilterChain.this.replace(getName(), newFilter);
886 }
887 }
888 }