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