KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ldap > server > interceptor > InterceptorChain


1 /*
2  * Copyright 2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.apache.ldap.server.interceptor;
18
19
20 import org.apache.ldap.server.authn.AuthenticationService;
21 import org.apache.ldap.server.invocation.Invocation;
22 import org.apache.ldap.server.authz.AuthorizationService;
23 import org.apache.ldap.server.schema.SchemaService;
24 import org.apache.ldap.server.operational.OperationalAttributeService;
25 import org.apache.ldap.server.exception.ExceptionService;
26 import org.apache.ldap.server.normalization.NormalizationService;
27
28 import javax.naming.NamingException JavaDoc;
29 import java.util.*;
30
31
32 /**
33  * Manages the chain of {@link Interceptor}s. <tt>InterceptorChain</tt>
34  * is also an {@link Interceptor}, and thus you can create hiararchical
35  * interceptor structure to break down complex interceptors.
36  * <p/>
37  * {@link org.apache.ldap.server.jndi.JndiProvider#invoke(Invocation)}
38  * redirects {@link Invocation}s to {@link #process(NextInterceptor, Invocation)}
39  * and the chain starts.
40  *
41  * @author <a HREF="mailto:dev@directory.apache.org">Apache Directory Project</a>
42  * @version $Rev: 169198 $, $Date: 2005-05-08 20:05:59 -0400 (Sun, 08 May 2005) $
43  */

44 public class InterceptorChain implements Interceptor
45 {
46     /**
47      * The name of default interceptor that passes its control to the
48      * next interceptor in parent chain.
49      */

50     public static final String JavaDoc NEXT_INTERCEPTOR = "nextInterceptor";
51
52
53     /**
54      * Returns a new chain of default interceptors required to run core.
55      */

56     public static InterceptorChain newDefaultChain()
57     {
58         InterceptorChain chain = new InterceptorChain();
59
60         chain.addFirst( "normalizationService", new NormalizationService() );
61
62         chain.addBefore( NEXT_INTERCEPTOR, "authenticationService", new AuthenticationService() );
63
64         chain.addBefore( NEXT_INTERCEPTOR, "authorizationService", new AuthorizationService() );
65
66         chain.addBefore( NEXT_INTERCEPTOR, "exceptionService", new ExceptionService() );
67
68         chain.addBefore( NEXT_INTERCEPTOR, "schemaService", new SchemaService() );
69
70         chain.addBefore( NEXT_INTERCEPTOR, "operationalAttributeService", new OperationalAttributeService() );
71
72         return chain;
73     }
74
75
76     private final Interceptor NEXT_INTERCEPTOR0 = new Interceptor()
77     {
78         public void init( InterceptorContext context )
79         {
80         }
81
82
83         public void destroy()
84         {
85         }
86
87
88         public void process( NextInterceptor nextInterceptor, Invocation invocation ) throws NamingException JavaDoc
89         {
90             if( parent != null )
91             {
92                 Entry e = ( Entry ) parent.interceptor2entry.get( InterceptorChain.this );
93
94                 e.nextInterceptor.process( invocation );
95             }
96
97             nextInterceptor.process( invocation );
98         }
99     };
100
101
102     private final Interceptor FINAL_INTERCEPTOR = new Interceptor()
103     {
104         private InterceptorContext ctx;
105
106
107         public void init( InterceptorContext context )
108         {
109             ctx = context;
110         }
111
112
113         public void destroy()
114         {
115             // unused
116
}
117
118
119         public void process( NextInterceptor nextInterceptor, Invocation call ) throws NamingException JavaDoc
120         {
121             if ( parent == null )
122             {
123                 // execute the actual backend operation only when this chain is root.
124

125                 call.execute( ctx.getRootNexus() );
126             }
127         }
128     };
129
130     private InterceptorChain parent;
131
132     private final Map name2entry = new HashMap();
133
134     private final Map interceptor2entry = new IdentityHashMap();
135
136     private Entry head = new Entry( null, null, NEXT_INTERCEPTOR, NEXT_INTERCEPTOR0 );
137
138     private final Entry tail = new Entry( null, null, "end", FINAL_INTERCEPTOR );
139
140
141     /**
142      * Create a new interceptor chain.
143      */

144     public InterceptorChain()
145     {
146         head.nextEntry = tail;
147
148         tail.prevEntry = head;
149
150         register( NEXT_INTERCEPTOR, head );
151     }
152
153
154     /**
155      * Initializes all interceptors this chain contains.
156      */

157     public synchronized void init( InterceptorContext ctx ) throws NamingException JavaDoc
158     {
159         ListIterator it = getAll().listIterator();
160
161         Interceptor interceptor = null;
162
163         try
164         {
165             while ( it.hasNext() )
166             {
167                 interceptor = ( Interceptor ) it.next();
168
169                 String JavaDoc name = getName( interceptor );
170
171                 Map config = InterceptorConfigBuilder.build( ctx.getConfig(), ( name == null ) ? "" : name );
172
173                 InterceptorContext newCtx = new InterceptorContext( ctx.getEnvironment(),
174                         ctx.getSystemPartition(), ctx.getGlobalRegistries(), ctx.getRootNexus(), config );
175
176                 interceptor.init( newCtx );
177             }
178         }
179         catch ( Throwable JavaDoc t )
180         {
181             while ( it.hasPrevious() )
182             {
183                 Interceptor i = ( Interceptor ) it.previous();
184
185                 try
186                 {
187                     i.destroy();
188                 }
189                 catch ( Throwable JavaDoc t2 )
190                 {
191                     t2.printStackTrace();
192                 }
193             }
194
195             if ( t instanceof NamingException JavaDoc )
196             {
197                 throw ( NamingException JavaDoc ) t;
198             }
199             else
200             {
201                 throw new InterceptorException( interceptor, null, "Failed to initialize interceptor chain.", t );
202             }
203         }
204     }
205
206
207     /**
208      * Deinitializes all interceptors this chain contains.
209      */

210     public synchronized void destroy()
211     {
212         ListIterator it = getAllReversed().listIterator();
213
214         while ( it.hasNext() )
215         {
216             Interceptor interceptor = ( Interceptor ) it.next();
217
218             try
219             {
220                 interceptor.destroy();
221             }
222             catch ( Throwable JavaDoc t )
223             {
224                 t.printStackTrace();
225             }
226         }
227     }
228
229
230     /**
231      * Returns the interceptor with the specified <code>name</code>.
232      *
233      * @return <code>null</code> if there is no interceptor with the specified <code>name</code>.
234      */

235     public Interceptor get( String JavaDoc name )
236     {
237         Entry e = ( Entry ) name2entry.get( name );
238
239         if ( e == null )
240         {
241             return null;
242         }
243
244         return e.interceptor;
245     }
246
247
248     private String JavaDoc getName( Interceptor interceptor )
249     {
250         Entry e = ( Entry ) interceptor2entry.get( interceptor );
251
252         if ( e == null )
253         {
254             return null;
255         }
256
257         return e.name;
258     }
259
260
261     /**
262      * Adds the specified interceptor with the specified name at the beginning of this chain.
263      */

264     public synchronized void addFirst( String JavaDoc name,
265                                        Interceptor interceptor )
266     {
267         checkAddable( name, interceptor );
268
269         Entry newEntry = new Entry( null, head, name, interceptor );
270
271         head.prevEntry = newEntry;
272
273         head = newEntry;
274
275         register( name, newEntry );
276     }
277
278
279     /**
280      * Adds the specified interceptor with the specified name at the end of this chain.
281      */

282     public synchronized void addLast( String JavaDoc name,
283                                       Interceptor interceptor )
284     {
285         checkAddable( name, interceptor );
286
287         Entry newEntry = new Entry( tail.prevEntry, tail, name, interceptor );
288
289         if ( tail.prevEntry != null )
290         {
291             tail.prevEntry.nextEntry = newEntry;
292         }
293         else
294         {
295             head = newEntry;
296         }
297
298         tail.prevEntry = newEntry;
299
300         register( name, newEntry );
301     }
302
303
304     /**
305      * Adds the specified interceptor with the specified name just before the interceptor whose name is
306      * <code>baseName</code> in this chain.
307      */

308     public synchronized void addBefore( String JavaDoc baseName, String JavaDoc name, Interceptor interceptor )
309     {
310         Entry baseEntry = checkOldName( baseName );
311
312         checkAddable( name, interceptor );
313
314         Entry prevEntry = baseEntry.prevEntry;
315
316         Entry newEntry = new Entry( prevEntry, baseEntry, name, interceptor );
317
318         if ( prevEntry == null )
319         {
320             baseEntry.prevEntry = newEntry;
321
322             head = newEntry;
323             
324         }
325         else
326         {
327             baseEntry.prevEntry = newEntry;
328
329             prevEntry.nextEntry = newEntry;
330         }
331
332         register( name, newEntry );
333     }
334
335
336     /**
337      * Adds the specified interceptor with the specified name just after the interceptor whose name is
338      * <code>baseName</code> in this chain.
339      */

340     public synchronized void addAfter( String JavaDoc baseName, String JavaDoc name, Interceptor interceptor )
341     {
342         Entry baseEntry = checkOldName( baseName );
343
344         checkAddable( name, interceptor );
345
346         Entry nextEntry = baseEntry.nextEntry;
347
348         Entry newEntry = new Entry( baseEntry, nextEntry, name, interceptor );
349
350         if ( nextEntry == null )
351         {
352             throw new IllegalStateException JavaDoc();
353         }
354
355         nextEntry.prevEntry.nextEntry = newEntry;
356
357         nextEntry.prevEntry = newEntry;
358
359         register( name, newEntry );
360     }
361
362
363     /**
364      * Removes the interceptor with the specified name from this chain.
365      */

366     public synchronized void remove( String JavaDoc name )
367     {
368         Entry entry = checkOldName( name );
369
370         Entry prevEntry = entry.prevEntry;
371
372         Entry nextEntry = entry.nextEntry;
373
374         if ( prevEntry == null )
375         {
376             nextEntry.prevEntry = null;
377
378             head = entry;
379         }
380         else
381         {
382             prevEntry.nextEntry = nextEntry;
383
384             nextEntry.prevEntry = prevEntry;
385         }
386
387         name2entry.remove( name );
388
389         Interceptor interceptor = entry.interceptor;
390
391         interceptor2entry.remove( interceptor );
392
393         if ( interceptor instanceof InterceptorChain )
394         {
395             ( ( InterceptorChain ) interceptor ).parent = null;
396         }
397     }
398
399
400     /**
401      * Removes all interceptors added to this chain.
402      */

403     public synchronized void clear()
404     {
405         Iterator it = new ArrayList( name2entry.keySet() ).iterator();
406
407         while ( it.hasNext() )
408         {
409             this.remove( ( String JavaDoc ) it.next() );
410         }
411     }
412
413
414     private void register( String JavaDoc name, Entry newEntry )
415     {
416         Interceptor interceptor = newEntry.interceptor;
417
418         name2entry.put( name, newEntry );
419
420         interceptor2entry.put( newEntry.interceptor, newEntry );
421
422         if ( interceptor instanceof InterceptorChain )
423         {
424             ( ( InterceptorChain ) interceptor ).parent = this;
425         }
426     }
427
428
429     /**
430      * Throws an exception when the specified interceptor name is not registered in this chain.
431      *
432      * @return An interceptor entry with the specified name.
433      */

434     private Entry checkOldName( String JavaDoc baseName )
435     {
436         Entry e = ( Entry ) name2entry.get( baseName );
437
438         if ( e == null )
439         {
440             throw new IllegalArgumentException JavaDoc( "Unknown interceptor name:" + baseName );
441         }
442
443         return e;
444     }
445
446
447     /**
448      * Checks the specified interceptor name is already taken and throws an exception if already taken.
449      */

450     private void checkAddable( String JavaDoc name, Interceptor interceptor )
451     {
452         if ( name2entry.containsKey( name ) )
453         {
454             throw new IllegalArgumentException JavaDoc( "Other interceptor is using name '" + name + "'" );
455         }
456
457         if ( interceptor instanceof InterceptorChain )
458         {
459             if ( ( ( InterceptorChain ) interceptor ).parent != null )
460             {
461                 throw new IllegalArgumentException JavaDoc( "This interceptor chain has its parent already." );
462             }
463         }
464     }
465
466
467     /**
468      * Start invocation chain with the specified invocation.
469      *
470      * @throws NamingException if invocation failed
471      */

472     public void process( NextInterceptor nextInterceptor, Invocation invocation ) throws NamingException JavaDoc
473     {
474         Entry head = this.head;
475
476         try
477         {
478             head.interceptor.process( head.nextInterceptor, invocation );
479         }
480         catch ( NamingException JavaDoc ne )
481         {
482             throw ne;
483         }
484         catch ( Throwable JavaDoc e )
485         {
486             throw new InterceptorException( head.interceptor, invocation, "Unexpected exception.", e );
487         }
488     }
489
490
491     /**
492      * Returns the list of interceptors this chain in the order of evaluation.
493      */

494     public List getAll()
495     {
496         List list = new ArrayList();
497
498         Entry e = head;
499
500         do
501         {
502             list.add( e.interceptor );
503
504             e = e.nextEntry;
505         }
506         while ( e != null );
507
508         return list;
509     }
510
511
512     /**
513      * Returns the list of interceptors this chain in the reversed order of evaluation.
514      */

515     public List getAllReversed()
516     {
517         List list = new ArrayList();
518
519         Entry e = tail;
520
521         do
522         {
523             list.add( e.interceptor );
524
525             e = e.prevEntry;
526         }
527
528         while ( e != null );
529
530         return list;
531     }
532
533
534     /**
535      * Represents an internal entry of this chain.
536      */

537     private class Entry
538     {
539         private Entry prevEntry;
540
541         private Entry nextEntry;
542
543         private final String JavaDoc name;
544
545         private final Interceptor interceptor;
546
547         private final NextInterceptor nextInterceptor;
548
549
550         private Entry( Entry prevEntry, Entry nextEntry,
551                        String JavaDoc name, Interceptor interceptor )
552         {
553             if ( interceptor == null )
554             {
555                 throw new NullPointerException JavaDoc( "interceptor" );
556             }
557             if ( name == null )
558             {
559                 throw new NullPointerException JavaDoc( "name" );
560             }
561
562             this.prevEntry = prevEntry;
563
564             this.nextEntry = nextEntry;
565
566             this.name = name;
567
568             this.interceptor = interceptor;
569
570             this.nextInterceptor = new NextInterceptor()
571             {
572                 public void process( Invocation call ) throws NamingException JavaDoc
573                 {
574                     Interceptor interceptor = Entry.this.nextEntry.interceptor;
575
576                     try
577                     {
578                         interceptor.process( Entry.this.nextEntry.nextInterceptor, call );
579                     }
580                     catch ( NamingException JavaDoc ne )
581                     {
582                         throw ne;
583                     }
584                     catch ( Throwable JavaDoc e )
585                     {
586                         throw new InterceptorException( interceptor, call, "Unexpected exception.", e );
587                     }
588                 }
589             };
590         }
591     }
592 }
593
Popular Tags