1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.mina.io;
20
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.IdentityHashMap;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.apache.mina.common.ByteBuffer;
29 import org.apache.mina.common.IdleStatus;
30 import org.apache.mina.io.IoFilter.NextFilter;
31
32 /***
33 * An abstract implementation of {@link IoFilterChain} that provides
34 * common operations for developers to support specific transport types.
35 * <p>
36 * All methods has been implemented. The list of filters is maintained
37 * as a doublely linked list. You can fire any MINA events which is filtered
38 * by this chain using these public methods:
39 * <ul>
40 * <li></li>
41 * </ul>
42 *
43 * The only method a developer should implement is {@link #doWrite(IoSession, ByteBuffer, Object)}.
44 * This method is invoked when filter chain is evaluated for
45 * {@link IoFilter#filterWrite(NextFilter, IoSession, ByteBuffer, Object)} and
46 * finally to be written to the underlying transport layer (e.g. socket)
47 *
48 * @author The Apache Directory Project
49 * @version $Rev: 327113 $, $Date: 2005-10-21 15:59:15 +0900 $
50 */
51 public abstract class AbstractIoFilterChain implements IoFilterChain
52 {
53 private final Map name2entry = new HashMap();
54
55 private final Map filter2entry = new IdentityHashMap();
56
57 private final Entry head;
58
59 private final Entry tail;
60
61 protected AbstractIoFilterChain()
62 {
63 head = new Entry( null, null, "head", createHeadFilter() );
64 tail = new Entry( head, null, "tail", createTailFilter() );
65 head.nextEntry = tail;
66 }
67
68 /***
69 * Override this method to create custom head of this filter chain.
70 */
71 protected IoFilter createHeadFilter()
72 {
73 return new IoFilter()
74 {
75 public void sessionOpened( NextFilter nextFilter, IoSession session ) throws Exception
76 {
77 nextFilter.sessionOpened( session );
78 }
79
80 public void sessionClosed( NextFilter nextFilter, IoSession session ) throws Exception
81 {
82 nextFilter.sessionClosed( session );
83 }
84
85 public void sessionIdle( NextFilter nextFilter, IoSession session,
86 IdleStatus status ) throws Exception
87 {
88 nextFilter.sessionIdle( session, status );
89 }
90
91 public void exceptionCaught( NextFilter nextFilter,
92 IoSession session, Throwable cause ) throws Exception
93 {
94 nextFilter.exceptionCaught( session, cause );
95 }
96
97 public void dataRead( NextFilter nextFilter, IoSession session,
98 ByteBuffer buf ) throws Exception
99 {
100 nextFilter.dataRead( session, buf );
101 }
102
103 public void dataWritten( NextFilter nextFilter, IoSession session,
104 Object marker ) throws Exception
105 {
106 nextFilter.dataWritten( session, marker );
107 }
108
109 public void filterWrite( NextFilter nextFilter, IoSession session,
110 ByteBuffer buf, Object marker ) throws Exception
111 {
112 doWrite( session, buf, marker );
113 }
114 };
115 }
116
117 /***
118 * Override this method to create custom tail of this filter chain.
119 */
120 protected IoFilter createTailFilter()
121 {
122 return new IoFilter()
123 {
124 public void sessionOpened( NextFilter nextFilter, IoSession session ) throws Exception
125 {
126 session.getHandler().sessionOpened( session );
127 }
128
129 public void sessionClosed( NextFilter nextFilter, IoSession session ) throws Exception
130 {
131 session.getHandler().sessionClosed( session );
132 }
133
134 public void sessionIdle( NextFilter nextFilter, IoSession session,
135 IdleStatus status ) throws Exception
136 {
137 session.getHandler().sessionIdle( session, status );
138 }
139
140 public void exceptionCaught( NextFilter nextFilter,
141 IoSession session, Throwable cause ) throws Exception
142 {
143 session.getHandler().exceptionCaught( session, cause );
144 }
145
146 public void dataRead( NextFilter nextFilter, IoSession session,
147 ByteBuffer buf ) throws Exception
148 {
149 IoHandler handler = session.getHandler();
150 try
151 {
152 handler.dataRead( session, buf );
153 }
154 finally
155 {
156 buf.release();
157 }
158 }
159
160 public void dataWritten( NextFilter nextFilter, IoSession session,
161 Object marker ) throws Exception
162 {
163 session.getHandler().dataWritten( session, marker );
164 }
165
166 public void filterWrite( NextFilter nextFilter,
167 IoSession session, ByteBuffer buf, Object marker ) throws Exception
168 {
169 nextFilter.filterWrite( session, buf, marker );
170 }
171 };
172 }
173
174 public IoFilter getChild( String name )
175 {
176 Entry e = ( Entry ) name2entry.get( name );
177 if ( e == null )
178 {
179 return null;
180 }
181 return e.filter;
182 }
183
184 /***
185 * Adds the specified interceptor with the specified name at the beginning of this chain.
186 */
187 public synchronized void addFirst( String name,
188 IoFilter filter )
189 {
190 checkAddable( name );
191 register( head, name, filter );
192 }
193
194
195 /***
196 * Adds the specified interceptor with the specified name at the end of this chain.
197 */
198 public synchronized void addLast( String name,
199 IoFilter filter )
200 {
201 checkAddable( name );
202 register( tail.prevEntry, name, filter );
203 }
204
205
206 /***
207 * Adds the specified interceptor with the specified name just before the interceptor whose name is
208 * <code>baseName</code> in this chain.
209 */
210 public synchronized void addBefore( String baseName,
211 String name,
212 IoFilter filter )
213 {
214 Entry baseEntry = checkOldName( baseName );
215 checkAddable( name );
216 register( baseEntry, name, filter );
217 }
218
219
220 /***
221 * Adds the specified interceptor with the specified name just after the interceptor whose name is
222 * <code>baseName</code> in this chain.
223 */
224 public synchronized void addAfter( String baseName,
225 String name,
226 IoFilter filter )
227 {
228 Entry baseEntry = checkOldName( baseName );
229 checkAddable( name );
230 register( baseEntry.prevEntry, name, filter );
231 }
232
233
234 /***
235 * Removes the interceptor with the specified name from this chain.
236 */
237 public synchronized IoFilter remove( String name )
238 {
239 Entry entry = checkOldName( name );
240 Entry prevEntry = entry.prevEntry;
241 Entry nextEntry = entry.nextEntry;
242 prevEntry.nextEntry = nextEntry;
243 nextEntry.prevEntry = prevEntry;
244
245 name2entry.remove( name );
246 IoFilter filter = entry.filter;
247 filter2entry.remove( filter );
248
249 return filter;
250 }
251
252
253 /***
254 * Removes all interceptors added to this chain.
255 */
256 public synchronized void clear()
257 {
258 Iterator it = new ArrayList( name2entry.keySet() ).iterator();
259 while ( it.hasNext() )
260 {
261 this.remove( ( String ) it.next() );
262 }
263 }
264
265 private void register( Entry prevEntry, String name, IoFilter filter )
266 {
267 Entry newEntry = new Entry( prevEntry, prevEntry.nextEntry, name, filter );
268 prevEntry.nextEntry.prevEntry = newEntry;
269 prevEntry.nextEntry = newEntry;
270 name2entry.put( name, newEntry );
271 filter2entry.put( filter, newEntry );
272 }
273
274 /***
275 * Throws an exception when the specified interceptor name is not registered in this chain.
276 *
277 * @return An interceptor entry with the specified name.
278 */
279 private Entry checkOldName( String baseName )
280 {
281 Entry e = ( Entry ) name2entry.get( baseName );
282 if ( e == null )
283 {
284 throw new IllegalArgumentException( "Unknown interceptor name:" +
285 baseName );
286 }
287 return e;
288 }
289
290
291 /***
292 * Checks the specified interceptor name is already taken and throws an exception if already taken.
293 */
294 private void checkAddable( String name )
295 {
296 if ( name2entry.containsKey( name ) )
297 {
298 throw new IllegalArgumentException( "Other interceptor is using name '" + name + "'" );
299 }
300 }
301
302 public void sessionOpened( IoSession session )
303 {
304 Entry head = this.head;
305 callNextSessionOpened(head, session);
306 }
307
308 private void callNextSessionOpened( Entry entry,
309 IoSession session)
310 {
311 try
312 {
313 entry.filter.sessionOpened( entry.nextFilter, session );
314 }
315 catch( Throwable e )
316 {
317 exceptionCaught( session, e );
318 }
319 }
320
321 public void sessionClosed( IoSession session )
322 {
323 Entry head = this.head;
324 callNextSessionClosed(head, session);
325 }
326
327 private void callNextSessionClosed( Entry entry,
328 IoSession session )
329 {
330 try
331 {
332 entry.filter.sessionClosed( entry.nextFilter, session );
333 }
334 catch( Throwable e )
335 {
336 exceptionCaught( session, e );
337 }
338 }
339
340 public void sessionIdle( IoSession session, IdleStatus status )
341 {
342 Entry head = this.head;
343 callNextSessionIdle(head, session, status);
344 }
345
346 private void callNextSessionIdle( Entry entry,
347 IoSession session,
348 IdleStatus status )
349 {
350 try
351 {
352 entry.filter.sessionIdle( entry.nextFilter, session, status );
353 }
354 catch( Throwable e )
355 {
356 exceptionCaught( session, e );
357 }
358 }
359
360 public void dataRead( IoSession session, ByteBuffer buf )
361 {
362 Entry head = this.head;
363 callNextDataRead(head, session, buf);
364 }
365
366 private void callNextDataRead( Entry entry,
367 IoSession session,
368 ByteBuffer buf )
369 {
370 try
371 {
372 entry.filter.dataRead( entry.nextFilter, session, buf );
373 }
374 catch( Throwable e )
375 {
376 exceptionCaught( session, e );
377 }
378 }
379
380 public void dataWritten( IoSession session, Object marker )
381 {
382 Entry head = this.head;
383 callNextDataWritten(head, session, marker);
384 }
385
386 private void callNextDataWritten( Entry entry,
387 IoSession session,
388 Object marker )
389 {
390 try
391 {
392 entry.filter.dataWritten( entry.nextFilter, session, marker );
393 }
394 catch( Throwable e )
395 {
396 exceptionCaught( session, e );
397 }
398 }
399
400 public void exceptionCaught( IoSession session, Throwable cause )
401 {
402 Entry head = this.head;
403 callNextExceptionCaught(head, session, cause);
404 }
405
406 private void callNextExceptionCaught( Entry entry,
407 IoSession session,
408 Throwable cause )
409 {
410 try
411 {
412 entry.filter.exceptionCaught( entry.nextFilter, session, cause );
413 }
414 catch( Throwable e )
415 {
416 e.printStackTrace();
417 }
418 }
419
420 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
421 {
422 Entry tail = this.tail;
423 callPreviousFilterWrite( tail, session, buf, marker );
424 }
425
426 private void callPreviousFilterWrite( Entry entry,
427 IoSession session,
428 ByteBuffer buf, Object marker )
429 {
430 if( buf == null )
431 {
432 return;
433 }
434
435 try
436 {
437 entry.filter.filterWrite( entry.nextFilter, session, buf, marker );
438 }
439 catch( Throwable e )
440 {
441 exceptionCaught( session, e );
442 }
443 }
444
445 public List getChildren()
446 {
447 List list = new ArrayList();
448 Entry e = head.nextEntry;
449 while( e != tail )
450 {
451 list.add( e.filter );
452 e = e.nextEntry;
453 }
454
455 return list;
456 }
457
458 public List getChildrenReversed()
459 {
460 List list = new ArrayList();
461 Entry e = tail.prevEntry;
462 while( e != head )
463 {
464 list.add( e.filter );
465 e = e.prevEntry;
466 }
467 return list;
468 }
469
470 protected abstract void doWrite( IoSession session, ByteBuffer buffer, Object marker );
471
472 private class Entry
473 {
474 private Entry prevEntry;
475
476 private Entry nextEntry;
477
478 private final String name;
479
480 private final IoFilter filter;
481
482 private final NextFilter nextFilter;
483
484 private Entry( Entry prevEntry, Entry nextEntry,
485 String name, IoFilter filter )
486 {
487 if( filter == null )
488 {
489 throw new NullPointerException( "filter" );
490 }
491 if( name == null )
492 {
493 throw new NullPointerException( "name" );
494 }
495
496 this.prevEntry = prevEntry;
497 this.nextEntry = nextEntry;
498 this.name = name;
499 this.filter = filter;
500 this.nextFilter = new NextFilter()
501 {
502
503 public void sessionOpened( IoSession session )
504 {
505 Entry nextEntry = Entry.this.nextEntry;
506 callNextSessionOpened( nextEntry, session );
507 }
508
509 public void sessionClosed( IoSession session )
510 {
511 Entry nextEntry = Entry.this.nextEntry;
512 callNextSessionClosed( nextEntry, session );
513 }
514
515 public void sessionIdle( IoSession session, IdleStatus status )
516 {
517 Entry nextEntry = Entry.this.nextEntry;
518 callNextSessionIdle( nextEntry, session, status );
519 }
520
521 public void exceptionCaught( IoSession session,
522 Throwable cause )
523 {
524 Entry nextEntry = Entry.this.nextEntry;
525 callNextExceptionCaught( nextEntry, session, cause );
526 }
527
528 public void dataRead( IoSession session, ByteBuffer buf )
529 {
530 Entry nextEntry = Entry.this.nextEntry;
531 callNextDataRead( nextEntry, session, buf );
532 }
533
534 public void dataWritten( IoSession session, Object marker )
535 {
536 Entry nextEntry = Entry.this.nextEntry;
537 callNextDataWritten( nextEntry, session, marker );
538 }
539
540 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
541 {
542 Entry nextEntry = Entry.this.prevEntry;
543 callPreviousFilterWrite( nextEntry, session, buf, marker );
544 }
545 };
546 }
547
548 public String getName()
549 {
550 return name;
551 }
552
553 public IoFilter getFilter()
554 {
555 return filter;
556 }
557 }
558 }