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 00:25:11 +0100 (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 }