View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  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,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.interceptor;
21  
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.directory.server.core.DirectoryService;
30  import org.apache.directory.server.core.entry.ClonedServerEntry;
31  import org.apache.directory.server.core.filtering.EntryFilteringCursor;
32  import org.apache.directory.server.core.interceptor.context.AddContextPartitionOperationContext;
33  import org.apache.directory.server.core.interceptor.context.AddOperationContext;
34  import org.apache.directory.server.core.interceptor.context.BindOperationContext;
35  import org.apache.directory.server.core.interceptor.context.CompareOperationContext;
36  import org.apache.directory.server.core.interceptor.context.DeleteOperationContext;
37  import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
38  import org.apache.directory.server.core.interceptor.context.GetMatchedNameOperationContext;
39  import org.apache.directory.server.core.interceptor.context.GetRootDSEOperationContext;
40  import org.apache.directory.server.core.interceptor.context.GetSuffixOperationContext;
41  import org.apache.directory.server.core.interceptor.context.ListOperationContext;
42  import org.apache.directory.server.core.interceptor.context.ListSuffixOperationContext;
43  import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
44  import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
45  import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext;
46  import org.apache.directory.server.core.interceptor.context.MoveOperationContext;
47  import org.apache.directory.server.core.interceptor.context.OperationContext;
48  import org.apache.directory.server.core.interceptor.context.RemoveContextPartitionOperationContext;
49  import org.apache.directory.server.core.interceptor.context.RenameOperationContext;
50  import org.apache.directory.server.core.interceptor.context.SearchOperationContext;
51  import org.apache.directory.server.core.interceptor.context.UnbindOperationContext;
52  import org.apache.directory.server.core.invocation.InvocationStack;
53  import org.apache.directory.server.core.partition.ByPassConstants;
54  import org.apache.directory.server.core.partition.PartitionNexus;
55  import org.apache.directory.shared.ldap.name.LdapDN;
56  import org.slf4j.Logger;
57  import org.slf4j.LoggerFactory;
58  
59  import javax.naming.ConfigurationException;
60  
61  
62  /**
63   * Manages the chain of {@link Interceptor}s.
64   *
65   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
66   * @version $Rev: 691853 $, $Date: 2008-09-04 03:41:23 +0200 (Do, 04 Sep 2008) $
67   */
68  public class InterceptorChain
69  {
70      private static final Logger LOG = LoggerFactory.getLogger( InterceptorChain.class );
71  
72      /** Speedup for logs */
73      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
74  
75      private final Interceptor FINAL_INTERCEPTOR = new Interceptor()
76      {
77          private PartitionNexus nexus;
78  
79  
80          public String getName()
81          {
82              return "FINAL";
83          }
84  
85          public void init( DirectoryService directoryService )
86          {
87              this.nexus = directoryService.getPartitionNexus();
88          }
89  
90  
91          public void destroy()
92          {
93              // unused
94          }
95  
96  
97          public boolean compare( NextInterceptor next, CompareOperationContext opContext ) throws Exception
98          {
99              return nexus.compare( opContext );
100         }
101 
102 
103         public ClonedServerEntry getRootDSE( NextInterceptor next, GetRootDSEOperationContext opContext ) throws Exception
104         {
105             return nexus.getRootDSE( opContext );
106         }
107 
108 
109         public LdapDN getMatchedName( NextInterceptor next, GetMatchedNameOperationContext opContext ) throws Exception
110         {
111             return ( LdapDN ) nexus.getMatchedName( opContext ).clone();
112         }
113 
114 
115         public LdapDN getSuffix( NextInterceptor next, GetSuffixOperationContext opContext ) throws Exception
116         {
117             return ( LdapDN ) nexus.getSuffix( opContext ).clone();
118         }
119 
120 
121         public Iterator<String> listSuffixes( NextInterceptor next, ListSuffixOperationContext opContext ) throws Exception
122         {
123             return nexus.listSuffixes( opContext );
124         }
125 
126 
127         public void delete( NextInterceptor next, DeleteOperationContext opContext ) throws Exception
128         {
129             nexus.delete( opContext );
130         }
131 
132 
133         public void add( NextInterceptor next, AddOperationContext opContext ) throws Exception
134         {
135             nexus.add( opContext );
136         }
137 
138 
139         public void modify( NextInterceptor next, ModifyOperationContext opContext ) throws Exception
140         {
141             nexus.modify( opContext );
142         }
143 
144 
145         public EntryFilteringCursor list( NextInterceptor next, ListOperationContext opContext ) throws Exception
146         {
147             return nexus.list( opContext );
148         }
149 
150 
151         public EntryFilteringCursor search( NextInterceptor next, SearchOperationContext opContext ) throws Exception
152         {
153             return nexus.search( opContext );
154         }
155 
156 
157         public ClonedServerEntry lookup( NextInterceptor next, LookupOperationContext opContext ) throws Exception
158         {
159             return nexus.lookup( opContext );
160         }
161 
162 
163         public boolean hasEntry( NextInterceptor next, EntryOperationContext opContext ) throws Exception
164         {
165             return nexus.hasEntry( opContext );
166         }
167 
168 
169         public void rename( NextInterceptor next, RenameOperationContext opContext )
170             throws Exception
171         {
172             nexus.rename( opContext );
173         }
174 
175 
176         public void move( NextInterceptor next, MoveOperationContext opContext ) throws Exception
177         {
178             nexus.move( opContext );
179         }
180 
181 
182         public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext opContext )
183             throws Exception
184         {
185             nexus.moveAndRename( opContext );
186         }
187 
188 
189         public void addContextPartition( NextInterceptor next, AddContextPartitionOperationContext opContext )
190             throws Exception
191         {
192             nexus.addContextPartition( opContext );
193         }
194 
195 
196         public void removeContextPartition( NextInterceptor next, RemoveContextPartitionOperationContext opContext ) throws Exception
197         {
198             nexus.removeContextPartition( opContext );
199         }
200 
201 
202         public void bind( NextInterceptor next, BindOperationContext opContext )  throws Exception
203         {
204             nexus.bind( opContext );
205         }
206 
207 
208         public void unbind( NextInterceptor next, UnbindOperationContext opContext ) throws Exception
209         {
210             nexus.unbind( opContext );
211         }
212     };
213 
214     private final Map<String, Entry> name2entry = new HashMap<String, Entry>();
215 
216     private final Entry tail;
217 
218     private Entry head;
219 
220     private DirectoryService directoryService;
221 
222 
223     /**
224      * Create a new interceptor chain.
225      */
226     public InterceptorChain()
227     {
228         tail = new Entry( "tail", null, null, FINAL_INTERCEPTOR );
229         head = tail;
230     }
231 
232 
233     /**
234      * Initializes and registers all interceptors according to the specified
235      * {@link DirectoryService}.
236      * @throws javax.naming.Exception if an interceptor cannot be initialized.
237      * @param directoryService the directory core
238      */
239     public synchronized void init( DirectoryService directoryService ) throws Exception
240     {
241         // Initialize tail first.
242         this.directoryService = directoryService;
243         FINAL_INTERCEPTOR.init( directoryService );
244 
245         // And register and initialize all interceptors
246         try
247         {
248             for ( Interceptor interceptor: directoryService.getInterceptors() )
249             {
250                 if ( IS_DEBUG )
251                 {
252                     LOG.debug( "Adding interceptor " + interceptor.getName() );
253                 }
254 
255                 register( interceptor );
256             }
257         }
258         catch ( Throwable t )
259         {
260             // destroy if failed to initialize all interceptors.
261             destroy();
262 
263             if ( t instanceof Exception )
264             {
265                 throw ( Exception ) t;
266             }
267             else
268             {
269                 throw new InterceptorException( null, "Failed to initialize interceptor chain.", t );
270             }
271         }
272     }
273 
274 
275     /**
276      * Deinitializes and deregisters all interceptors this chain contains.
277      */
278     public synchronized void destroy()
279     {
280         List<Entry> entries = new ArrayList<Entry>();
281         Entry e = tail;
282 
283         do
284         {
285             entries.add( e );
286             e = e.prevEntry;
287         }
288         while ( e != null );
289 
290         for ( Entry entry:entries )
291         {
292             if ( entry != tail )
293             {
294                 try
295                 {
296                     deregister( entry.getName() );
297                 }
298                 catch ( Throwable t )
299                 {
300                     LOG.warn( "Failed to deregister an interceptor: " + entry.getName(), t );
301                 }
302             }
303         }
304     }
305 
306 
307     /**
308      * Returns the registered interceptor with the specified name.
309      * @param interceptorName name of the interceptor to look for
310      * @return <tt>null</tt> if the specified name doesn't exist.
311      */
312     public Interceptor get( String interceptorName )
313     {
314         Entry e = name2entry.get( interceptorName );
315         if ( e == null )
316         {
317             return null;
318         }
319 
320         return e.interceptor;
321     }
322 
323 
324     /**
325      * Returns the list of all registered interceptors.
326      * @return a list of all the registered interceptors.
327      */
328     public synchronized List<Interceptor> getAll()
329     {
330         List<Interceptor> result = new ArrayList<Interceptor>();
331         Entry e = head;
332 
333         do
334         {
335             result.add( e.interceptor );
336             e = e.nextEntry;
337         }
338         while ( e != tail );
339 
340         return result;
341     }
342 
343 
344     public synchronized void addFirst( Interceptor interceptor ) throws Exception
345     {
346         register0( interceptor, head );
347     }
348 
349 
350     public synchronized void addLast( Interceptor interceptor ) throws Exception
351     {
352         register0( interceptor, tail );
353     }
354 
355 
356     public synchronized void addBefore( String nextInterceptorName, Interceptor interceptor )
357         throws Exception
358     {
359         Entry e = name2entry.get( nextInterceptorName );
360         if ( e == null )
361         {
362             throw new ConfigurationException( "Interceptor not found: " + nextInterceptorName );
363         }
364         register0( interceptor, e );
365     }
366 
367 
368     public synchronized String remove( String interceptorName ) throws Exception
369     {
370         return deregister( interceptorName );
371     }
372 
373 
374     public synchronized void addAfter( String prevInterceptorName, Interceptor interceptor )
375         throws Exception
376     {
377         Entry e = name2entry.get( prevInterceptorName );
378         if ( e == null )
379         {
380             throw new ConfigurationException( "Interceptor not found: " + prevInterceptorName );
381         }
382         register0( interceptor, e.nextEntry );
383     }
384 
385 
386     /**
387      * Adds and initializes an interceptor with the specified configuration.
388      * @param interceptor interceptor to add to end of chain
389      * @throws javax.naming.Exception if there is already an interceptor of this name or the interceptor
390      * cannot be initialized.
391      */
392     private void register( Interceptor interceptor ) throws Exception
393     {
394         checkAddable( interceptor );
395         register0( interceptor, tail );
396     }
397 
398 
399     /**
400      * Removes and deinitializes the interceptor with the specified name.
401      * @param name name of interceptor to remove
402      * @return name of interceptor removed, if any
403      * @throws javax.naming.ConfigurationException if no interceptor registered under that name
404      */
405     private String deregister( String name ) throws ConfigurationException
406     {
407         Entry entry = checkOldName( name );
408         Entry prevEntry = entry.prevEntry;
409         Entry nextEntry = entry.nextEntry;
410 
411         if ( nextEntry == null )
412         {
413             // Don't deregister tail
414             return null;
415         }
416 
417         if ( prevEntry == null )
418         {
419             nextEntry.prevEntry = null;
420             head = nextEntry;
421         }
422         else
423         {
424             prevEntry.nextEntry = nextEntry;
425             nextEntry.prevEntry = prevEntry;
426         }
427 
428         name2entry.remove( name );
429         entry.interceptor.destroy();
430 
431         return entry.getName();
432     }
433 
434     
435     private void register0( Interceptor interceptor, Entry nextEntry ) throws Exception
436     {
437         String name = interceptor.getName();
438 
439         interceptor.init( directoryService );
440         Entry newEntry;
441         if ( nextEntry == head )
442         {
443             newEntry = new Entry( interceptor.getName(), null, head, interceptor );
444             head.prevEntry = newEntry;
445             head = newEntry;
446         }
447         else if ( head == tail )
448         {
449             newEntry = new Entry( interceptor.getName(), null, tail, interceptor );
450             tail.prevEntry = newEntry;
451             head = newEntry;
452         }
453         else
454         {
455             newEntry = new Entry( interceptor.getName(), nextEntry.prevEntry, nextEntry, interceptor );
456             nextEntry.prevEntry.nextEntry = newEntry;
457             nextEntry.prevEntry = newEntry;
458         }
459 
460         name2entry.put( name, newEntry );
461     }
462 
463 
464     /**
465      * Throws an exception when the specified interceptor name is not registered in this chain.
466      *
467      * @param name name of interceptor to look for
468      * @return An interceptor entry with the specified name.
469      * @throws javax.naming.ConfigurationException if no interceptor has that name
470      */
471     private Entry checkOldName( String name ) throws ConfigurationException
472     {
473         Entry e = name2entry.get( name );
474 
475         if ( e == null )
476         {
477             throw new ConfigurationException( "Unknown interceptor name:" + name );
478         }
479 
480         return e;
481     }
482 
483 
484     /**
485      * Checks the specified interceptor name is already taken and throws an exception if already taken.
486      * @param interceptor interceptor to check
487      * @throws javax.naming.ConfigurationException if interceptor name is already registered
488      */
489     private void checkAddable( Interceptor interceptor ) throws ConfigurationException
490     {
491         if ( name2entry.containsKey( interceptor.getName() ) )
492         {
493             throw new ConfigurationException( "Other interceptor is using name '" + interceptor.getName() + "'" );
494         }
495     }
496 
497 
498     /**
499      * Gets the InterceptorEntry to use first with bypass information considered.
500      *
501      * @return the first entry to use.
502      */
503     private Entry getStartingEntry()
504     {
505         if ( InvocationStack.getInstance().isEmpty() )
506         {
507             return head;
508         }
509 
510         OperationContext opContext = InvocationStack.getInstance().peek();
511         if ( !opContext.hasBypass() )
512         {
513             return head;
514         }
515 
516         if ( opContext.isBypassed( ByPassConstants.BYPASS_ALL ) )
517         {
518             return tail;
519         }
520 
521         Entry next = head;
522         while ( next != tail )
523         {
524             if ( opContext.isBypassed( next.getName() ) )
525             {
526                 next = next.nextEntry;
527             }
528             else
529             {
530                 return next;
531             }
532         }
533 
534         return tail;
535     }
536 
537 
538     public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext ) throws Exception
539     {
540         Entry entry = getStartingEntry();
541         Interceptor head = entry.interceptor;
542         NextInterceptor next = entry.nextInterceptor;
543 
544         try
545         {
546             return head.getRootDSE( next, opContext );
547         }
548         catch ( Exception ne )
549         {
550             throw ne;
551         }
552         catch ( Throwable e )
553         {
554             throwInterceptorException( head, e );
555             throw new InternalError(); // Should be unreachable
556         }
557     }
558 
559 
560     public LdapDN getMatchedName( GetMatchedNameOperationContext opContext ) throws Exception
561     {
562         Entry entry = getStartingEntry();
563         Interceptor head = entry.interceptor;
564         NextInterceptor next = entry.nextInterceptor;
565 
566         try
567         {
568             return head.getMatchedName( next, opContext );
569         }
570         catch ( Exception ne )
571         {
572             throw ne;
573         }
574         catch ( Throwable e )
575         {
576             throwInterceptorException( head, e );
577             throw new InternalError(); // Should be unreachable
578         }
579     }
580 
581 
582     public LdapDN getSuffix( GetSuffixOperationContext opContext ) throws Exception
583     {
584         Entry entry = getStartingEntry();
585         Interceptor head = entry.interceptor;
586         NextInterceptor next = entry.nextInterceptor;
587 
588         try
589         {
590             return head.getSuffix( next, opContext );
591         }
592         catch ( Exception ne )
593         {
594             throw ne;
595         }
596         catch ( Throwable e )
597         {
598             throwInterceptorException( head, e );
599             throw new InternalError(); // Should be unreachable
600         }
601     }
602 
603 
604     public boolean compare( CompareOperationContext opContext ) throws Exception
605     {
606         Entry entry = getStartingEntry();
607         Interceptor head = entry.interceptor;
608         NextInterceptor next = entry.nextInterceptor;
609 
610         try
611         {
612             return head.compare( next, opContext );
613         }
614         catch ( Exception ne )
615         {
616             throw ne;
617         }
618         catch ( Throwable e )
619         {
620             throwInterceptorException( head, e );
621             throw new InternalError(); // Should be unreachable
622         }
623     }
624 
625 
626     public Iterator<String> listSuffixes( ListSuffixOperationContext opContext ) throws Exception
627     {
628         Entry entry = getStartingEntry();
629         Interceptor head = entry.interceptor;
630         NextInterceptor next = entry.nextInterceptor;
631 
632         try
633         {
634             return head.listSuffixes( next, opContext );
635         }
636         catch ( Exception ne )
637         {
638             throw ne;
639         }
640         catch ( Throwable e )
641         {
642             throwInterceptorException( head, e );
643             throw new InternalError(); // Should be unreachable
644         }
645     }
646 
647 
648     public void addContextPartition( AddContextPartitionOperationContext opContext ) throws Exception
649     {
650         Entry entry = getStartingEntry();
651         Interceptor head = entry.interceptor;
652         NextInterceptor next = entry.nextInterceptor;
653 
654         try
655         {
656             head.addContextPartition( next, opContext );
657         }
658         catch ( Exception ne )
659         {
660             throw ne;
661         }
662         catch ( Throwable e )
663         {
664             throwInterceptorException( head, e );
665             throw new InternalError(); // Should be unreachable
666         }
667     }
668 
669 
670     public void removeContextPartition( RemoveContextPartitionOperationContext opContext ) throws Exception
671     {
672         Entry entry = getStartingEntry();
673         Interceptor head = entry.interceptor;
674         NextInterceptor next = entry.nextInterceptor;
675 
676         try
677         {
678             head.removeContextPartition( next, opContext );
679         }
680         catch ( Exception ne )
681         {
682             throw ne;
683         }
684         catch ( Throwable e )
685         {
686             throwInterceptorException( head, e );
687             throw new InternalError(); // Should be unreachable
688         }
689     }
690 
691     
692     /**
693      * Eagerly populates fields of operation contexts so multiple Interceptors 
694      * in the processing pathway can reuse this value without performing a 
695      * redundant lookup operation.
696      *
697      * @param opContext the operation context to populate with cached fields
698      */
699     private void eagerlyPopulateFields( OperationContext opContext )
700     {
701         // If the entry field is not set for ops other than add for example 
702         // then we set the entry but don't freak if we fail to do so since it
703         // may not exist in the first place
704         
705         if ( opContext.getEntry() == null )
706         {
707             try
708             {
709                 opContext.setEntry( opContext.getSession().lookup( opContext.getDn() ) );
710             }
711             catch ( Exception e )
712             {
713                 // might not exist
714             }
715         }
716     }
717     
718 
719     public void delete( DeleteOperationContext opContext ) throws Exception
720     {
721         Entry entry = getStartingEntry();
722         Interceptor head = entry.interceptor;
723         NextInterceptor next = entry.nextInterceptor;
724         eagerlyPopulateFields( opContext );
725         
726         try
727         {
728             head.delete( next, opContext );
729         }
730         catch ( Exception ne )
731         {
732             throw ne;
733         }
734         catch ( Throwable e )
735         {
736             throwInterceptorException( head, e );
737         }
738     }
739 
740 
741     public void add( AddOperationContext opContext ) throws Exception
742     {
743         Entry node = getStartingEntry();
744         Interceptor head = node.interceptor;
745         NextInterceptor next = node.nextInterceptor;
746 
747         try
748         {
749             head.add( next, opContext );
750         }
751         catch ( Exception ne )
752         {
753             throw ne;
754         }
755         catch ( Throwable e )
756         {
757             throwInterceptorException( head, e );
758         }
759     }
760 
761 
762     public void bind( BindOperationContext opContext ) throws Exception
763     {
764         Entry node = getStartingEntry();
765         Interceptor head = node.interceptor;
766         NextInterceptor next = node.nextInterceptor;
767         eagerlyPopulateFields( opContext );
768 
769         try
770         {
771             head.bind( next, opContext );
772         }
773         catch ( Exception ne )
774         {
775             throw ne;
776         }
777         catch ( Throwable e )
778         {
779             throwInterceptorException( head, e );
780         }
781     }
782 
783 
784     public void unbind( UnbindOperationContext opContext ) throws Exception
785     {
786         Entry node = getStartingEntry();
787         Interceptor head = node.interceptor;
788         NextInterceptor next = node.nextInterceptor;
789 
790         try
791         {
792             head.unbind( next, opContext );
793         }
794         catch ( Exception ne )
795         {
796             throw ne;
797         }
798         catch ( Throwable e )
799         {
800             throwInterceptorException( head, e );
801         }
802     }
803 
804 
805     public void modify( ModifyOperationContext opContext ) throws Exception
806     {
807         Entry entry = getStartingEntry();
808         Interceptor head = entry.interceptor;
809         NextInterceptor next = entry.nextInterceptor;
810         eagerlyPopulateFields( opContext );
811 
812         try
813         {
814             head.modify( next, opContext );
815         }
816         catch ( Exception ne )
817         {
818             throw ne;
819         }
820         catch ( Throwable e )
821         {
822             throwInterceptorException( head, e );
823         }
824     }
825 
826 
827     public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
828     {
829         Entry entry = getStartingEntry();
830         Interceptor head = entry.interceptor;
831         NextInterceptor next = entry.nextInterceptor;
832         eagerlyPopulateFields( opContext );
833 
834         try
835         {
836             return head.list( next, opContext );
837         }
838         catch ( Exception ne )
839         {
840             throw ne;
841         }
842         catch ( Throwable e )
843         {
844             throwInterceptorException( head, e );
845             throw new InternalError(); // Should be unreachable
846         }
847     }
848 
849 
850     public EntryFilteringCursor search( SearchOperationContext opContext )
851         throws Exception
852     {
853         Entry entry = getStartingEntry();
854         Interceptor head = entry.interceptor;
855         NextInterceptor next = entry.nextInterceptor;
856         eagerlyPopulateFields( opContext );
857 
858         try
859         {
860             return head.search( next, opContext );
861         }
862         catch ( Exception ne )
863         {
864             throw ne;
865         }
866         catch ( Throwable e )
867         {
868             throwInterceptorException( head, e );
869             throw new InternalError(); // Should be unreachable
870         }
871     }
872 
873 
874     public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
875     {
876         Entry entry = getStartingEntry();
877         Interceptor head = entry.interceptor;
878         NextInterceptor next = entry.nextInterceptor;
879 
880         try
881         {
882             return head.lookup( next, opContext );
883         }
884         catch ( Exception ne )
885         {
886             throw ne;
887         }
888         catch ( Throwable e )
889         {
890             throwInterceptorException( head, e );
891             throw new InternalError(); // Should be unreachable
892         }
893     }
894 
895 
896     public boolean hasEntry( EntryOperationContext opContext ) throws Exception
897     {
898         Entry entry = getStartingEntry();
899         Interceptor head = entry.interceptor;
900         NextInterceptor next = entry.nextInterceptor;
901 
902         try
903         {
904             return head.hasEntry( next, opContext );
905         }
906         catch ( Exception ne )
907         {
908             throw ne;
909         }
910         catch ( Throwable e )
911         {
912             throwInterceptorException( head, e );
913             throw new InternalError(); // Should be unreachable
914         }
915     }
916 
917 
918     public void rename( RenameOperationContext opContext ) throws Exception
919     {
920         Entry entry = getStartingEntry();
921         Interceptor head = entry.interceptor;
922         NextInterceptor next = entry.nextInterceptor;
923         eagerlyPopulateFields( opContext );
924 
925         try
926         {
927             head.rename( next, opContext );
928         }
929         catch ( Exception ne )
930         {
931             throw ne;
932         }
933         catch ( Throwable e )
934         {
935             throwInterceptorException( head, e );
936         }
937     }
938 
939 
940     public void move( MoveOperationContext opContext ) throws Exception
941     {
942         Entry entry = getStartingEntry();
943         Interceptor head = entry.interceptor;
944         NextInterceptor next = entry.nextInterceptor;
945         eagerlyPopulateFields( opContext );
946 
947         try
948         {
949             head.move( next, opContext );
950         }
951         catch ( Exception ne )
952         {
953             throw ne;
954         }
955         catch ( Throwable e )
956         {
957             throwInterceptorException( head, e );
958         }
959     }
960 
961 
962     public void moveAndRename( MoveAndRenameOperationContext opContext ) throws Exception
963     {
964         Entry entry = getStartingEntry();
965         Interceptor head = entry.interceptor;
966         NextInterceptor next = entry.nextInterceptor;
967         eagerlyPopulateFields( opContext );
968 
969         try
970         {
971             head.moveAndRename( next, opContext );
972         }
973         catch ( Exception ne )
974         {
975             throw ne;
976         }
977         catch ( Throwable e )
978         {
979             throwInterceptorException( head, e );
980         }
981     }
982 
983     /**
984      * Represents an internal entry of this chain.
985      */
986     private class Entry
987     {
988         private volatile Entry prevEntry;
989 
990         private volatile Entry nextEntry;
991 
992         private final String name;
993 
994         private final Interceptor interceptor;
995 
996         private final NextInterceptor nextInterceptor;
997 
998 
999         private String getName()
1000         {
1001             return name;
1002         }
1003 
1004 
1005         private Entry( String name, Entry prevEntry, Entry nextEntry, Interceptor interceptor )
1006         {
1007             this.name = name;
1008 
1009             if ( interceptor == null )
1010             {
1011                 throw new NullPointerException( "interceptor" );
1012             }
1013 
1014             this.prevEntry = prevEntry;
1015             this.nextEntry = nextEntry;
1016             this.interceptor = interceptor;
1017             this.nextInterceptor = new NextInterceptor()
1018             {
1019                 private Entry getNextEntry()
1020                 {
1021                     if ( InvocationStack.getInstance().isEmpty() )
1022                     {
1023                         return Entry.this.nextEntry;
1024                     }
1025 
1026                     OperationContext opContext = InvocationStack.getInstance().peek();
1027                     if ( !opContext.hasBypass() )
1028                     {
1029                         return Entry.this.nextEntry;
1030                     }
1031 
1032                     //  I don't think we really need this since this check is performed by the chain when
1033                     //  getting the interceptor head to use.
1034                     //
1035                     //                    if ( invocation.isBypassed( DirectoryPartitionNexusProxy.BYPASS_ALL ) )
1036                     //                    {
1037                     //                        return tail;
1038                     //                    }
1039 
1040                     Entry next = Entry.this.nextEntry;
1041                     while ( next != tail )
1042                     {
1043                         if ( opContext.isBypassed( next.getName() ) )
1044                         {
1045                             next = next.nextEntry;
1046                         }
1047                         else
1048                         {
1049                             return next;
1050                         }
1051                     }
1052 
1053                     return next;
1054                 }
1055 
1056 
1057                 public boolean compare( CompareOperationContext opContext ) throws Exception
1058                 {
1059                     Entry next = getNextEntry();
1060                     Interceptor interceptor = next.interceptor;
1061 
1062                     try
1063                     {
1064                         return interceptor.compare( next.nextInterceptor, opContext );
1065                     }
1066                     catch ( Exception ne )
1067                     {
1068                         throw ne;
1069                     }
1070                     catch ( Throwable e )
1071                     {
1072                         throwInterceptorException( interceptor, e );
1073                         throw new InternalError(); // Should be unreachable
1074                     }
1075                 }
1076 
1077 
1078                 public ClonedServerEntry getRootDSE( GetRootDSEOperationContext opContext ) throws Exception
1079                 {
1080                     Entry next = getNextEntry();
1081                     Interceptor interceptor = next.interceptor;
1082 
1083                     try
1084                     {
1085                         return interceptor.getRootDSE( next.nextInterceptor, opContext );
1086                     }
1087                     catch ( Exception ne )
1088                     {
1089                         throw ne;
1090                     }
1091                     catch ( Throwable e )
1092                     {
1093                         throwInterceptorException( interceptor, e );
1094                         throw new InternalError(); // Should be unreachable
1095                     }
1096                 }
1097 
1098 
1099                 public LdapDN getMatchedName( GetMatchedNameOperationContext opContext ) throws Exception
1100                 {
1101                     Entry next = getNextEntry();
1102                     Interceptor interceptor = next.interceptor;
1103 
1104                     try
1105                     {
1106                         return interceptor.getMatchedName( next.nextInterceptor, opContext );
1107                     }
1108                     catch ( Exception ne )
1109                     {
1110                         throw ne;
1111                     }
1112                     catch ( Throwable e )
1113                     {
1114                         throwInterceptorException( interceptor, e );
1115                         throw new InternalError(); // Should be unreachable
1116                     }
1117                 }
1118 
1119 
1120                 public LdapDN getSuffix( GetSuffixOperationContext opContext ) throws Exception
1121                 {
1122                     Entry next = getNextEntry();
1123                     Interceptor interceptor = next.interceptor;
1124 
1125                     try
1126                     {
1127                         return interceptor.getSuffix( next.nextInterceptor, opContext );
1128                     }
1129                     catch ( Exception ne )
1130                     {
1131                         throw ne;
1132                     }
1133                     catch ( Throwable e )
1134                     {
1135                         throwInterceptorException( interceptor, e );
1136                         throw new InternalError(); // Should be unreachable
1137                     }
1138                 }
1139 
1140 
1141                 public Iterator<String> listSuffixes( ListSuffixOperationContext opContext ) throws Exception
1142                 {
1143                     Entry next = getNextEntry();
1144                     Interceptor interceptor = next.interceptor;
1145 
1146                     try
1147                     {
1148                         return interceptor.listSuffixes( next.nextInterceptor, opContext );
1149                     }
1150                     catch ( Exception ne )
1151                     {
1152                         throw ne;
1153                     }
1154                     catch ( Throwable e )
1155                     {
1156                         throwInterceptorException( interceptor, e );
1157                         throw new InternalError(); // Should be unreachable
1158                     }
1159                 }
1160 
1161 
1162                 public void delete( DeleteOperationContext opContext ) throws Exception
1163                 {
1164                     Entry next = getNextEntry();
1165                     Interceptor interceptor = next.interceptor;
1166 
1167                     try
1168                     {
1169                         interceptor.delete( next.nextInterceptor, opContext );
1170                     }
1171                     catch ( Exception ne )
1172                     {
1173                         throw ne;
1174                     }
1175                     catch ( Throwable e )
1176                     {
1177                         throwInterceptorException( interceptor, e );
1178                     }
1179                 }
1180 
1181 
1182                 public void add( AddOperationContext opContext ) throws Exception
1183                 {
1184                     Entry next = getNextEntry();
1185                     Interceptor interceptor = next.interceptor;
1186 
1187                     try
1188                     {
1189                         interceptor.add( next.nextInterceptor, opContext );
1190                     }
1191                     catch ( Exception ne )
1192                     {
1193                         throw ne;
1194                     }
1195                     catch ( Throwable e )
1196                     {
1197                         throwInterceptorException( interceptor, e );
1198                     }
1199                 }
1200 
1201 
1202                 public void modify( ModifyOperationContext opContext ) throws Exception
1203                 {
1204                     Entry next = getNextEntry();
1205                     Interceptor interceptor = next.interceptor;
1206 
1207                     try
1208                     {
1209                         interceptor.modify( next.nextInterceptor, opContext );
1210                     }
1211                     catch ( Exception ne )
1212                     {
1213                         throw ne;
1214                     }
1215                     catch ( Throwable e )
1216                     {
1217                         throwInterceptorException( interceptor, e );
1218                     }
1219                 }
1220 
1221                 
1222                 public EntryFilteringCursor list( ListOperationContext opContext ) throws Exception
1223                 {
1224                     Entry next = getNextEntry();
1225                     Interceptor interceptor = next.interceptor;
1226 
1227                     try
1228                     {
1229                         return interceptor.list( next.nextInterceptor, opContext );
1230                     }
1231                     catch ( Exception ne )
1232                     {
1233                         throw ne;
1234                     }
1235                     catch ( Throwable e )
1236                     {
1237                         throwInterceptorException( interceptor, e );
1238                         throw new InternalError(); // Should be unreachable
1239                     }
1240                 }
1241 
1242 
1243                 public EntryFilteringCursor search( SearchOperationContext opContext )
1244                     throws Exception
1245                 {
1246                     Entry next = getNextEntry();
1247                     Interceptor interceptor = next.interceptor;
1248 
1249                     try
1250                     {
1251                         return interceptor.search( next.nextInterceptor, opContext );
1252                     }
1253                     catch ( Exception ne )
1254                     {
1255                         throw ne;
1256                     }
1257                     catch ( Throwable e )
1258                     {
1259                         throwInterceptorException( interceptor, e );
1260                         throw new InternalError(); // Should be unreachable
1261                     }
1262                 }
1263 
1264 
1265                 public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
1266                 {
1267                     Entry next = getNextEntry();
1268                     Interceptor interceptor = next.interceptor;
1269 
1270                     try
1271                     {
1272                         return interceptor.lookup( next.nextInterceptor, opContext );
1273                     }
1274                     catch ( Exception ne )
1275                     {
1276                         throw ne;
1277                     }
1278                     catch ( Throwable e )
1279                     {
1280                         throwInterceptorException( interceptor, e );
1281                         throw new InternalError(); // Should be unreachable
1282                     }
1283                 }
1284 
1285 
1286                 public boolean hasEntry( EntryOperationContext opContext ) throws Exception
1287                 {
1288                     Entry next = getNextEntry();
1289                     Interceptor interceptor = next.interceptor;
1290 
1291                     try
1292                     {
1293                         return interceptor.hasEntry( next.nextInterceptor, opContext );
1294                     }
1295                     catch ( Exception ne )
1296                     {
1297                         throw ne;
1298                     }
1299                     catch ( Throwable e )
1300                     {
1301                         throwInterceptorException( interceptor, e );
1302                         throw new InternalError(); // Should be unreachable
1303                     }
1304                 }
1305 
1306 
1307                 public void rename( RenameOperationContext opContext ) throws Exception
1308                 {
1309                     Entry next = getNextEntry();
1310                     Interceptor interceptor = next.interceptor;
1311 
1312                     try
1313                     {
1314                         interceptor.rename( next.nextInterceptor, opContext );
1315                     }
1316                     catch ( Exception ne )
1317                     {
1318                         throw ne;
1319                     }
1320                     catch ( Throwable e )
1321                     {
1322                         throwInterceptorException( interceptor, e );
1323                     }
1324                 }
1325 
1326 
1327                 public void move( MoveOperationContext opContext ) throws Exception
1328                 {
1329                     Entry next = getNextEntry();
1330                     Interceptor interceptor = next.interceptor;
1331 
1332                     try
1333                     {
1334                         interceptor.move( next.nextInterceptor, opContext );
1335                     }
1336                     catch ( Exception ne )
1337                     {
1338                         throw ne;
1339                     }
1340                     catch ( Throwable e )
1341                     {
1342                         throwInterceptorException( interceptor, e );
1343                     }
1344                 }
1345 
1346 
1347                 public void moveAndRename( MoveAndRenameOperationContext opContext )
1348                     throws Exception
1349                 {
1350                     Entry next = getNextEntry();
1351                     Interceptor interceptor = next.interceptor;
1352 
1353                     try
1354                     {
1355                         interceptor.moveAndRename( next.nextInterceptor, opContext );
1356                     }
1357                     catch ( Exception ne )
1358                     {
1359                         throw ne;
1360                     }
1361                     catch ( Throwable e )
1362                     {
1363                         throwInterceptorException( interceptor, e );
1364                     }
1365                 }
1366 
1367 
1368                 public void bind( BindOperationContext opContext ) throws Exception
1369                 {
1370                     Entry next = getNextEntry();
1371                     Interceptor interceptor = next.interceptor;
1372     
1373                     try
1374                     {
1375                         interceptor.bind( next.nextInterceptor, opContext );
1376                     }
1377                     catch ( Exception ne )
1378                     {
1379                         throw ne;
1380                     }
1381                     catch ( Throwable e )
1382                     {
1383                         throwInterceptorException( interceptor, e );
1384                     }
1385                 }
1386 
1387 
1388                 public void unbind( UnbindOperationContext opContext ) throws Exception
1389                 {
1390                     Entry next = getNextEntry();
1391                     Interceptor interceptor = next.interceptor;
1392 
1393                     try
1394                     {
1395                         interceptor.unbind( next.nextInterceptor, opContext );
1396                     }
1397                     catch ( Exception ne )
1398                     {
1399                         throw ne;
1400                     }
1401                     catch ( Throwable e )
1402                     {
1403                         throwInterceptorException( interceptor, e );
1404                     }
1405                 }
1406 
1407 
1408                 public void addContextPartition( AddContextPartitionOperationContext opContext ) throws Exception
1409                 {
1410                     Entry next = getNextEntry();
1411                     Interceptor interceptor = next.interceptor;
1412 
1413                     try
1414                     {
1415                         interceptor.addContextPartition( next.nextInterceptor, opContext );
1416                     }
1417                     catch ( Exception ne )
1418                     {
1419                         throw ne;
1420                     }
1421                     catch ( Throwable e )
1422                     {
1423                         throwInterceptorException( interceptor, e );
1424                         throw new InternalError(); // Should be unreachable
1425                     }
1426                 }
1427 
1428 
1429                 public void removeContextPartition( RemoveContextPartitionOperationContext opContext ) throws Exception
1430                 {
1431                     Entry next = getNextEntry();
1432                     Interceptor interceptor = next.interceptor;
1433 
1434                     try
1435                     {
1436                         interceptor.removeContextPartition( next.nextInterceptor, opContext );
1437                     }
1438                     catch ( Exception ne )
1439                     {
1440                         throw ne;
1441                     }
1442                     catch ( Throwable e )
1443                     {
1444                         throwInterceptorException( interceptor, e );
1445                         throw new InternalError(); // Should be unreachable
1446                     }
1447                 }
1448             };
1449         }
1450     }
1451 
1452 
1453     private static void throwInterceptorException( Interceptor interceptor, Throwable e ) throws InterceptorException
1454     {
1455         throw new InterceptorException( interceptor, "Unexpected exception.", e );
1456     }
1457 }