View Javadoc

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