1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;
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: 159467 $, $Date: 2005-03-30 02:38:30 -0500 (Wed, 30 Mar 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 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
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
116 }
117
118
119 public void process( NextInterceptor nextInterceptor, Invocation call ) throws NamingException
120 {
121 if ( parent == null )
122 {
123
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
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 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 t )
180 {
181 while ( it.hasPrevious() )
182 {
183 Interceptor i = ( Interceptor ) it.previous();
184
185 try
186 {
187 i.destroy();
188 }
189 catch ( Throwable t2 )
190 {
191 t2.printStackTrace();
192 }
193 }
194
195 if ( t instanceof NamingException )
196 {
197 throw ( NamingException ) 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 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 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 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 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 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 baseName, String 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 baseName, String 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();
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 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 ) it.next() );
410 }
411 }
412
413
414 private void register( String 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 baseName )
435 {
436 Entry e = ( Entry ) name2entry.get( baseName );
437
438 if ( e == null )
439 {
440 throw new IllegalArgumentException( "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 name, Interceptor interceptor )
451 {
452 if ( name2entry.containsKey( name ) )
453 {
454 throw new IllegalArgumentException( "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( "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
473 {
474 Entry head = this.head;
475
476 try
477 {
478 head.interceptor.process( head.nextInterceptor, invocation );
479 }
480 catch ( NamingException ne )
481 {
482 throw ne;
483 }
484 catch ( Throwable 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 name;
544
545 private final Interceptor interceptor;
546
547 private final NextInterceptor nextInterceptor;
548
549
550 private Entry( Entry prevEntry, Entry nextEntry,
551 String name, Interceptor interceptor )
552 {
553 if ( interceptor == null )
554 {
555 throw new NullPointerException( "interceptor" );
556 }
557 if ( name == null )
558 {
559 throw new NullPointerException( "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
573 {
574 Interceptor interceptor = Entry.this.nextEntry.interceptor;
575
576 try
577 {
578 interceptor.process( Entry.this.nextEntry.nextInterceptor, call );
579 }
580 catch ( NamingException ne )
581 {
582 throw ne;
583 }
584 catch ( Throwable e )
585 {
586 throw new InterceptorException( interceptor, call, "Unexpected exception.", e );
587 }
588 }
589 };
590 }
591 }
592 }