1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.handler.chain;
21
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.apache.mina.core.session.IoSession;
29
30
31
32
33
34
35 public class IoHandlerChain implements IoHandlerCommand {
36 private static volatile int nextId = 0;
37
38 private final int id = nextId++;
39
40 private final String NEXT_COMMAND = IoHandlerChain.class.getName() + '.' + id + ".nextCommand";
41
42 private final Map<String, Entry> name2entry = new ConcurrentHashMap<>();
43
44
45 private final Entry head;
46
47
48 private final Entry tail;
49
50
51
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
62
63
64 @Override
65 public void execute(NextCommand next, IoSession session, Object message) throws Exception {
66 next.execute(session, message);
67 }
68 };
69 }
70
71 private IoHandlerCommand createTailCommand() {
72 return new IoHandlerCommand() {
73
74
75
76 @Override
77 public void execute(NextCommand next, IoSession session, Object message) throws Exception {
78 next = (NextCommand) session.getAttribute(NEXT_COMMAND);
79
80 if (next != null) {
81 next.execute(session, message);
82 }
83 }
84 };
85 }
86
87
88
89
90
91
92 public Entry getEntry(String name) {
93 Entry e = name2entry.get(name);
94
95 if (e == null) {
96 return null;
97 }
98
99 return e;
100 }
101
102
103
104
105
106
107
108 public IoHandlerCommand get(String name) {
109 Entry e = getEntry(name);
110
111 if (e == null) {
112 return null;
113 }
114
115 return e.getCommand();
116 }
117
118
119
120
121
122
123
124
125 public NextCommand getNextCommand(String name) {
126 Entry e = getEntry(name);
127
128 if (e == null) {
129 return null;
130 }
131
132 return e.getNextCommand();
133 }
134
135
136
137
138
139
140
141 public synchronized void addFirst(String name, IoHandlerCommand command) {
142 checkAddable(name);
143 register(head, name, command);
144 }
145
146
147
148
149
150
151
152 public synchronized void addLast(String name, IoHandlerCommand command) {
153 checkAddable(name);
154 register(tail.prevEntry, name, command);
155 }
156
157
158
159
160
161
162
163
164 public synchronized void addBefore(String baseName, String name, IoHandlerCommand command) {
165 Entry baseEntry = checkOldName(baseName);
166 checkAddable(name);
167 register(baseEntry.prevEntry, name, command);
168 }
169
170
171
172
173
174
175
176
177 public synchronized void addAfter(String baseName, String name, IoHandlerCommand command) {
178 Entry baseEntry = checkOldName(baseName);
179 checkAddable(name);
180 register(baseEntry, name, command);
181 }
182
183
184
185
186
187
188
189 public synchronized IoHandlerCommand remove(String name) {
190 Entry entry = checkOldName(name);
191 deregister(entry);
192
193 return entry.getCommand();
194 }
195
196
197
198
199
200 public synchronized void clear() throws Exception {
201 Iterator<String> it = new ArrayList<String>(name2entry.keySet()).iterator();
202
203 while (it.hasNext()) {
204 remove(it.next());
205 }
206 }
207
208 private void register(Entry prevEntry, String name, IoHandlerCommand command) {
209 Entry newEntry = new Entry(prevEntry, prevEntry.nextEntry, name, command);
210 prevEntry.nextEntry.prevEntry = newEntry;
211 prevEntry.nextEntry = newEntry;
212
213 name2entry.put(name, newEntry);
214 }
215
216 private void deregister(Entry entry) {
217 Entry prevEntry = entry.prevEntry;
218 Entry nextEntry = entry.nextEntry;
219 prevEntry.nextEntry = nextEntry;
220 nextEntry.prevEntry = prevEntry;
221
222 name2entry.remove(entry.name);
223 }
224
225
226
227
228
229
230 private Entry checkOldName(String baseName) {
231 Entry e = name2entry.get(baseName);
232
233 if (e == null) {
234 throw new IllegalArgumentException("Unknown filter name:" + baseName);
235 }
236
237 return e;
238 }
239
240
241
242
243 private void checkAddable(String name) {
244 if (name2entry.containsKey(name)) {
245 throw new IllegalArgumentException("Other filter is using the same name '" + name + "'");
246 }
247 }
248
249
250
251
252 @Override
253 public void execute(NextCommand next, IoSession session, Object message) throws Exception {
254 if (next != null) {
255 session.setAttribute(NEXT_COMMAND, next);
256 }
257
258 try {
259 callNextCommand(head, session, message);
260 } finally {
261 session.removeAttribute(NEXT_COMMAND);
262 }
263 }
264
265 private void callNextCommand(Entry entry, IoSession session, Object message) throws Exception {
266 entry.getCommand().execute(entry.getNextCommand(), session, message);
267 }
268
269
270
271
272 public List<Entry> getAll() {
273 List<Entry> list = new ArrayList<>();
274 Entry e = head.nextEntry;
275
276 while (e != tail) {
277 list.add(e);
278 e = e.nextEntry;
279 }
280
281 return list;
282 }
283
284
285
286
287 public List<Entry> getAllReversed() {
288 List<Entry> list = new ArrayList<>();
289 Entry e = tail.prevEntry;
290
291 while (e != head) {
292 list.add(e);
293 e = e.prevEntry;
294 }
295
296 return list;
297 }
298
299
300
301
302
303
304
305 public boolean contains(String name) {
306 return getEntry(name) != null;
307 }
308
309
310
311
312
313
314
315 public boolean contains(IoHandlerCommand command) {
316 Entry e = head.nextEntry;
317 while (e != tail) {
318 if (e.getCommand() == command) {
319 return true;
320 }
321 e = e.nextEntry;
322 }
323 return false;
324 }
325
326
327
328
329
330
331
332 public boolean contains(Class<? extends IoHandlerCommand> commandType) {
333 Entry e = head.nextEntry;
334
335 while (e != tail) {
336 if (commandType.isAssignableFrom(e.getCommand().getClass())) {
337 return true;
338 }
339
340 e = e.nextEntry;
341 }
342
343 return false;
344 }
345
346
347
348
349 @Override
350 public String toString() {
351 StringBuilder buf = new StringBuilder();
352 buf.append("{ ");
353
354 boolean empty = true;
355
356 Entry e = head.nextEntry;
357
358 while (e != tail) {
359 if (!empty) {
360 buf.append(", ");
361 } else {
362 empty = false;
363 }
364
365 buf.append('(');
366 buf.append(e.getName());
367 buf.append(':');
368 buf.append(e.getCommand());
369 buf.append(')');
370
371 e = e.nextEntry;
372 }
373
374 if (empty) {
375 buf.append("empty");
376 }
377
378 buf.append(" }");
379
380 return buf.toString();
381 }
382
383
384
385
386
387
388 public class Entry {
389 private Entry prevEntry;
390
391 private Entry nextEntry;
392
393 private final String name;
394
395 private final IoHandlerCommand command;
396
397 private final NextCommand nextCommand;
398
399 private Entry(Entry prevEntry, Entry nextEntry, String name, IoHandlerCommand command) {
400 if (command == null) {
401 throw new IllegalArgumentException("command");
402 }
403
404 if (name == null) {
405 throw new IllegalArgumentException("name");
406 }
407
408 this.prevEntry = prevEntry;
409 this.nextEntry = nextEntry;
410 this.name = name;
411 this.command = command;
412 this.nextCommand = new NextCommand() {
413
414
415
416 @Override
417 public void execute(IoSession session, Object message) throws Exception {
418 callNextCommand(Entry.this.nextEntry, session, message);
419 }
420 };
421 }
422
423
424
425
426 public String getName() {
427 return name;
428 }
429
430
431
432
433 public IoHandlerCommand getCommand() {
434 return command;
435 }
436
437
438
439
440 public NextCommand getNextCommand() {
441 return nextCommand;
442 }
443 }
444 }