001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.handler.chain;
021:
022: import java.util.ArrayList;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: import org.apache.mina.common.IoSession;
029:
030: /**
031: * A chain of {@link IoHandlerCommand}s.
032: *
033: * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
034: * @version $Rev: 576217 $, $Date: 2007-09-16 17:55:27 -0600 (Sun, 16 Sep 2007) $
035: */
036: public class IoHandlerChain implements IoHandlerCommand {
037: private static volatile int nextId = 0;
038:
039: private final int id = nextId++;
040:
041: private final String NEXT_COMMAND = IoHandlerChain.class.getName()
042: + '.' + id + ".nextCommand";
043:
044: private final Map<String, Entry> name2entry = new HashMap<String, Entry>();
045:
046: private final Entry head;
047:
048: private final Entry tail;
049:
050: /**
051: * Creates a new, empty chain of {@link IoHandlerCommand}s.
052: */
053: public IoHandlerChain() {
054: head = new Entry(null, null, "head", createHeadCommand());
055: tail = new Entry(head, null, "tail", createTailCommand());
056: head.nextEntry = tail;
057: }
058:
059: private IoHandlerCommand createHeadCommand() {
060: return new IoHandlerCommand() {
061: public void execute(NextCommand next, IoSession session,
062: Object message) throws Exception {
063: next.execute(session, message);
064: }
065: };
066: }
067:
068: private IoHandlerCommand createTailCommand() {
069: return new IoHandlerCommand() {
070: public void execute(NextCommand next, IoSession session,
071: Object message) throws Exception {
072: next = (NextCommand) session.getAttribute(NEXT_COMMAND);
073: if (next != null) {
074: next.execute(session, message);
075: }
076: }
077: };
078: }
079:
080: public Entry getEntry(String name) {
081: Entry e = name2entry.get(name);
082: if (e == null) {
083: return null;
084: }
085: return e;
086: }
087:
088: public IoHandlerCommand get(String name) {
089: Entry e = getEntry(name);
090: if (e == null) {
091: return null;
092: }
093:
094: return e.getCommand();
095: }
096:
097: public NextCommand getNextCommand(String name) {
098: Entry e = getEntry(name);
099: if (e == null) {
100: return null;
101: }
102:
103: return e.getNextCommand();
104: }
105:
106: public synchronized void addFirst(String name,
107: IoHandlerCommand command) {
108: checkAddable(name);
109: register(head, name, command);
110: }
111:
112: public synchronized void addLast(String name,
113: IoHandlerCommand command) {
114: checkAddable(name);
115: register(tail.prevEntry, name, command);
116: }
117:
118: public synchronized void addBefore(String baseName, String name,
119: IoHandlerCommand command) {
120: Entry baseEntry = checkOldName(baseName);
121: checkAddable(name);
122: register(baseEntry.prevEntry, name, command);
123: }
124:
125: public synchronized void addAfter(String baseName, String name,
126: IoHandlerCommand command) {
127: Entry baseEntry = checkOldName(baseName);
128: checkAddable(name);
129: register(baseEntry, name, command);
130: }
131:
132: public synchronized IoHandlerCommand remove(String name) {
133: Entry entry = checkOldName(name);
134: deregister(entry);
135: return entry.getCommand();
136: }
137:
138: public synchronized void clear() throws Exception {
139: Iterator<String> it = new ArrayList<String>(name2entry.keySet())
140: .iterator();
141: while (it.hasNext()) {
142: this .remove(it.next());
143: }
144: }
145:
146: private void register(Entry prevEntry, String name,
147: IoHandlerCommand command) {
148: Entry newEntry = new Entry(prevEntry, prevEntry.nextEntry,
149: name, command);
150: prevEntry.nextEntry.prevEntry = newEntry;
151: prevEntry.nextEntry = newEntry;
152:
153: name2entry.put(name, newEntry);
154: }
155:
156: private void deregister(Entry entry) {
157: Entry prevEntry = entry.prevEntry;
158: Entry nextEntry = entry.nextEntry;
159: prevEntry.nextEntry = nextEntry;
160: nextEntry.prevEntry = prevEntry;
161:
162: name2entry.remove(entry.name);
163: }
164:
165: /**
166: * Throws an exception when the specified filter name is not registered in this chain.
167: *
168: * @return An filter entry with the specified name.
169: */
170: private Entry checkOldName(String baseName) {
171: Entry e = name2entry.get(baseName);
172: if (e == null) {
173: throw new IllegalArgumentException("Unknown filter name:"
174: + baseName);
175: }
176: return e;
177: }
178:
179: /**
180: * Checks the specified filter name is already taken and throws an exception if already taken.
181: */
182: private void checkAddable(String name) {
183: if (name2entry.containsKey(name)) {
184: throw new IllegalArgumentException(
185: "Other filter is using the same name '" + name
186: + "'");
187: }
188: }
189:
190: public void execute(NextCommand next, IoSession session,
191: Object message) throws Exception {
192: if (next != null) {
193: session.setAttribute(NEXT_COMMAND, next);
194: }
195:
196: try {
197: callNextCommand(head, session, message);
198: } finally {
199: session.removeAttribute(NEXT_COMMAND);
200: }
201: }
202:
203: private void callNextCommand(Entry entry, IoSession session,
204: Object message) throws Exception {
205: entry.getCommand().execute(entry.getNextCommand(), session,
206: message);
207: }
208:
209: public List<Entry> getAll() {
210: List<Entry> list = new ArrayList<Entry>();
211: Entry e = head.nextEntry;
212: while (e != tail) {
213: list.add(e);
214: e = e.nextEntry;
215: }
216:
217: return list;
218: }
219:
220: public List<Entry> getAllReversed() {
221: List<Entry> list = new ArrayList<Entry>();
222: Entry e = tail.prevEntry;
223: while (e != head) {
224: list.add(e);
225: e = e.prevEntry;
226: }
227: return list;
228: }
229:
230: public boolean contains(String name) {
231: return getEntry(name) != null;
232: }
233:
234: public boolean contains(IoHandlerCommand command) {
235: Entry e = head.nextEntry;
236: while (e != tail) {
237: if (e.getCommand() == command) {
238: return true;
239: }
240: e = e.nextEntry;
241: }
242: return false;
243: }
244:
245: public boolean contains(
246: Class<? extends IoHandlerCommand> commandType) {
247: Entry e = head.nextEntry;
248: while (e != tail) {
249: if (commandType.isAssignableFrom(e.getCommand().getClass())) {
250: return true;
251: }
252: e = e.nextEntry;
253: }
254: return false;
255: }
256:
257: @Override
258: public String toString() {
259: StringBuffer buf = new StringBuffer();
260: buf.append("{ ");
261:
262: boolean empty = true;
263:
264: Entry e = head.nextEntry;
265: while (e != tail) {
266: if (!empty) {
267: buf.append(", ");
268: } else {
269: empty = false;
270: }
271:
272: buf.append('(');
273: buf.append(e.getName());
274: buf.append(':');
275: buf.append(e.getCommand());
276: buf.append(')');
277:
278: e = e.nextEntry;
279: }
280:
281: if (empty) {
282: buf.append("empty");
283: }
284:
285: buf.append(" }");
286:
287: return buf.toString();
288: }
289:
290: /**
291: * Represents a name-command pair that an {@link IoHandlerChain} contains.
292: *
293: * @author The Apache MINA Project (dev@mina.apache.org)
294: * @version $Rev: 576217 $, $Date: 2007-09-16 17:55:27 -0600 (Sun, 16 Sep 2007) $
295: */
296: public class Entry {
297: private Entry prevEntry;
298:
299: private Entry nextEntry;
300:
301: private final String name;
302:
303: private final IoHandlerCommand command;
304:
305: private final NextCommand nextCommand;
306:
307: private Entry(Entry prevEntry, Entry nextEntry, String name,
308: IoHandlerCommand command) {
309: if (command == null) {
310: throw new NullPointerException("command");
311: }
312: if (name == null) {
313: throw new NullPointerException("name");
314: }
315:
316: this .prevEntry = prevEntry;
317: this .nextEntry = nextEntry;
318: this .name = name;
319: this .command = command;
320: this .nextCommand = new NextCommand() {
321: public void execute(IoSession session, Object message)
322: throws Exception {
323: Entry nextEntry = Entry.this .nextEntry;
324: callNextCommand(nextEntry, session, message);
325: }
326: };
327: }
328:
329: /**
330: * Returns the name of the command.
331: */
332: public String getName() {
333: return name;
334: }
335:
336: /**
337: * Returns the command.
338: */
339: public IoHandlerCommand getCommand() {
340: return command;
341: }
342:
343: /**
344: * Returns the {@link IoHandlerCommand.NextCommand} of the command.
345: */
346: public NextCommand getNextCommand() {
347: return nextCommand;
348: }
349: }
350: }
|