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