1 | /* |
2 | * @(#) $Id: AbstractProtocolFilterChain.java 327113 2005-10-21 06:59:15Z 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: 327113 $, $Date: 2005-10-21 15:59:15 +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 ProtocolFilter 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 | return 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, ProtocolFilter 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( ProtocolSession session ) |
295 | { |
296 | Entry head = this.head; |
297 | callNextSessionOpened(head, session); |
298 | } |
299 | |
300 | private void callNextSessionOpened( Entry entry, |
301 | ProtocolSession 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( ProtocolSession session ) |
314 | { |
315 | Entry head = this.head; |
316 | callNextSessionClosed(head, session); |
317 | } |
318 | |
319 | private void callNextSessionClosed( Entry entry, |
320 | ProtocolSession session ) |
321 | { |
322 | try |
323 | { |
324 | entry.filter.sessionClosed( entry.nextFilter, session ); |
325 | |
326 | } |
327 | catch( Throwable e ) |
328 | { |
329 | exceptionCaught( session, e ); |
330 | } |
331 | } |
332 | |
333 | public void sessionIdle( ProtocolSession session, IdleStatus status ) |
334 | { |
335 | Entry head = this.head; |
336 | callNextSessionIdle(head, session, status); |
337 | } |
338 | |
339 | private void callNextSessionIdle( Entry entry, |
340 | ProtocolSession session, |
341 | IdleStatus status ) |
342 | { |
343 | try |
344 | { |
345 | entry.filter.sessionIdle( entry.nextFilter, session, status ); |
346 | } |
347 | catch( Throwable e ) |
348 | { |
349 | exceptionCaught( session, e ); |
350 | } |
351 | } |
352 | |
353 | public void messageReceived( ProtocolSession session, Object message ) |
354 | { |
355 | Entry head = this.head; |
356 | callNextMessageReceived(head, session, message ); |
357 | } |
358 | |
359 | private void callNextMessageReceived( Entry entry, |
360 | ProtocolSession session, |
361 | Object message ) |
362 | { |
363 | try |
364 | { |
365 | entry.filter.messageReceived( entry.nextFilter, session, message ); |
366 | } |
367 | catch( Throwable e ) |
368 | { |
369 | exceptionCaught( session, e ); |
370 | } |
371 | } |
372 | |
373 | public void messageSent( ProtocolSession session, Object message ) |
374 | { |
375 | Entry head = this.head; |
376 | callNextMessageSent(head, session, message); |
377 | } |
378 | |
379 | private void callNextMessageSent( Entry entry, |
380 | ProtocolSession session, |
381 | Object message ) |
382 | { |
383 | try |
384 | { |
385 | entry.filter.messageSent( entry.nextFilter, session, message ); |
386 | } |
387 | catch( Throwable e ) |
388 | { |
389 | exceptionCaught( session, e ); |
390 | } |
391 | } |
392 | |
393 | public void exceptionCaught( ProtocolSession session, Throwable cause ) |
394 | { |
395 | Entry head = this.head; |
396 | callNextExceptionCaught(head, session, cause); |
397 | } |
398 | |
399 | private void callNextExceptionCaught( Entry entry, |
400 | ProtocolSession session, |
401 | Throwable cause ) |
402 | { |
403 | try |
404 | { |
405 | entry.filter.exceptionCaught( entry.nextFilter, session, cause ); |
406 | } |
407 | catch( Throwable e ) |
408 | { |
409 | e.printStackTrace(); |
410 | } |
411 | } |
412 | |
413 | public void filterWrite( ProtocolSession session, Object message ) |
414 | { |
415 | Entry tail = this.tail; |
416 | callPreviousFilterWrite( tail, session, message ); |
417 | } |
418 | |
419 | private void callPreviousFilterWrite( Entry entry, |
420 | ProtocolSession session, |
421 | Object message ) |
422 | { |
423 | if( message == null ) |
424 | { |
425 | return; |
426 | } |
427 | |
428 | try |
429 | { |
430 | entry.filter.filterWrite( entry.nextFilter, session, message ); |
431 | } |
432 | catch( Throwable e ) |
433 | { |
434 | exceptionCaught( session, e ); |
435 | } |
436 | } |
437 | |
438 | public List getChildren() |
439 | { |
440 | List list = new ArrayList(); |
441 | Entry e = head.nextEntry; |
442 | while( e != tail ) |
443 | { |
444 | list.add( e.filter ); |
445 | e = e.nextEntry; |
446 | } |
447 | |
448 | return list; |
449 | } |
450 | |
451 | public List getChildrenReversed() |
452 | { |
453 | List list = new ArrayList(); |
454 | Entry e = tail.prevEntry; |
455 | while( e != head ) |
456 | { |
457 | list.add( e.filter ); |
458 | e = e.prevEntry; |
459 | } |
460 | return list; |
461 | } |
462 | |
463 | protected abstract void doWrite( ProtocolSession session, Object message ); |
464 | |
465 | private class Entry |
466 | { |
467 | private Entry prevEntry; |
468 | |
469 | private Entry nextEntry; |
470 | |
471 | private final String name; |
472 | |
473 | private final ProtocolFilter filter; |
474 | |
475 | private final NextFilter nextFilter; |
476 | |
477 | private Entry( Entry prevEntry, Entry nextEntry, |
478 | String name, ProtocolFilter filter ) |
479 | { |
480 | if( filter == null ) |
481 | { |
482 | throw new NullPointerException( "filter" ); |
483 | } |
484 | if( name == null ) |
485 | { |
486 | throw new NullPointerException( "name" ); |
487 | } |
488 | |
489 | this.prevEntry = prevEntry; |
490 | this.nextEntry = nextEntry; |
491 | this.name = name; |
492 | this.filter = filter; |
493 | this.nextFilter = new NextFilter() |
494 | { |
495 | |
496 | public void sessionOpened( ProtocolSession session ) |
497 | { |
498 | Entry nextEntry = Entry.this.nextEntry; |
499 | callNextSessionOpened( nextEntry, session ); |
500 | } |
501 | |
502 | public void sessionClosed( ProtocolSession session ) |
503 | { |
504 | Entry nextEntry = Entry.this.nextEntry; |
505 | callNextSessionClosed( nextEntry, session ); |
506 | } |
507 | |
508 | public void sessionIdle( ProtocolSession session, IdleStatus status ) |
509 | { |
510 | Entry nextEntry = Entry.this.nextEntry; |
511 | callNextSessionIdle( nextEntry, session, status ); |
512 | } |
513 | |
514 | public void exceptionCaught( ProtocolSession session, |
515 | Throwable cause ) |
516 | { |
517 | Entry nextEntry = Entry.this.nextEntry; |
518 | callNextExceptionCaught( nextEntry, session, cause ); |
519 | } |
520 | |
521 | public void messageReceived( ProtocolSession session, Object message ) |
522 | { |
523 | Entry nextEntry = Entry.this.nextEntry; |
524 | callNextMessageReceived( nextEntry, session, message ); |
525 | } |
526 | |
527 | public void messageSent( ProtocolSession session, Object message ) |
528 | { |
529 | Entry nextEntry = Entry.this.nextEntry; |
530 | callNextMessageSent( nextEntry, session, message ); |
531 | } |
532 | |
533 | public void filterWrite( ProtocolSession session, Object message ) |
534 | { |
535 | Entry nextEntry = Entry.this.prevEntry; |
536 | callPreviousFilterWrite( nextEntry, session, message ); |
537 | } |
538 | }; |
539 | } |
540 | |
541 | public String getName() |
542 | { |
543 | return name; |
544 | } |
545 | |
546 | public ProtocolFilter getFilter() |
547 | { |
548 | return filter; |
549 | } |
550 | } |
551 | } |