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 fireExceptionCaught(session, e);
364 }
365 }
366
367 public void fireFilterClose(IoSession session) {
368 Entry tail = this.tail;
369 callPreviousFilterClose(tail, session);
370 }
371
372 private void callPreviousFilterClose(Entry entry, IoSession session) {
373 try {
374 entry.getFilter().filterClose(entry.getNextFilter(), session);
375 } catch (Throwable e) {
376 fireExceptionCaught(session, e);
377 }
378 }
379
380 public List getAll() {
381 List list = new ArrayList();
382 EntryImpl e = head.nextEntry;
383 while (e != tail) {
384 list.add(e);
385 e = e.nextEntry;
386 }
387
388 return list;
389 }
390
391 public List getAllReversed() {
392 List list = new ArrayList();
393 EntryImpl e = tail.prevEntry;
394 while (e != head) {
395 list.add(e);
396 e = e.prevEntry;
397 }
398 return list;
399 }
400
401 public boolean contains(String name) {
402 return getEntry(name) != null;
403 }
404
405 public boolean contains(IoFilter filter) {
406 EntryImpl e = head.nextEntry;
407 while (e != tail) {
408 if (e.getFilter() == filter) {
409 return true;
410 }
411 e = e.nextEntry;
412 }
413 return false;
414 }
415
416 public boolean contains(Class filterType) {
417 EntryImpl e = head.nextEntry;
418 while (e != tail) {
419 if (filterType.isAssignableFrom(e.getFilter().getClass())) {
420 return true;
421 }
422 e = e.nextEntry;
423 }
424 return false;
425 }
426
427 public String toString() {
428 StringBuffer buf = new StringBuffer();
429 buf.append("{ ");
430
431 boolean empty = true;
432
433 EntryImpl e = head.nextEntry;
434 while (e != tail) {
435 if (!empty) {
436 buf.append(", ");
437 } else {
438 empty = false;
439 }
440
441 buf.append('(');
442 buf.append(e.getName());
443 buf.append(':');
444 buf.append(e.getFilter());
445 buf.append(')');
446
447 e = e.nextEntry;
448 }
449
450 if (empty) {
451 buf.append("empty");
452 }
453
454 buf.append(" }");
455
456 return buf.toString();
457 }
458
459 protected void finalize() throws Throwable {
460 try {
461 this.clear();
462 } finally {
463 super.finalize();
464 }
465 }
466
467 protected abstract void doWrite(IoSession session, WriteRequest writeRequest)
468 throws Exception;
469
470 protected abstract void doClose(IoSession session) throws Exception;
471
472 private class HeadFilter extends IoFilterAdapter {
473 public void sessionCreated(NextFilter nextFilter, IoSession session) {
474 nextFilter.sessionCreated(session);
475 }
476
477 public void sessionOpened(NextFilter nextFilter, IoSession session) {
478 nextFilter.sessionOpened(session);
479 }
480
481 public void sessionClosed(NextFilter nextFilter, IoSession session) {
482 nextFilter.sessionClosed(session);
483 }
484
485 public void sessionIdle(NextFilter nextFilter, IoSession session,
486 IdleStatus status) {
487 nextFilter.sessionIdle(session, status);
488 }
489
490 public void exceptionCaught(NextFilter nextFilter, IoSession session,
491 Throwable cause) {
492 nextFilter.exceptionCaught(session, cause);
493 }
494
495 public void messageReceived(NextFilter nextFilter, IoSession session,
496 Object message) {
497 nextFilter.messageReceived(session, message);
498 }
499
500 public void messageSent(NextFilter nextFilter, IoSession session,
501 Object message) {
502 nextFilter.messageSent(session, message);
503 }
504
505 public void filterWrite(NextFilter nextFilter, IoSession session,
506 WriteRequest writeRequest) throws Exception {
507 if (session.getTransportType().getEnvelopeType().isAssignableFrom(
508 writeRequest.getMessage().getClass())) {
509 doWrite(session, writeRequest);
510 } else {
511 throw new IllegalStateException(
512 "Write requests must be transformed to "
513 + session.getTransportType().getEnvelopeType()
514 + ": " + writeRequest);
515 }
516 }
517
518 public void filterClose(NextFilter nextFilter, IoSession session)
519 throws Exception {
520 doClose(session);
521 }
522 }
523
524 private static class TailFilter extends IoFilterAdapter {
525 public void sessionCreated(NextFilter nextFilter, IoSession session)
526 throws Exception {
527 session.getHandler().sessionCreated(session);
528 }
529
530 public void sessionOpened(NextFilter nextFilter, IoSession session)
531 throws Exception {
532 try {
533 session.getHandler().sessionOpened(session);
534 } finally {
535
536
537 ConnectFuture future = (ConnectFuture) session
538 .removeAttribute(CONNECT_FUTURE);
539 if (future != null) {
540 future.setSession(session);
541 }
542 }
543 }
544
545 public void sessionClosed(NextFilter nextFilter, IoSession session)
546 throws Exception {
547 try {
548 session.getHandler().sessionClosed(session);
549 } finally {
550
551 session.getFilterChain().clear();
552 }
553 }
554
555 public void sessionIdle(NextFilter nextFilter, IoSession session,
556 IdleStatus status) throws Exception {
557 session.getHandler().sessionIdle(session, status);
558 }
559
560 public void exceptionCaught(NextFilter nextFilter, IoSession session,
561 Throwable cause) throws Exception {
562 session.getHandler().exceptionCaught(session, cause);
563 }
564
565 public void messageReceived(NextFilter nextFilter, IoSession session,
566 Object message) throws Exception {
567 try {
568 session.getHandler().messageReceived(session, message);
569 } finally {
570 ByteBufferUtil.releaseIfPossible(message);
571 }
572 }
573
574 public void messageSent(NextFilter nextFilter, IoSession session,
575 Object message) throws Exception {
576 try {
577 session.getHandler().messageSent(session, message);
578 } finally {
579 ByteBufferUtil.releaseIfPossible(message);
580 }
581 }
582
583 public void filterWrite(NextFilter nextFilter, IoSession session,
584 WriteRequest writeRequest) throws Exception {
585 nextFilter.filterWrite(session, writeRequest);
586 }
587
588 public void filterClose(NextFilter nextFilter, IoSession session)
589 throws Exception {
590 nextFilter.filterClose(session);
591 }
592 }
593
594 private class EntryImpl implements Entry {
595 private EntryImpl prevEntry;
596
597 private EntryImpl nextEntry;
598
599 private final String name;
600
601 private final IoFilter filter;
602
603 private final NextFilter nextFilter;
604
605 private EntryImpl(EntryImpl prevEntry, EntryImpl nextEntry,
606 String name, IoFilter filter) {
607 if (filter == null) {
608 throw new NullPointerException("filter");
609 }
610 if (name == null) {
611 throw new NullPointerException("name");
612 }
613
614 this.prevEntry = prevEntry;
615 this.nextEntry = nextEntry;
616 this.name = name;
617 this.filter = filter;
618 this.nextFilter = new NextFilter() {
619 public void sessionCreated(IoSession session) {
620 Entry nextEntry = EntryImpl.this.nextEntry;
621 callNextSessionCreated(nextEntry, session);
622 }
623
624 public void sessionOpened(IoSession session) {
625 Entry nextEntry = EntryImpl.this.nextEntry;
626 callNextSessionOpened(nextEntry, session);
627 }
628
629 public void sessionClosed(IoSession session) {
630 Entry nextEntry = EntryImpl.this.nextEntry;
631 callNextSessionClosed(nextEntry, session);
632 }
633
634 public void sessionIdle(IoSession session, IdleStatus status) {
635 Entry nextEntry = EntryImpl.this.nextEntry;
636 callNextSessionIdle(nextEntry, session, status);
637 }
638
639 public void exceptionCaught(IoSession session, Throwable cause) {
640 Entry nextEntry = EntryImpl.this.nextEntry;
641 callNextExceptionCaught(nextEntry, session, cause);
642 }
643
644 public void messageReceived(IoSession session, Object message) {
645 Entry nextEntry = EntryImpl.this.nextEntry;
646 callNextMessageReceived(nextEntry, session, message);
647 }
648
649 public void messageSent(IoSession session, Object message) {
650 Entry nextEntry = EntryImpl.this.nextEntry;
651 callNextMessageSent(nextEntry, session, message);
652 }
653
654 public void filterWrite(IoSession session,
655 WriteRequest writeRequest) {
656 Entry nextEntry = EntryImpl.this.prevEntry;
657 callPreviousFilterWrite(nextEntry, session, writeRequest);
658 }
659
660 public void filterClose(IoSession session) {
661 Entry nextEntry = EntryImpl.this.prevEntry;
662 callPreviousFilterClose(nextEntry, session);
663 }
664 };
665 }
666
667 public String getName() {
668 return name;
669 }
670
671 public IoFilter getFilter() {
672 return filter;
673 }
674
675 public NextFilter getNextFilter() {
676 return nextFilter;
677 }
678
679 public String toString() {
680 return "(" + getName() + ':' + filter + ')';
681 }
682 }
683 }