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