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.handler.chain;
    21
    22  import java.util.ArrayList;
    23  import java.util.HashMap;
    24  import java.util.Iterator;
    25  import java.util.List;
    26  import java.util.Map;
    27
    28  import org.apache.mina.common.IoSession;
    29
    30  /**
    31   * A chain of {@link IoHandlerCommand}s.
    32   *
    33   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
    34   * @version $Rev: 555855 $, $Date: 2007-07-13 05:19:00 +0200 (Fri, 13 Jul 2007) $
    35   */
    36  public class IoHandlerChain implements IoHandlerCommand {
    37      private static volatile int nextId = 0;
    38
    39      private final int id = nextId++;
    40
    41      private final String NEXT_COMMAND = IoHandlerChain.class.getName() + '.'
    42              + id + ".nextCommand";
    43
    44      private final Map<String, Entry> name2entry = new HashMap<String, Entry>();
    45
    46      private final Entry head;
    47
    48      private final Entry tail;
    49
    50      /**
    51       * Creates a new, empty chain of {@link IoHandlerCommand}s.
    52       */
    53      public IoHandlerChain() {
    54          head = new Entry(null, null, "head", createHeadCommand());
    55          tail = new Entry(head, null, "tail", createTailCommand());
    56          head.nextEntry = tail;
    57      }
    58
    59      private IoHandlerCommand createHeadCommand() {
    60          return new IoHandlerCommand() {
    61              public void execute(NextCommand next, IoSession session,
    62                      Object message) throws Exception {
    63                  next.execute(session, message);
    64              }
    65          };
    66      }
    67
    68      private IoHandlerCommand createTailCommand() {
    69          return new IoHandlerCommand() {
    70              public void execute(NextCommand next, IoSession session,
    71                      Object message) throws Exception {
    72                  next = (NextCommand) session.getAttribute(NEXT_COMMAND);
    73                  if (next != null) {
    74                      next.execute(session, message);
    75                  }
    76              }
    77          };
    78      }
    79
    80      public Entry getEntry(String name) {
    81          Entry e = name2entry.get(name);
    82          if (e == null) {
    83              return null;
    84          }
    85          return e;
    86      }
    87
    88      public IoHandlerCommand get(String name) {
    89          Entry e = getEntry(name);
    90          if (e == null) {
    91              return null;
    92          }
    93
    94          return e.getCommand();
    95      }
    96
    97      public NextCommand getNextCommand(String name) {
    98          Entry e = getEntry(name);
    99          if (e == null) {
    100             return null;
    101         }
    102
    103         return e.getNextCommand();
    104     }
    105
    106     public synchronized void addFirst(String name, IoHandlerCommand command) {
    107         checkAddable(name);
    108         register(head, name, command);
    109     }
    110
    111     public synchronized void addLast(String name, IoHandlerCommand command) {
    112         checkAddable(name);
    113         register(tail.prevEntry, name, command);
    114     }
    115
    116     public synchronized void addBefore(String baseName, String name,
    117             IoHandlerCommand command) {
    118         Entry baseEntry = checkOldName(baseName);
    119         checkAddable(name);
    120         register(baseEntry.prevEntry, name, command);
    121     }
    122
    123     public synchronized void addAfter(String baseName, String name,
    124             IoHandlerCommand command) {
    125         Entry baseEntry = checkOldName(baseName);
    126         checkAddable(name);
    127         register(baseEntry, name, command);
    128     }
    129
    130     public synchronized IoHandlerCommand remove(String name) {
    131         Entry entry = checkOldName(name);
    132         deregister(entry);
    133         return entry.getCommand();
    134     }
    135
    136     public synchronized void clear() throws Exception {
    137         Iterator<String> it = new ArrayList<String>(name2entry.keySet())
    138                 .iterator();
    139         while (it.hasNext()) {
    140             this.remove(it.next());
    141         }
    142     }
    143
    144     private void register(Entry prevEntry, String name, IoHandlerCommand command) {
    145         Entry newEntry = new Entry(prevEntry, prevEntry.nextEntry, name,
    146                 command);
    147         prevEntry.nextEntry.prevEntry = newEntry;
    148         prevEntry.nextEntry = newEntry;
    149
    150         name2entry.put(name, newEntry);
    151     }
    152
    153     private void deregister(Entry entry) {
    154         Entry prevEntry = entry.prevEntry;
    155         Entry nextEntry = entry.nextEntry;
    156         prevEntry.nextEntry = nextEntry;
    157         nextEntry.prevEntry = prevEntry;
    158
    159         name2entry.remove(entry.name);
    160     }
    161
    162     /**
    163      * Throws an exception when the specified filter name is not registered in this chain.
    164      *
    165      * @return An filter entry with the specified name.
    166      */
    167     private Entry checkOldName(String baseName) {
    168         Entry e = name2entry.get(baseName);
    169         if (e == null) {
    170             throw new IllegalArgumentException("Unknown filter name:"
    171                     + baseName);
    172         }
    173         return e;
    174     }
    175
    176     /**
    177      * Checks the specified filter name is already taken and throws an exception if already taken.
    178      */
    179     private void checkAddable(String name) {
    180         if (name2entry.containsKey(name)) {
    181             throw new IllegalArgumentException(
    182                     "Other filter is using the same name '" + name + "'");
    183         }
    184     }
    185
    186     public void execute(NextCommand next, IoSession session, Object message)
    187             throws Exception {
    188         if (next != null) {
    189             session.setAttribute(NEXT_COMMAND, next);
    190         }
    191
    192         try {
    193             callNextCommand(head, session, message);
    194         } finally {
    195             session.removeAttribute(NEXT_COMMAND);
    196         }
    197     }
    198
    199     private void callNextCommand(Entry entry, IoSession session, Object message)
    200             throws Exception {
    201         entry.getCommand().execute(entry.getNextCommand(), session, message);
    202     }
    203
    204     public List<Entry> getAll() {
    205         List<Entry> list = new ArrayList<Entry>();
    206         Entry e = head.nextEntry;
    207         while (e != tail) {
    208             list.add(e);
    209             e = e.nextEntry;
    210         }
    211
    212         return list;
    213     }
    214
    215     public List<Entry> getAllReversed() {
    216         List<Entry> list = new ArrayList<Entry>();
    217         Entry e = tail.prevEntry;
    218         while (e != head) {
    219             list.add(e);
    220             e = e.prevEntry;
    221         }
    222         return list;
    223     }
    224
    225     public boolean contains(String name) {
    226         return getEntry(name) != null;
    227     }
    228
    229     public boolean contains(IoHandlerCommand command) {
    230         Entry e = head.nextEntry;
    231         while (e != tail) {
    232             if (e.getCommand() == command) {
    233                 return true;
    234             }
    235             e = e.nextEntry;
    236         }
    237         return false;
    238     }
    239
    240     public boolean contains(Class<? extends IoHandlerCommand> commandType) {
    241         Entry e = head.nextEntry;
    242         while (e != tail) {
    243             if (commandType.isAssignableFrom(e.getCommand().getClass())) {
    244                 return true;
    245             }
    246             e = e.nextEntry;
    247         }
    248         return false;
    249     }
    250
    251     public String toString() {
    252         StringBuffer buf = new StringBuffer();
    253         buf.append("{ ");
    254
    255         boolean empty = true;
    256
    257         Entry e = head.nextEntry;
    258         while (e != tail) {
    259             if (!empty) {
    260                 buf.append(", ");
    261             } else {
    262                 empty = false;
    263             }
    264
    265             buf.append('(');
    266             buf.append(e.getName());
    267             buf.append(':');
    268             buf.append(e.getCommand());
    269             buf.append(')');
    270
    271             e = e.nextEntry;
    272         }
    273
    274         if (empty) {
    275             buf.append("empty");
    276         }
    277
    278         buf.append(" }");
    279
    280         return buf.toString();
    281     }
    282
    283     /**
    284      * Represents a name-command pair that an {@link IoHandlerChain} contains.
    285      *
    286      * @author The Apache Directory Project (mina-dev@directory.apache.org)
    287      * @version $Rev: 555855 $, $Date: 2007-07-13 05:19:00 +0200 (Fri, 13 Jul 2007) $
    288      */
    289     public class Entry {
    290         private Entry prevEntry;
    291
    292         private Entry nextEntry;
    293
    294         private final String name;
    295
    296         private final IoHandlerCommand command;
    297
    298         private final NextCommand nextCommand;
    299
    300         private Entry(Entry prevEntry, Entry nextEntry, String name,
    301                 IoHandlerCommand command) {
    302             if (command == null) {
    303                 throw new NullPointerException("command");
    304             }
    305             if (name == null) {
    306                 throw new NullPointerException("name");
    307             }
    308
    309             this.prevEntry = prevEntry;
    310             this.nextEntry = nextEntry;
    311             this.name = name;
    312             this.command = command;
    313             this.nextCommand = new NextCommand() {
    314                 public void execute(IoSession session, Object message)
    315                         throws Exception {
    316                     Entry nextEntry = Entry.this.nextEntry;
    317                     callNextCommand(nextEntry, session, message);
    318                 }
    319             };
    320         }
    321
    322         /**
    323          * Returns the name of the command.
    324          */
    325         public String getName() {
    326             return name;
    327         }
    328
    329         /**
    330          * Returns the command.
    331          */
    332         public IoHandlerCommand getCommand() {
    333             return command;
    334         }
    335
    336         /**
    337          * Returns the {@link IoHandlerCommand.NextCommand} of the command.
    338          */
    339         public NextCommand getNextCommand() {
    340             return nextCommand;
    341         }
    342     }
    343 }