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: 169321 $, $Date: 2005-05-10 00:00:25 +0900 (?, 10 5? 2005) $
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 void 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
244
245 /***
246 * Removes all interceptors added to this chain.
247 */
248 public synchronized void clear()
249 {
250 Iterator it = new ArrayList( name2entry.keySet() ).iterator();
251 while ( it.hasNext() )
252 {
253 this.remove( ( String ) it.next() );
254 }
255 }
256
257 private void register( Entry prevEntry, String name, IoFilter filter )
258 {
259 Entry newEntry = new Entry( prevEntry, prevEntry.nextEntry, name, filter );
260 prevEntry.nextEntry.prevEntry = newEntry;
261 prevEntry.nextEntry = newEntry;
262 name2entry.put( name, newEntry );
263 filter2entry.put( filter, newEntry );
264 }
265
266 /***
267 * Throws an exception when the specified interceptor name is not registered in this chain.
268 *
269 * @return An interceptor entry with the specified name.
270 */
271 private Entry checkOldName( String baseName )
272 {
273 Entry e = ( Entry ) name2entry.get( baseName );
274 if ( e == null )
275 {
276 throw new IllegalArgumentException( "Unknown interceptor name:" +
277 baseName );
278 }
279 return e;
280 }
281
282
283 /***
284 * Checks the specified interceptor name is already taken and throws an exception if already taken.
285 */
286 private void checkAddable( String name )
287 {
288 if ( name2entry.containsKey( name ) )
289 {
290 throw new IllegalArgumentException( "Other interceptor is using name '" + name + "'" );
291 }
292 }
293
294 public void sessionOpened( IoSession session )
295 {
296 Entry head = this.head;
297 callNextSessionOpened(head, session);
298 }
299
300 private void callNextSessionOpened( Entry entry,
301 IoSession session)
302 {
303 try
304 {
305 entry.filter.sessionOpened( entry.nextFilter, session );
306 }
307 catch( Throwable e )
308 {
309 exceptionCaught( session, e );
310 }
311 }
312
313 public void sessionClosed( IoSession session )
314 {
315 Entry head = this.head;
316 callNextSessionClosed(head, session);
317 }
318
319 private void callNextSessionClosed( Entry entry,
320 IoSession session )
321 {
322 try
323 {
324 entry.filter.sessionClosed( entry.nextFilter, session );
325 }
326 catch( Throwable e )
327 {
328 exceptionCaught( session, e );
329 }
330 }
331
332 public void sessionIdle( IoSession session, IdleStatus status )
333 {
334 Entry head = this.head;
335 callNextSessionIdle(head, session, status);
336 }
337
338 private void callNextSessionIdle( Entry entry,
339 IoSession session,
340 IdleStatus status )
341 {
342 try
343 {
344 entry.filter.sessionIdle( entry.nextFilter, session, status );
345 }
346 catch( Throwable e )
347 {
348 exceptionCaught( session, e );
349 }
350 }
351
352 public void dataRead( IoSession session, ByteBuffer buf )
353 {
354 Entry head = this.head;
355 callNextDataRead(head, session, buf);
356 }
357
358 private void callNextDataRead( Entry entry,
359 IoSession session,
360 ByteBuffer buf )
361 {
362 try
363 {
364 entry.filter.dataRead( entry.nextFilter, session, buf );
365 }
366 catch( Throwable e )
367 {
368 exceptionCaught( session, e );
369 }
370 }
371
372 public void dataWritten( IoSession session, Object marker )
373 {
374 Entry head = this.head;
375 callNextDataWritten(head, session, marker);
376 }
377
378 private void callNextDataWritten( Entry entry,
379 IoSession session,
380 Object marker )
381 {
382 try
383 {
384 entry.filter.dataWritten( entry.nextFilter, session, marker );
385 }
386 catch( Throwable e )
387 {
388 exceptionCaught( session, e );
389 }
390 }
391
392 public void exceptionCaught( IoSession session, Throwable cause )
393 {
394 Entry head = this.head;
395 callNextExceptionCaught(head, session, cause);
396 }
397
398 private void callNextExceptionCaught( Entry entry,
399 IoSession session,
400 Throwable cause )
401 {
402 try
403 {
404 entry.filter.exceptionCaught( entry.nextFilter, session, cause );
405 }
406 catch( Throwable e )
407 {
408 e.printStackTrace();
409 }
410 }
411
412 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
413 {
414 Entry tail = this.tail;
415 callPreviousFilterWrite( tail, session, buf, marker );
416 }
417
418 private void callPreviousFilterWrite( Entry entry,
419 IoSession session,
420 ByteBuffer buf, Object marker )
421 {
422 if( buf == null )
423 {
424 return;
425 }
426
427 try
428 {
429 entry.filter.filterWrite( entry.nextFilter, session, buf, marker );
430 }
431 catch( Throwable e )
432 {
433 exceptionCaught( session, e );
434 }
435 }
436
437 public List getChildren()
438 {
439 List list = new ArrayList();
440 Entry e = head.nextEntry;
441 while( e != tail )
442 {
443 list.add( e.filter );
444 e = e.nextEntry;
445 }
446
447 return list;
448 }
449
450 public List getChildrenReversed()
451 {
452 List list = new ArrayList();
453 Entry e = tail.prevEntry;
454 while( e != head )
455 {
456 list.add( e.filter );
457 e = e.prevEntry;
458 }
459 return list;
460 }
461
462 protected abstract void doWrite( IoSession session, ByteBuffer buffer, Object marker );
463
464 private class Entry
465 {
466 private Entry prevEntry;
467
468 private Entry nextEntry;
469
470 private final String name;
471
472 private final IoFilter filter;
473
474 private final NextFilter nextFilter;
475
476 private Entry( Entry prevEntry, Entry nextEntry,
477 String name, IoFilter filter )
478 {
479 if( filter == null )
480 {
481 throw new NullPointerException( "filter" );
482 }
483 if( name == null )
484 {
485 throw new NullPointerException( "name" );
486 }
487
488 this.prevEntry = prevEntry;
489 this.nextEntry = nextEntry;
490 this.name = name;
491 this.filter = filter;
492 this.nextFilter = new NextFilter()
493 {
494
495 public void sessionOpened( IoSession session )
496 {
497 Entry nextEntry = Entry.this.nextEntry;
498 callNextSessionOpened( nextEntry, session );
499 }
500
501 public void sessionClosed( IoSession session )
502 {
503 Entry nextEntry = Entry.this.nextEntry;
504 callNextSessionClosed( nextEntry, session );
505 }
506
507 public void sessionIdle( IoSession session, IdleStatus status )
508 {
509 Entry nextEntry = Entry.this.nextEntry;
510 callNextSessionIdle( nextEntry, session, status );
511 }
512
513 public void exceptionCaught( IoSession session,
514 Throwable cause )
515 {
516 Entry nextEntry = Entry.this.nextEntry;
517 callNextExceptionCaught( nextEntry, session, cause );
518 }
519
520 public void dataRead( IoSession session, ByteBuffer buf )
521 {
522 Entry nextEntry = Entry.this.nextEntry;
523 callNextDataRead( nextEntry, session, buf );
524 }
525
526 public void dataWritten( IoSession session, Object marker )
527 {
528 Entry nextEntry = Entry.this.nextEntry;
529 callNextDataWritten( nextEntry, session, marker );
530 }
531
532 public void filterWrite( IoSession session, ByteBuffer buf, Object marker )
533 {
534 Entry nextEntry = Entry.this.prevEntry;
535 callPreviousFilterWrite( nextEntry, session, buf, marker );
536 }
537 };
538 }
539
540 public String getName()
541 {
542 return name;
543 }
544
545 public IoFilter getFilter()
546 {
547 return filter;
548 }
549 }
550 }