View Javadoc

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 }