1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.common.support;
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.common.ConnectFuture;
29 import org.apache.mina.common.IdleStatus;
30 import org.apache.mina.common.IoFilter;
31 import org.apache.mina.common.IoFilterAdapter;
32 import org.apache.mina.common.IoFilterChain;
33 import org.apache.mina.common.IoFilterLifeCycleException;
34 import org.apache.mina.common.IoSession;
35 import org.apache.mina.common.IoFilter.NextFilter;
36 import org.apache.mina.common.IoFilter.WriteRequest;
37 import org.apache.mina.util.ByteBufferUtil;
38 import org.apache.mina.util.SessionLog;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public abstract class AbstractIoFilterChain implements IoFilterChain {
54
55
56
57
58
59
60 public static final String CONNECT_FUTURE = AbstractIoFilterChain.class
61 .getName()
62 + ".connectFuture";
63
64 private final IoSession session;
65
66 private final Map name2entry = new HashMap();
67
68 private final EntryImpl head;
69
70 private final EntryImpl tail;
71
72 protected AbstractIoFilterChain(IoSession session) {
73 if (session == null) {
74 throw new NullPointerException("session");
75 }
76
77 this.session = session;
78 head = new EntryImpl(null, null, "head", new HeadFilter());
79 tail = new EntryImpl(head, null, "tail", new TailFilter());
80 head.nextEntry = tail;
81 }
82
83 public IoSession getSession() {
84 return session;
85 }
86
87 public Entry getEntry(String name) {
88 Entry e = (Entry) name2entry.get(name);
89 if (e == null) {
90 return null;
91 }
92 return e;
93 }
94
95 public IoFilter get(String name) {
96 Entry e = getEntry(name);
97 if (e == null) {
98 return null;
99 }
100
101 return e.getFilter();
102 }
103
104 public NextFilter getNextFilter(String name) {
105 Entry e = getEntry(name);
106 if (e == null) {
107 return null;
108 }
109
110 return e.getNextFilter();
111 }
112
113 public synchronized void addFirst(String name, IoFilter filter) {
114 checkAddable(name);
115 register(head, name, filter);
116 }
117
118 public synchronized void addLast(String name, IoFilter filter) {
119 checkAddable(name);
120 register(tail.prevEntry, name, filter);
121 }
122
123 public synchronized void addBefore(String baseName, String name,
124 IoFilter filter) {
125 EntryImpl baseEntry = checkOldName(baseName);
126 checkAddable(name);
127 register(baseEntry.prevEntry, name, filter);
128 }
129
130 public synchronized void addAfter(String baseName, String name,
131 IoFilter filter) {
132 EntryImpl baseEntry = checkOldName(baseName);
133 checkAddable(name);
134 register(baseEntry, name, filter);
135 }
136
137 public synchronized IoFilter remove(String name) {
138 EntryImpl entry = checkOldName(name);
139 deregister(entry);
140 return entry.getFilter();
141 }
142
143 public synchronized void clear() throws Exception {
144 Iterator it = new ArrayList(name2entry.keySet()).iterator();
145 while (it.hasNext()) {
146 this.remove((String) it.next());
147 }
148 }
149
150 private void register(EntryImpl prevEntry, String name, IoFilter filter) {
151 EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry,
152 name, filter);
153
154 try {
155 filter.onPreAdd(this, name, newEntry.getNextFilter());
156 } catch (Exception e) {
157 throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':'
158 + filter + " in " + getSession(), e);
159 }
160
161 prevEntry.nextEntry.prevEntry = newEntry;
162 prevEntry.nextEntry = newEntry;
163 name2entry.put(name, newEntry);
164
165 try {
166 filter.onPostAdd(this, name, newEntry.getNextFilter());
167 } catch (Exception e) {
168 deregister0(newEntry);
169 throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':'
170 + filter + " in " + getSession(), e);
171 }
172 }
173
174 private void deregister(EntryImpl entry) {
175 IoFilter filter = entry.getFilter();
176
177 try {
178 filter.onPreRemove(this, entry.getName(), entry.getNextFilter());
179 } catch (Exception e) {
180 throw new IoFilterLifeCycleException("onPreRemove(): "
181 + entry.getName() + ':' + filter + " in " + getSession(), e);
182 }
183
184 deregister0(entry);
185
186 try {
187 filter.onPostRemove(this, entry.getName(), entry.getNextFilter());
188 } catch (Exception e) {
189 throw new IoFilterLifeCycleException("onPostRemove(): "
190 + entry.getName() + ':' + filter + " in " + getSession(), e);
191 }
192 }
193
194 private void deregister0(EntryImpl entry) {
195 EntryImpl prevEntry = entry.prevEntry;
196 EntryImpl nextEntry = entry.nextEntry;
197 prevEntry.nextEntry = nextEntry;
198 nextEntry.prevEntry = prevEntry;
199
200 name2entry.remove(entry.name);
201 }
202
203
204
205
206
207
208 private EntryImpl checkOldName(String baseName) {
209 EntryImpl e = (EntryImpl) name2entry.get(baseName);
210 if (e == null) {
211 throw new IllegalArgumentException("Unknown filter name:"
212 + baseName);
213 }
214 return e;
215 }
216
217
218
219
220 private void checkAddable(String name) {
221 if (name2entry.containsKey(name)) {
222 throw new IllegalArgumentException(
223 "Other filter is using the same name '" + name + "'");
224 }
225 }
226
227 public void fireSessionCreated(IoSession session) {
228 Entry head = this.head;
229 callNextSessionCreated(head, session);
230 }
231
232 private void callNextSessionCreated(Entry entry, IoSession session) {
233 try {
234 entry.getFilter().sessionCreated(entry.getNextFilter(), session);
235 } catch (Throwable e) {
236 fireExceptionCaught(session, e);
237 }
238 }
239
240 public void fireSessionOpened(IoSession session) {
241 Entry head = this.head;
242 callNextSessionOpened(head, session);
243 }
244
245 private void callNextSessionOpened(Entry entry, IoSession session) {
246 try {
247 entry.getFilter().sessionOpened(entry.getNextFilter(), session);
248 } catch (Throwable e) {
249 fireExceptionCaught(session, e);
250 }
251 }
252
253 public void fireSessionClosed(IoSession session) {
254
255 try {
256 session.getCloseFuture().setClosed();
257 } catch (Throwable t) {
258 fireExceptionCaught(session, t);
259 }
260
261
262 Entry head = this.head;
263 callNextSessionClosed(head, session);
264 }
265
266 private void callNextSessionClosed(Entry entry, IoSession session) {
267 try {
268 entry.getFilter().sessionClosed(entry.getNextFilter(), session);
269
270 } catch (Throwable e) {
271 fireExceptionCaught(session, e);
272 }
273 }
274
275 public void fireSessionIdle(IoSession session, IdleStatus status) {
276 Entry head = this.head;
277 callNextSessionIdle(head, session, status);
278 }
279
280 private void callNextSessionIdle(Entry entry, IoSession session,
281 IdleStatus status) {
282 try {
283 entry.getFilter().sessionIdle(entry.getNextFilter(), session,
284 status);
285 } catch (Throwable e) {
286 fireExceptionCaught(session, e);
287 }
288 }
289
290 public void fireMessageReceived(IoSession session, Object message) {
291 Entry head = this.head;
292 callNextMessageReceived(head, session, message);
293 }
294
295 private void callNextMessageReceived(Entry entry, IoSession session,
296 Object message) {
297 try {
298 entry.getFilter().messageReceived(entry.getNextFilter(), session,
299 message);
300 } catch (Throwable e) {
301 fireExceptionCaught(session, e);
302 }
303 }
304
305 public void fireMessageSent(IoSession session, WriteRequest request) {
306 try {
307 request.getFuture().setWritten(true);
308 } catch (Throwable t) {
309 fireExceptionCaught(session, t);
310 }
311
312 Entry head = this.head;
313 callNextMessageSent(head, session, request.getMessage());
314 }
315
316 private void callNextMessageSent(Entry entry, IoSession session,
317 Object message) {
318 try {
319 entry.getFilter().messageSent(entry.getNextFilter(), session,
320 message);
321 } catch (Throwable e) {
322 fireExceptionCaught(session, e);
323 }
324 }
325
326 public void fireExceptionCaught(IoSession session, Throwable cause) {
327
328
329 ConnectFuture future = (ConnectFuture) session
330 .removeAttribute(CONNECT_FUTURE);
331 if (future == null) {
332 Entry head = this.head;
333 callNextExceptionCaught(head, session, cause);
334 } else {
335
336
337 future.setException(cause);
338 }
339 }
340
341 private void callNextExceptionCaught(Entry entry, IoSession session,
342 Throwable cause) {
343 try {
344 entry.getFilter().exceptionCaught(entry.getNextFilter(), session,
345 cause);
346 } catch (Throwable e) {
347 SessionLog.warn(session,
348 "Unexpected exception from exceptionCaught handler.", e);
349 }
350 }
351
352 public void fireFilterWrite(IoSession session, WriteRequest writeRequest) {
353 Entry tail = this.tail;
354 callPreviousFilterWrite(tail, session, writeRequest);
355 }
356
357 private void callPreviousFilterWrite(Entry entry, IoSession session,
358 WriteRequest writeRequest) {
359 try {
360 entry.getFilter().filterWrite(entry.getNextFilter(), session,
361 writeRequest);
362 } catch (Throwable e) {
363 writeRequest.getFuture().setWritten(false);
364 fireExceptionCaught(session, e);
365 }
366 }
367
368 public void fireFilterClose(IoSession session) {
369 Entry tail = this.tail;
370 callPreviousFilterClose(tail, session);
371 }
372
373 private void callPreviousFilterClose(Entry entry, IoSession session) {
374 try {
375 entry.getFilter().filterClose(entry.getNextFilter(), session);
376 } catch (Throwable e) {
377 fireExceptionCaught(session, e);
378 }
379 }
380
381 public List getAll() {
382 List list = new ArrayList();
383 EntryImpl e = head.nextEntry;
384 while (e != tail) {
385 list.add(e);
386 e = e.nextEntry;
387 }
388
389 return list;
390 }
391
392 public List getAllReversed() {
393 List list = new ArrayList();
394 EntryImpl e = tail.prevEntry;
395 while (e != head) {
396 list.add(e);
397 e = e.prevEntry;
398 }
399 return list;
400 }
401
402 public boolean contains(String name) {
403 return getEntry(name) != null;
404 }
405
406 public boolean contains(IoFilter filter) {
407 EntryImpl e = head.nextEntry;
408 while (e != tail) {
409 if (e.getFilter() == filter) {
410 return true;
411 }
412 e = e.nextEntry;
413 }
414 return false;
415 }
416
417 public boolean contains(Class filterType) {
418 EntryImpl e = head.nextEntry;
419 while (e != tail) {
420 if (filterType.isAssignableFrom(e.getFilter().getClass())) {
421 return true;
422 }
423 e = e.nextEntry;
424 }
425 return false;
426 }
427
428 public String toString() {
429 StringBuffer buf = new StringBuffer();
430 buf.append("{ ");
431
432 boolean empty = true;
433
434 EntryImpl e = head.nextEntry;
435 while (e != tail) {
436 if (!empty) {
437 buf.append(", ");
438 } else {
439 empty = false;
440 }
441
442 buf.append('(');
443 buf.append(e.getName());
444 buf.append(':');
445 buf.append(e.getFilter());
446 buf.append(')');
447
448 e = e.nextEntry;
449 }
450
451 if (empty) {
452 buf.append("empty");
453 }
454
455 buf.append(" }");
456
457 return buf.toString();
458 }
459
460 protected void finalize() throws Throwable {
461 try {
462 this.clear();
463 } finally {
464 super.finalize();
465 }
466 }
467
468 protected abstract void doWrite(IoSession session, WriteRequest writeRequest)
469 throws Exception;
470
471 protected abstract void doClose(IoSession session) throws Exception;
472
473 private class HeadFilter extends IoFilterAdapter {
474 public void sessionCreated(NextFilter nextFilter, IoSession session) {
475 nextFilter.sessionCreated(session);
476 }
477
478 public void sessionOpened(NextFilter nextFilter, IoSession session) {
479 nextFilter.sessionOpened(session);
480 }
481
482 public void sessionClosed(NextFilter nextFilter, IoSession session) {
483 nextFilter.sessionClosed(session);
484 }
485
486 public void sessionIdle(NextFilter nextFilter, IoSession session,
487 IdleStatus status) {
488 nextFilter.sessionIdle(session, status);
489 }
490
491 public void exceptionCaught(NextFilter nextFilter, IoSession session,
492 Throwable cause) {
493 nextFilter.exceptionCaught(session, cause);
494 }
495
496 public void messageReceived(NextFilter nextFilter, IoSession session,
497 Object message) {
498 nextFilter.messageReceived(session, message);
499 }
500
501 public void messageSent(NextFilter nextFilter, IoSession session,
502 Object message) {
503 nextFilter.messageSent(session, message);
504 }
505
506 public void filterWrite(NextFilter nextFilter, IoSession session,
507 WriteRequest writeRequest) throws Exception {
508 if (session.getTransportType().getEnvelopeType().isAssignableFrom(
509 writeRequest.getMessage().getClass())) {
510 doWrite(session, writeRequest);
511 } else {
512 throw new IllegalStateException(
513 "Write requests must be transformed to "
514 + session.getTransportType().getEnvelopeType()
515 + ": " + writeRequest);
516 }
517 }
518
519 public void filterClose(NextFilter nextFilter, IoSession session)
520 throws Exception {
521 doClose(session);
522 }
523 }
524
525 private static class TailFilter extends IoFilterAdapter {
526 public void sessionCreated(NextFilter nextFilter, IoSession session)
527 throws Exception {
528 session.getHandler().sessionCreated(session);
529 }
530
531 public void sessionOpened(NextFilter nextFilter, IoSession session)
532 throws Exception {
533 try {
534 session.getHandler().sessionOpened(session);
535 } finally {
536
537
538 ConnectFuture future = (ConnectFuture) session
539 .removeAttribute(CONNECT_FUTURE);
540 if (future != null) {
541 future.setSession(session);
542 }
543 }
544 }
545
546 public void sessionClosed(NextFilter nextFilter, IoSession session)
547 throws Exception {
548 try {
549 session.getHandler().sessionClosed(session);
550 } finally {
551
552 session.getFilterChain().clear();
553 }
554 }
555
556 public void sessionIdle(NextFilter nextFilter, IoSession session,
557 IdleStatus status) throws Exception {
558 session.getHandler().sessionIdle(session, status);
559 }
560
561 public void exceptionCaught(NextFilter nextFilter, IoSession session,
562 Throwable cause) throws Exception {
563 session.getHandler().exceptionCaught(session, cause);
564 }
565
566 public void messageReceived(NextFilter nextFilter, IoSession session,
567 Object message) throws Exception {
568 try {
569 session.getHandler().messageReceived(session, message);
570 } finally {
571 ByteBufferUtil.releaseIfPossible(message);
572 }
573 }
574
575 public void messageSent(NextFilter nextFilter, IoSession session,
576 Object message) throws Exception {
577 try {
578 session.getHandler().messageSent(session, message);
579 } finally {
580 ByteBufferUtil.releaseIfPossible(message);
581 }
582 }
583
584 public void filterWrite(NextFilter nextFilter, IoSession session,
585 WriteRequest writeRequest) throws Exception {
586 nextFilter.filterWrite(session, writeRequest);
587 }
588
589 public void filterClose(NextFilter nextFilter, IoSession session)
590 throws Exception {
591 nextFilter.filterClose(session);
592 }
593 }
594
595 private class EntryImpl implements Entry {
596 private EntryImpl prevEntry;
597
598 private EntryImpl nextEntry;
599
600 private final String name;
601
602 private final IoFilter filter;
603
604 private final NextFilter nextFilter;
605
606 private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry,
607 String name, IoFilter filter) {
608 if (filter == null) {
609 throw new NullPointerException("filter");
610 }
611 if (name == null) {
612 throw new NullPointerException("name");
613 }
614
615 this.prevEntry = prevEntry;
616 this.nextEntry = nextEntry;
617 this.name = name;
618 this.filter = filter;
619 this.nextFilter = new NextFilter() {
620 public void sessionCreated(IoSession session) {
621 Entry nextEntry = EntryImpl.this.nextEntry;
622 callNextSessionCreated(nextEntry, session);
623 }
624
625 public void sessionOpened(IoSession session) {
626 Entry nextEntry = EntryImpl.this.nextEntry;
627 callNextSessionOpened(nextEntry, session);
628 }
629
630 public void sessionClosed(IoSession session) {
631 Entry nextEntry = EntryImpl.this.nextEntry;
632 callNextSessionClosed(nextEntry, session);
633 }
634
635 public void sessionIdle(IoSession session, IdleStatus status) {
636 Entry nextEntry = EntryImpl.this.nextEntry;
637 callNextSessionIdle(nextEntry, session, status);
638 }
639
640 public void exceptionCaught(IoSession session, Throwable cause) {
641 Entry nextEntry = EntryImpl.this.nextEntry;
642 callNextExceptionCaught(nextEntry, session, cause);
643 }
644
645 public void messageReceived(IoSession session, Object message) {
646 Entry nextEntry = EntryImpl.this.nextEntry;
647 callNextMessageReceived(nextEntry, session, message);
648 }
649
650 public void messageSent(IoSession session, Object message) {
651 Entry nextEntry = EntryImpl.this.nextEntry;
652 callNextMessageSent(nextEntry, session, message);
653 }
654
655 public void filterWrite(IoSession session,
656 WriteRequest writeRequest) {
657 Entry nextEntry = EntryImpl.this.prevEntry;
658 callPreviousFilterWrite(nextEntry, session, writeRequest);
659 }
660
661 public void filterClose(IoSession session) {
662 Entry nextEntry = EntryImpl.this.prevEntry;
663 callPreviousFilterClose(nextEntry, session);
664 }
665 };
666 }
667
668 public String getName() {
669 return name;
670 }
671
672 public IoFilter getFilter() {
673 return filter;
674 }
675
676 public NextFilter getNextFilter() {
677 return nextFilter;
678 }
679
680 public String toString() {
681 return "(" + getName() + ':' + filter + ')';
682 }
683 }
684 }