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 12:19:00 +0900 (금, 13  7월 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 name2entry = new HashMap();
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 = (Entry) 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 it = new ArrayList(name2entry.keySet()).iterator();
138         while (it.hasNext()) {
139             this.remove((String) it.next());
140         }
141     }
142 
143     private void register(Entry prevEntry, String name, IoHandlerCommand command) {
144         Entry newEntry = new Entry(prevEntry, prevEntry.nextEntry, name,
145                 command);
146         prevEntry.nextEntry.prevEntry = newEntry;
147         prevEntry.nextEntry = newEntry;
148 
149         name2entry.put(name, newEntry);
150     }
151 
152     private void deregister(Entry entry) {
153         Entry prevEntry = entry.prevEntry;
154         Entry nextEntry = entry.nextEntry;
155         prevEntry.nextEntry = nextEntry;
156         nextEntry.prevEntry = prevEntry;
157 
158         name2entry.remove(entry.name);
159     }
160 
161     /**
162      * Throws an exception when the specified filter name is not registered in this chain.
163      *
164      * @return An filter entry with the specified name.
165      */
166     private Entry checkOldName(String baseName) {
167         Entry e = (Entry) name2entry.get(baseName);
168         if (e == null) {
169             throw new IllegalArgumentException("Unknown filter name:"
170                     + baseName);
171         }
172         return e;
173     }
174 
175     /**
176      * Checks the specified filter name is already taken and throws an exception if already taken.
177      */
178     private void checkAddable(String name) {
179         if (name2entry.containsKey(name)) {
180             throw new IllegalArgumentException(
181                     "Other filter is using the same name '" + name + "'");
182         }
183     }
184 
185     public void execute(NextCommand next, IoSession session, Object message)
186             throws Exception {
187         if (next != null) {
188             session.setAttribute(NEXT_COMMAND, next);
189         }
190 
191         try {
192             callNextCommand(head, session, message);
193         } finally {
194             session.removeAttribute(NEXT_COMMAND);
195         }
196     }
197 
198     private void callNextCommand(Entry entry, IoSession session, Object message)
199             throws Exception {
200         entry.getCommand().execute(entry.getNextCommand(), session, message);
201     }
202 
203     public List getAll() {
204         List list = new ArrayList();
205         Entry e = head.nextEntry;
206         while (e != tail) {
207             list.add(e);
208             e = e.nextEntry;
209         }
210 
211         return list;
212     }
213 
214     public List getAllReversed() {
215         List list = new ArrayList();
216         Entry e = tail.prevEntry;
217         while (e != head) {
218             list.add(e);
219             e = e.prevEntry;
220         }
221         return list;
222     }
223 
224     public boolean contains(String name) {
225         return getEntry(name) != null;
226     }
227 
228     public boolean contains(IoHandlerCommand command) {
229         Entry e = head.nextEntry;
230         while (e != tail) {
231             if (e.getCommand() == command) {
232                 return true;
233             }
234             e = e.nextEntry;
235         }
236         return false;
237     }
238 
239     public boolean contains(Class commandType) {
240         Entry e = head.nextEntry;
241         while (e != tail) {
242             if (commandType.isAssignableFrom(e.getCommand().getClass())) {
243                 return true;
244             }
245             e = e.nextEntry;
246         }
247         return false;
248     }
249 
250     public String toString() {
251         StringBuffer buf = new StringBuffer();
252         buf.append("{ ");
253 
254         boolean empty = true;
255 
256         Entry e = head.nextEntry;
257         while (e != tail) {
258             if (!empty) {
259                 buf.append(", ");
260             } else {
261                 empty = false;
262             }
263 
264             buf.append('(');
265             buf.append(e.getName());
266             buf.append(':');
267             buf.append(e.getCommand());
268             buf.append(')');
269 
270             e = e.nextEntry;
271         }
272 
273         if (empty) {
274             buf.append("empty");
275         }
276 
277         buf.append(" }");
278 
279         return buf.toString();
280     }
281 
282     /**
283      * Represents a name-command pair that an {@link IoHandlerChain} contains.
284      *
285      * @author The Apache Directory Project (mina-dev@directory.apache.org)
286      * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13  7월 2007) $
287      */
288     public class Entry {
289         private Entry prevEntry;
290 
291         private Entry nextEntry;
292 
293         private final String name;
294 
295         private final IoHandlerCommand command;
296 
297         private final NextCommand nextCommand;
298 
299         private Entry(Entry prevEntry, Entry nextEntry, String name,
300                 IoHandlerCommand command) {
301             if (command == null) {
302                 throw new NullPointerException("command");
303             }
304             if (name == null) {
305                 throw new NullPointerException("name");
306             }
307 
308             this.prevEntry = prevEntry;
309             this.nextEntry = nextEntry;
310             this.name = name;
311             this.command = command;
312             this.nextCommand = new NextCommand() {
313                 public void execute(IoSession session, Object message)
314                         throws Exception {
315                     Entry nextEntry = Entry.this.nextEntry;
316                     callNextCommand(nextEntry, session, message);
317                 }
318             };
319         }
320 
321         /**
322          * Returns the name of the command.
323          */
324         public String getName() {
325             return name;
326         }
327 
328         /**
329          * Returns the command.
330          */
331         public IoHandlerCommand getCommand() {
332             return command;
333         }
334 
335         /**
336          * Returns the {@link IoHandlerCommand.NextCommand} of the command.
337          */
338         public NextCommand getNextCommand() {
339             return nextCommand;
340         }
341     }
342 }