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