View Javadoc

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