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