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