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: 210062 $, $Date: 2005-07-11 12:52:38 +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 handler.dataRead( session, buf );
151 buf.release();
152 }
153
154 public void dataWritten( NextFilter nextFilter, IoSession session,
155 Object marker ) throws Exception
156 {
157 session.getHandler().dataWritten( session, marker );
158 }
159
160 public void filterWrite( NextFilter nextFilter,
161 IoSession session, ByteBuffer buf, Object marker ) throws Exception
162 {
163 nextFilter.filterWrite( session, buf, marker );
164 }
165 };
166 }
167
168 public IoFilter getChild( String name )
169 {
170 Entry e = ( Entry ) name2entry.get( name );
171 if ( e == null )
172 {
173 return null;
174 }
175 return e.filter;
176 }
177
178 /***
179 * Adds the specified interceptor with the specified name at the beginning of this chain.
180 */
181 public synchronized void addFirst( String name,
182 IoFilter filter )
183 {
184 checkAddable( name );
185 register( head, name, filter );
186 }
187
188
189 /***
190 * Adds the specified interceptor with the specified name at the end of this chain.
191 */
192 public synchronized void addLast( String name,
193 IoFilter filter )
194 {
195 checkAddable( name );
196 register( tail.prevEntry, name, filter );
197 }
198
199
200 /***
201 * Adds the specified interceptor with the specified name just before the interceptor whose name is
202 * <code>baseName</code> in this chain.
203 */
204 public synchronized void addBefore( String baseName,
205 String name,
206 IoFilter filter )
207 {
208 Entry baseEntry = checkOldName( baseName );
209 checkAddable( name );
210 register( baseEntry, name, filter );
211 }
212
213
214 /***
215 * Adds the specified interceptor with the specified name just after the interceptor whose name is
216 * <code>baseName</code> in this chain.
217 */
218 public synchronized void addAfter( String baseName,
219 String name,
220 IoFilter filter )
221 {
222 Entry baseEntry = checkOldName( baseName );
223 checkAddable( name );
224 register( baseEntry.prevEntry, name, filter );
225 }
226
227
228 /***
229 * Removes the interceptor with the specified name from this chain.
230 */
231 public synchronized IoFilter remove( String name )
232 {
233 Entry entry = checkOldName( name );
234 Entry prevEntry = entry.prevEntry;
235 Entry nextEntry = entry.nextEntry;
236 prevEntry.nextEntry = nextEntry;
237 nextEntry.prevEntry = prevEntry;
238
239 name2entry.remove( name );
240 IoFilter filter = entry.filter;
241 filter2entry.remove( filter );
242
243 return filter;
244 }
245
246
247 /***
248 * Removes all interceptors added to this chain.
249 */
250 public synchronized void clear()
251 {
252 Iterator it = new ArrayList( name2entry.keySet() ).iterator();
253 while ( it.hasNext() )
254 {
255 this.remove( ( String ) it.next() );
256 }
257 }
258
259 private void register( Entry prevEntry, String name, IoFilter filter )
260 {
261 Entry newEntry = new Entry( prevEntry, prevEntry.nextEntry, name, filter );
262 prevEntry.nextEntry.prevEntry = newEntry;
263 prevEntry.nextEntry = newEntry;
264 name2entry.put( name, newEntry );
265 filter2entry.put( filter, newEntry );
266 }
267
268 /***
269 * Throws an exception when the specified interceptor name is not registered in this chain.
270 *
271 * @return An interceptor entry with the specified name.
272 */
273 private Entry checkOldName( String baseName )
274 {
275 Entry e = ( Entry ) name2entry.get( baseName );
276 if ( e == null )
277 {
278 throw new IllegalArgumentException( "Unknown interceptor name:" +
279 baseName );
280 }
281 return e;
282 }
283
284
285 /***
286 * Checks the specified interceptor name is already taken and throws an exception if already taken.
287 */
288 private void checkAddable( String name )
289 {
290 if ( name2entry.containsKey( name ) )
291 {
292 throw new IllegalArgumentException( "Other interceptor is using name '" + name + "'" );
293 }
294 }
295
296 public void sessionOpened( IoSession session )
297 {
298 Entry head = this.head;
299 callNextSessionOpened(head, session);
300 }
301
302 private void callNextSessionOpened( Entry entry,
303 IoSession session)
304 {
305 try
306 {
307 entry.filter.sessionOpened( entry.nextFilter, session );
308 }
309 catch( Throwable e )
310 {
311 exceptionCaught( session, e );
312 }
313 }
314
315 public void sessionClosed( IoSession session )
316 {
317 Entry head = this.head;
318 callNextSessionClosed(head, session);
319 }
320
321 private void callNextSessionClosed( Entry entry,
322 IoSession session )
323 {
324 try
325 {
326 entry.filter.sessionClosed( entry.nextFilter, session );
327 }
328 catch( Throwable e )
329 {
330 exceptionCaught( session, e );
331 }
332 }
333
334 public void sessionIdle( IoSession session, IdleStatus status )
335 {
336 Entry head = this.head;
337 callNextSessionIdle(head, session, status);
338 }
339
340 private void callNextSessionIdle( Entry entry,
341 IoSession session,
342 IdleStatus status )
343 {
344 try
345 {
346 entry.filter.sessionIdle( entry.nextFilter, session, status );
347 }
348 catch( Throwable e )
349 {
350 exceptionCaught( session, e );
351 }
352 }
353
354 public void dataRead( IoSession session, ByteBuffer buf )
355 {
356 Entry head = this.head;
357 callNextDataRead(head, session, buf);
358 }
359
360 private void callNextDataRead( Entry entry,
361 IoSession session,
362 ByteBuffer buf )
363 {
364 try
365 {
366 entry.filter.dataRead( entry.nextFilter, session, buf );
367 }
368 catch( Throwable e )
369 {
370 exceptionCaught( session, e );
371 }
372 }
373
374 public void dataWritten( IoSession session, Object marker )
375 {
376 Entry head = this.head;
377 callNextDataWritten(head, session, marker);
378 }
379
380 private void callNextDataWritten( Entry entry,
381 IoSession session,
382 Object marker )
383 {
384 try
385 {
386 entry.filter.dataWritten( entry.nextFilter, session, marker );
387 }
388 catch( Throwable e )
389 {
390 exceptionCaught( session, e );
391 }
392 }
393
394 public void exceptionCaught( IoSession session, Throwable cause )
395 {
396 Entry head = this.head;
397 callNextExceptionCaught(head, session, cause);
398 }
399
400 private void callNextExceptionCaught( Entry entry,
401 IoSession session,
402 Throwable cause )
403 {
404 try
405 {
406 entry.filter.exceptionCaught( entry.nextFilter, session, cause );
407 }
408 catch( Throwable e )
409 {
410 e.printStackTrace();
411 }
412 }
413
414 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
415 {
416 Entry tail = this.tail;
417 callPreviousFilterWrite( tail, session, buf, marker );
418 }
419
420 private void callPreviousFilterWrite( Entry entry,
421 IoSession session,
422 ByteBuffer buf, Object marker )
423 {
424 if( buf == null )
425 {
426 return;
427 }
428
429 try
430 {
431 entry.filter.filterWrite( entry.nextFilter, session, buf, marker );
432 }
433 catch( Throwable e )
434 {
435 exceptionCaught( session, e );
436 }
437 }
438
439 public List getChildren()
440 {
441 List list = new ArrayList();
442 Entry e = head.nextEntry;
443 while( e != tail )
444 {
445 list.add( e.filter );
446 e = e.nextEntry;
447 }
448
449 return list;
450 }
451
452 public List getChildrenReversed()
453 {
454 List list = new ArrayList();
455 Entry e = tail.prevEntry;
456 while( e != head )
457 {
458 list.add( e.filter );
459 e = e.prevEntry;
460 }
461 return list;
462 }
463
464 protected abstract void doWrite( IoSession session, ByteBuffer buffer, Object marker );
465
466 private class Entry
467 {
468 private Entry prevEntry;
469
470 private Entry nextEntry;
471
472 private final String name;
473
474 private final IoFilter filter;
475
476 private final NextFilter nextFilter;
477
478 private Entry( Entry prevEntry, Entry nextEntry,
479 String name, IoFilter filter )
480 {
481 if( filter == null )
482 {
483 throw new NullPointerException( "filter" );
484 }
485 if( name == null )
486 {
487 throw new NullPointerException( "name" );
488 }
489
490 this.prevEntry = prevEntry;
491 this.nextEntry = nextEntry;
492 this.name = name;
493 this.filter = filter;
494 this.nextFilter = new NextFilter()
495 {
496
497 public void sessionOpened( IoSession session )
498 {
499 Entry nextEntry = Entry.this.nextEntry;
500 callNextSessionOpened( nextEntry, session );
501 }
502
503 public void sessionClosed( IoSession session )
504 {
505 Entry nextEntry = Entry.this.nextEntry;
506 callNextSessionClosed( nextEntry, session );
507 }
508
509 public void sessionIdle( IoSession session, IdleStatus status )
510 {
511 Entry nextEntry = Entry.this.nextEntry;
512 callNextSessionIdle( nextEntry, session, status );
513 }
514
515 public void exceptionCaught( IoSession session,
516 Throwable cause )
517 {
518 Entry nextEntry = Entry.this.nextEntry;
519 callNextExceptionCaught( nextEntry, session, cause );
520 }
521
522 public void dataRead( IoSession session, ByteBuffer buf )
523 {
524 Entry nextEntry = Entry.this.nextEntry;
525 callNextDataRead( nextEntry, session, buf );
526 }
527
528 public void dataWritten( IoSession session, Object marker )
529 {
530 Entry nextEntry = Entry.this.nextEntry;
531 callNextDataWritten( nextEntry, session, marker );
532 }
533
534 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
535 {
536 Entry nextEntry = Entry.this.prevEntry;
537 callPreviousFilterWrite( nextEntry, session, buf, marker );
538 }
539 };
540 }
541
542 public String getName()
543 {
544 return name;
545 }
546
547 public IoFilter getFilter()
548 {
549 return filter;
550 }
551 }
552 }