View Javadoc

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