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