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<String, Entry> name2entry = new HashMap<String, Entry>();
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 = 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<String> it = new ArrayList<String>(name2entry.keySet())
145 .iterator();
146 while (it.hasNext()) {
147 this.remove(it.next());
148 }
149 }
150
151 private void register(EntryImpl prevEntry, String name, IoFilter filter) {
152 EntryImpl newEntry = new EntryImpl(prevEntry, prevEntry.nextEntry,
153 name, filter);
154
155 try {
156 filter.onPreAdd(this, name, newEntry.getNextFilter());
157 } catch (Exception e) {
158 throw new IoFilterLifeCycleException("onPreAdd(): " + name + ':'
159 + filter + " in " + getSession(), e);
160 }
161
162 prevEntry.nextEntry.prevEntry = newEntry;
163 prevEntry.nextEntry = newEntry;
164 name2entry.put(name, newEntry);
165
166 try {
167 filter.onPostAdd(this, name, newEntry.getNextFilter());
168 } catch (Exception e) {
169 deregister0(newEntry);
170 throw new IoFilterLifeCycleException("onPostAdd(): " + name + ':'
171 + filter + " in " + getSession(), e);
172 }
173 }
174
175 private void deregister(EntryImpl entry) {
176 IoFilter filter = entry.getFilter();
177
178 try {
179 filter.onPreRemove(this, entry.getName(), entry.getNextFilter());
180 } catch (Exception e) {
181 throw new IoFilterLifeCycleException("onPreRemove(): "
182 + entry.getName() + ':' + filter + " in " + getSession(), e);
183 }
184
185 deregister0(entry);
186
187 try {
188 filter.onPostRemove(this, entry.getName(), entry.getNextFilter());
189 } catch (Exception e) {
190 throw new IoFilterLifeCycleException("onPostRemove(): "
191 + entry.getName() + ':' + filter + " in " + getSession(), e);
192 }
193 }
194
195 private void deregister0(EntryImpl entry) {
196 EntryImpl prevEntry = entry.prevEntry;
197 EntryImpl nextEntry = entry.nextEntry;
198 prevEntry.nextEntry = nextEntry;
199 nextEntry.prevEntry = prevEntry;
200
201 name2entry.remove(entry.name);
202 }
203
204
205
206
207
208
209 private EntryImpl checkOldName(String baseName) {
210 EntryImpl e = (EntryImpl) name2entry.get(baseName);
211 if (e == null) {
212 throw new IllegalArgumentException("Unknown filter name:"
213 + baseName);
214 }
215 return e;
216 }
217
218
219
220
221 private void checkAddable(String name) {
222 if (name2entry.containsKey(name)) {
223 throw new IllegalArgumentException(
224 "Other filter is using the same name '" + name + "'");
225 }
226 }
227
228 public void fireSessionCreated(IoSession session) {
229 Entry head = this.head;
230 callNextSessionCreated(head, session);
231 }
232
233 private void callNextSessionCreated(Entry entry, IoSession session) {
234 try {
235 entry.getFilter().sessionCreated(entry.getNextFilter(), session);
236 } catch (Throwable e) {
237 fireExceptionCaught(session, e);
238 }
239 }
240
241 public void fireSessionOpened(IoSession session) {
242 Entry head = this.head;
243 callNextSessionOpened(head, session);
244 }
245
246 private void callNextSessionOpened(Entry entry, IoSession session) {
247 try {
248 entry.getFilter().sessionOpened(entry.getNextFilter(), session);
249 } catch (Throwable e) {
250 fireExceptionCaught(session, e);
251 }
252 }
253
254 public void fireSessionClosed(IoSession session) {
255
256 try {
257 session.getCloseFuture().setClosed();
258 } catch (Throwable t) {
259 fireExceptionCaught(session, t);
260 }
261
262
263 Entry head = this.head;
264 callNextSessionClosed(head, session);
265 }
266
267 private void callNextSessionClosed(Entry entry, IoSession session) {
268 try {
269 entry.getFilter().sessionClosed(entry.getNextFilter(), session);
270
271 } catch (Throwable e) {
272 fireExceptionCaught(session, e);
273 }
274 }
275
276 public void fireSessionIdle(IoSession session, IdleStatus status) {
277 Entry head = this.head;
278 callNextSessionIdle(head, session, status);
279 }
280
281 private void callNextSessionIdle(Entry entry, IoSession session,
282 IdleStatus status) {
283 try {
284 entry.getFilter().sessionIdle(entry.getNextFilter(), session,
285 status);
286 } catch (Throwable e) {
287 fireExceptionCaught(session, e);
288 }
289 }
290
291 public void fireMessageReceived(IoSession session, Object message) {
292 Entry head = this.head;
293 callNextMessageReceived(head, session, message);
294 }
295
296 private void callNextMessageReceived(Entry entry, IoSession session,
297 Object message) {
298 try {
299 entry.getFilter().messageReceived(entry.getNextFilter(), session,
300 message);
301 } catch (Throwable e) {
302 fireExceptionCaught(session, e);
303 }
304 }
305
306 public void fireMessageSent(IoSession session, WriteRequest request) {
307 try {
308 request.getFuture().setWritten(true);
309 } catch (Throwable t) {
310 fireExceptionCaught(session, t);
311 }
312
313 Entry head = this.head;
314 callNextMessageSent(head, session, request.getMessage());
315 }
316
317 private void callNextMessageSent(Entry entry, IoSession session,
318 Object message) {
319 try {
320 entry.getFilter().messageSent(entry.getNextFilter(), session,
321 message);
322 } catch (Throwable e) {
323 fireExceptionCaught(session, e);
324 }
325 }
326
327 public void fireExceptionCaught(IoSession session, Throwable cause) {
328
329
330 ConnectFuture future = (ConnectFuture) session
331 .removeAttribute(CONNECT_FUTURE);
332 if (future == null) {
333 Entry head = this.head;
334 callNextExceptionCaught(head, session, cause);
335 } else {
336
337
338 future.setException(cause);
339 }
340 }
341
342 private void callNextExceptionCaught(Entry entry, IoSession session,
343 Throwable cause) {
344 try {
345 entry.getFilter().exceptionCaught(entry.getNextFilter(), session,
346 cause);
347 } catch (Throwable e) {
348 SessionLog.warn(session,
349 "Unexpected exception from exceptionCaught handler.", e);
350 }
351 }
352
353 public void fireFilterWrite(IoSession session, WriteRequest writeRequest) {
354 Entry tail = this.tail;
355 callPreviousFilterWrite(tail, session, writeRequest);
356 }
357
358 private void callPreviousFilterWrite(Entry entry, IoSession session,
359 WriteRequest writeRequest) {
360 try {
361 entry.getFilter().filterWrite(entry.getNextFilter(), session,
362 writeRequest);
363 } catch (Throwable e) {
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<Entry> getAll() {
382 List<Entry> list = new ArrayList<Entry>();
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<Entry> getAllReversed() {
393 List<Entry> list = new ArrayList<Entry>();
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<? extends IoFilter> 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 }