View Javadoc

1   /*
2    *   @(#) $Id: AbstractProtocolFilterChain.java 210062 2005-07-11 03:52:38Z 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: 210062 $, $Date: 2005-07-11 12:52:38 +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 }