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 */ 020package org.apache.directory.server.core; 021 022 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.List; 026import java.util.concurrent.locks.ReadWriteLock; 027import java.util.concurrent.locks.ReentrantReadWriteLock; 028 029import org.apache.directory.api.ldap.model.constants.Loggers; 030import org.apache.directory.api.ldap.model.constants.SchemaConstants; 031import org.apache.directory.api.ldap.model.entry.Attribute; 032import org.apache.directory.api.ldap.model.entry.Entry; 033import org.apache.directory.api.ldap.model.entry.Value; 034import org.apache.directory.api.ldap.model.exception.LdapAffectMultipleDsaException; 035import org.apache.directory.api.ldap.model.exception.LdapException; 036import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException; 037import org.apache.directory.api.ldap.model.exception.LdapOperationErrorException; 038import org.apache.directory.api.ldap.model.exception.LdapOtherException; 039import org.apache.directory.api.ldap.model.exception.LdapPartialResultException; 040import org.apache.directory.api.ldap.model.exception.LdapReferralException; 041import org.apache.directory.api.ldap.model.exception.LdapServiceUnavailableException; 042import org.apache.directory.api.ldap.model.exception.LdapURLEncodingException; 043import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 044import org.apache.directory.api.ldap.model.message.SearchScope; 045import org.apache.directory.api.ldap.model.name.Dn; 046import org.apache.directory.api.ldap.model.name.Rdn; 047import org.apache.directory.api.ldap.model.url.LdapUrl; 048import org.apache.directory.server.core.api.CoreSession; 049import org.apache.directory.server.core.api.DirectoryService; 050import org.apache.directory.server.core.api.OperationManager; 051import org.apache.directory.server.core.api.ReferralManager; 052import org.apache.directory.server.core.api.filtering.EntryFilteringCursor; 053import org.apache.directory.server.core.api.interceptor.Interceptor; 054import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; 055import org.apache.directory.server.core.api.interceptor.context.BindOperationContext; 056import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext; 057import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext; 058import org.apache.directory.server.core.api.interceptor.context.GetRootDseOperationContext; 059import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext; 060import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; 061import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; 062import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext; 063import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext; 064import org.apache.directory.server.core.api.interceptor.context.OperationContext; 065import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext; 066import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext; 067import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext; 068import org.apache.directory.server.core.api.partition.Partition; 069import org.apache.directory.server.core.api.partition.PartitionTxn; 070import org.apache.directory.server.i18n.I18n; 071import org.slf4j.Logger; 072import org.slf4j.LoggerFactory; 073 074 075/** 076 * The default implementation of an OperationManager. 077 * 078 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 079 */ 080public class DefaultOperationManager implements OperationManager 081{ 082 /** A logger specifically for operations */ 083 private static final Logger OPERATION_LOG = LoggerFactory.getLogger( Loggers.OPERATION_LOG.getName() ); 084 085 /** A logger specifically for operations time */ 086 private static final Logger OPERATION_TIME = LoggerFactory.getLogger( Loggers.OPERATION_TIME.getName() ); 087 088 /** A logger specifically for operations statistics */ 089 private static final Logger OPERATION_STAT = LoggerFactory.getLogger( Loggers.OPERATION_STAT.getName() ); 090 091 /** Speedup for logs */ 092 private static final boolean IS_DEBUG = OPERATION_LOG.isDebugEnabled(); 093 private static final boolean IS_TIME = OPERATION_TIME.isDebugEnabled(); 094 private static final boolean IS_STAT = OPERATION_STAT.isDebugEnabled(); 095 096 /** The directory service instance */ 097 private final DirectoryService directoryService; 098 099 /** A lock used to protect against concurrent operations */ 100 private ReadWriteLock rwLock = new ReentrantReadWriteLock( true ); 101 102 public DefaultOperationManager( DirectoryService directoryService ) 103 { 104 this.directoryService = directoryService; 105 } 106 107 108 /** 109 * {@inheritDoc} 110 */ 111 public ReadWriteLock getRWLock() 112 { 113 return rwLock; 114 } 115 116 117 /** 118 * Acquires a ReadLock 119 */ 120 public void lockRead() 121 { 122 rwLock.readLock().lock(); 123 } 124 125 126 /** 127 * Acquires a WriteLock 128 */ 129 public void lockWrite() 130 { 131 rwLock.writeLock().lock(); 132 } 133 134 135 /** 136 * Releases a WriteLock 137 */ 138 public void unlockWrite() 139 { 140 rwLock.writeLock().unlock(); 141 } 142 143 144 /** 145 * Releases a ReadLock 146 */ 147 public void unlockRead() 148 { 149 rwLock.readLock().unlock(); 150 } 151 152 153 /** 154 * Eagerly populates fields of operation contexts so multiple Interceptors 155 * in the processing pathway can reuse this value without performing a 156 * redundant lookup operation. 157 * 158 * @param opContext the operation context to populate with cached fields 159 */ 160 private void eagerlyPopulateFields( OperationContext opContext ) throws LdapException 161 { 162 // If the entry field is not set for ops other than add for example 163 // then we set the entry but don't freak if we fail to do so since it 164 // may not exist in the first place 165 166 if ( opContext.getEntry() == null ) 167 { 168 // We have to use the admin session here, otherwise we may have 169 // trouble reading the entry due to insufficient access rights 170 CoreSession adminSession = opContext.getSession().getDirectoryService().getAdminSession(); 171 172 LookupOperationContext lookupContext = new LookupOperationContext( adminSession, opContext.getDn(), 173 SchemaConstants.ALL_ATTRIBUTES_ARRAY ); 174 lookupContext.setPartition( opContext.getPartition() ); 175 lookupContext.setTransaction( opContext.getTransaction() ); 176 Entry foundEntry = opContext.getSession().getDirectoryService().getPartitionNexus().lookup( lookupContext ); 177 178 if ( foundEntry != null ) 179 { 180 opContext.setEntry( foundEntry ); 181 } 182 else 183 { 184 // This is an error : we *must* have an entry if we want to be able to rename. 185 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_256_NO_SUCH_OBJECT, opContext.getDn() ) ); 186 } 187 } 188 } 189 190 191 private Entry getOriginalEntry( OperationContext opContext ) throws LdapException 192 { 193 // We have to use the admin session here, otherwise we may have 194 // trouble reading the entry due to insufficient access rights 195 CoreSession adminSession = opContext.getSession().getDirectoryService().getAdminSession(); 196 197 Entry foundEntry = adminSession.lookup( opContext.getDn(), SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES, 198 SchemaConstants.ALL_USER_ATTRIBUTES ); 199 200 if ( foundEntry != null ) 201 { 202 return foundEntry; 203 } 204 else 205 { 206 // This is an error : we *must* have an entry if we want to be able to rename. 207 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_256_NO_SUCH_OBJECT, 208 opContext.getDn() ) ); 209 } 210 } 211 212 213 private LdapReferralException buildReferralException( Entry parentEntry, Dn childDn ) throws LdapException 214 { 215 // Get the Ref attributeType 216 Attribute refs = parentEntry.get( SchemaConstants.REF_AT ); 217 218 List<String> urls = new ArrayList<>(); 219 220 try 221 { 222 // manage each Referral, building the correct URL for each of them 223 for ( Value url : refs ) 224 { 225 // we have to replace the parent by the referral 226 LdapUrl ldapUrl = new LdapUrl( url.getString() ); 227 228 // We have a problem with the Dn : we can't use the UpName, 229 // as we may have some spaces around the ',' and '+'. 230 // So we have to take the Rdn one by one, and create a 231 // new Dn with the type and value UP form 232 233 Dn urlDn = ldapUrl.getDn().add( childDn ); 234 235 ldapUrl.setDn( urlDn ); 236 urls.add( ldapUrl.toString() ); 237 } 238 } 239 catch ( LdapURLEncodingException luee ) 240 { 241 throw new LdapOperationErrorException( luee.getMessage(), luee ); 242 } 243 244 // Return with an exception 245 LdapReferralException lre = new LdapReferralException( urls ); 246 lre.setRemainingDn( childDn ); 247 lre.setResolvedDn( parentEntry.getDn() ); 248 lre.setResolvedObject( parentEntry ); 249 250 return lre; 251 } 252 253 254 private LdapReferralException buildReferralExceptionForSearch( Entry parentEntry, Dn childDn, SearchScope scope ) 255 throws LdapException 256 { 257 // Get the Ref attributeType 258 Attribute refs = parentEntry.get( SchemaConstants.REF_AT ); 259 260 List<String> urls = new ArrayList<>(); 261 262 // manage each Referral, building the correct URL for each of them 263 for ( Value url : refs ) 264 { 265 // we have to replace the parent by the referral 266 try 267 { 268 LdapUrl ldapUrl = new LdapUrl( url.getString() ); 269 270 StringBuilder urlString = new StringBuilder(); 271 272 if ( ( ldapUrl.getDn() == null ) || ( ldapUrl.getDn() == Dn.ROOT_DSE ) ) 273 { 274 ldapUrl.setDn( parentEntry.getDn() ); 275 } 276 else 277 { 278 // We have a problem with the Dn : we can't use the UpName, 279 // as we may have some spaces around the ',' and '+'. 280 // So we have to take the Rdn one by one, and create a 281 // new Dn with the type and value UP form 282 283 Dn urlDn = ldapUrl.getDn().add( childDn ); 284 285 ldapUrl.setDn( urlDn ); 286 } 287 288 urlString.append( ldapUrl.toString() ).append( "??" ); 289 290 switch ( scope ) 291 { 292 case OBJECT: 293 urlString.append( "base" ); 294 break; 295 296 case SUBTREE: 297 urlString.append( "sub" ); 298 break; 299 300 case ONELEVEL: 301 urlString.append( "one" ); 302 break; 303 304 default: 305 throw new IllegalArgumentException( "Unexpected scope " + scope ); 306 } 307 308 urls.add( urlString.toString() ); 309 } 310 catch ( LdapURLEncodingException luee ) 311 { 312 // The URL is not correct, returns it as is 313 urls.add( url.getString() ); 314 } 315 } 316 317 // Return with an exception 318 LdapReferralException lre = new LdapReferralException( urls ); 319 lre.setRemainingDn( childDn ); 320 lre.setResolvedDn( parentEntry.getDn() ); 321 lre.setResolvedObject( parentEntry ); 322 323 return lre; 324 } 325 326 327 private LdapPartialResultException buildLdapPartialResultException( Dn childDn ) 328 { 329 LdapPartialResultException lpre = new LdapPartialResultException( I18n.err( I18n.ERR_315 ) ); 330 331 lpre.setRemainingDn( childDn ); 332 lpre.setResolvedDn( Dn.EMPTY_DN ); 333 334 return lpre; 335 } 336 337 338 /** 339 * {@inheritDoc} 340 */ 341 public void add( AddOperationContext addContext ) throws LdapException 342 { 343 if ( IS_DEBUG ) 344 { 345 OPERATION_LOG.debug( ">> AddOperation : {}", addContext ); 346 } 347 348 long addStart = 0L; 349 350 if ( IS_TIME ) 351 { 352 addStart = System.nanoTime(); 353 } 354 355 ensureStarted(); 356 357 // Normalize the addContext Dn 358 Dn dn = addContext.getDn(); 359 360 if ( !dn.isSchemaAware() ) 361 { 362 dn = new Dn( directoryService.getSchemaManager(), dn ); 363 addContext.setDn( dn ); 364 } 365 366 // Find the working partition 367 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 368 addContext.setPartition( partition ); 369 370 // We have to deal with the referral first 371 directoryService.getReferralManager().lockRead(); 372 373 try 374 { 375 if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 376 { 377 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 378 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 379 380 // Depending on the Context.REFERRAL property value, we will throw 381 // a different exception. 382 if ( addContext.isReferralIgnored() ) 383 { 384 throw buildLdapPartialResultException( childDn ); 385 } 386 else 387 { 388 throw buildReferralException( parentEntry, childDn ); 389 } 390 } 391 } 392 finally 393 { 394 // Unlock the referral manager 395 directoryService.getReferralManager().unlock(); 396 } 397 398 // Call the Add method 399 Interceptor head = directoryService.getInterceptor( addContext.getNextInterceptor() ); 400 401 lockWrite(); 402 403 // Start a Write transaction right away 404 PartitionTxn transaction = addContext.getSession().getTransaction( partition ); 405 406 try 407 { 408 if ( transaction == null ) 409 { 410 transaction = partition.beginWriteTransaction(); 411 412 if ( addContext.getSession().hasSessionTransaction() ) 413 { 414 addContext.getSession().addTransaction( partition, transaction ); 415 } 416 } 417 418 addContext.setTransaction( transaction ); 419 420 head.add( addContext ); 421 422 if ( !addContext.getSession().hasSessionTransaction() ) 423 { 424 transaction.commit(); 425 } 426 } 427 catch ( LdapException le ) 428 { 429 try 430 { 431 if ( transaction != null ) 432 { 433 transaction.abort(); 434 } 435 436 throw le; 437 } 438 catch ( IOException ioe ) 439 { 440 throw new LdapOtherException( ioe.getMessage(), ioe ); 441 } 442 } 443 catch ( IOException ioe ) 444 { 445 try 446 { 447 transaction.abort(); 448 449 throw new LdapOtherException( ioe.getMessage(), ioe ); 450 } 451 catch ( IOException ioe2 ) 452 { 453 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 454 } 455 } 456 finally 457 { 458 unlockWrite(); 459 } 460 461 if ( IS_DEBUG ) 462 { 463 OPERATION_LOG.debug( "<< AddOperation successful" ); 464 } 465 466 if ( IS_TIME ) 467 { 468 OPERATION_TIME.debug( "Add operation took {} ns", ( System.nanoTime() - addStart ) ); 469 } 470 } 471 472 473 /** 474 * {@inheritDoc} 475 */ 476 public void bind( BindOperationContext bindContext ) throws LdapException 477 { 478 if ( IS_DEBUG ) 479 { 480 OPERATION_LOG.debug( ">> BindOperation : {}", bindContext ); 481 } 482 483 long opStart = 0L; 484 485 if ( IS_TIME ) 486 { 487 opStart = System.nanoTime(); 488 } 489 490 ensureStarted(); 491 492 // Call the Delete method 493 Interceptor head = directoryService.getInterceptor( bindContext.getNextInterceptor() ); 494 495 // Normalize the addContext Dn 496 Dn dn = bindContext.getDn(); 497 498 if ( ( dn != null ) && !dn.isSchemaAware() ) 499 { 500 dn = new Dn( directoryService.getSchemaManager(), dn ); 501 bindContext.setDn( dn ); 502 } 503 504 lockRead(); 505 506 try 507 { 508 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 509 510 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 511 { 512 bindContext.setPartition( partition ); 513 bindContext.setTransaction( partitionTxn ); 514 515 head.bind( bindContext ); 516 } 517 catch ( IOException ioe ) 518 { 519 throw new LdapOtherException( ioe.getMessage(), ioe ); 520 } 521 } 522 finally 523 { 524 unlockRead(); 525 } 526 527 if ( IS_DEBUG ) 528 { 529 OPERATION_LOG.debug( "<< BindOperation successful" ); 530 } 531 532 if ( IS_TIME ) 533 { 534 OPERATION_TIME.debug( "Bind operation took {} ns", ( System.nanoTime() - opStart ) ); 535 } 536 } 537 538 539 /** 540 * {@inheritDoc} 541 */ 542 public boolean compare( CompareOperationContext compareContext ) throws LdapException 543 { 544 if ( IS_DEBUG ) 545 { 546 OPERATION_LOG.debug( ">> CompareOperation : {}", compareContext ); 547 } 548 549 long opStart = 0L; 550 551 if ( IS_TIME ) 552 { 553 opStart = System.nanoTime(); 554 } 555 556 ensureStarted(); 557 558 // Normalize the compareContext Dn 559 Dn dn = compareContext.getDn(); 560 561 if ( !dn.isSchemaAware() ) 562 { 563 dn = new Dn( directoryService.getSchemaManager(), dn ); 564 compareContext.setDn( dn ); 565 } 566 567 // We have to deal with the referral first 568 directoryService.getReferralManager().lockRead(); 569 570 try 571 { 572 // Check if we have an ancestor for this Dn 573 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 574 575 if ( parentEntry != null ) 576 { 577 // We have found a parent referral for the current Dn 578 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 579 580 if ( directoryService.getReferralManager().isReferral( dn ) ) 581 { 582 // This is a referral. We can delete it if the ManageDsaIt flag is true 583 // Otherwise, we just throw a LdapReferralException 584 if ( !compareContext.isReferralIgnored() ) 585 { 586 // Throw a Referral Exception 587 throw buildReferralException( parentEntry, childDn ); 588 } 589 } 590 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 591 { 592 // Depending on the Context.REFERRAL property value, we will throw 593 // a different exception. 594 if ( compareContext.isReferralIgnored() ) 595 { 596 throw buildLdapPartialResultException( childDn ); 597 } 598 else 599 { 600 throw buildReferralException( parentEntry, childDn ); 601 } 602 } 603 } 604 } 605 finally 606 { 607 // Unlock the ReferralManager 608 directoryService.getReferralManager().unlock(); 609 } 610 611 // populate the context with the old entry 612 compareContext.setOriginalEntry( getOriginalEntry( compareContext ) ); 613 614 // Call the Compare method 615 Interceptor head = directoryService.getInterceptor( compareContext.getNextInterceptor() ); 616 617 boolean result = false; 618 619 lockRead(); 620 621 try 622 { 623 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 624 625 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 626 { 627 compareContext.setPartition( partition ); 628 compareContext.setTransaction( partitionTxn ); 629 630 result = head.compare( compareContext ); 631 } 632 catch ( IOException ioe ) 633 { 634 throw new LdapOtherException( ioe.getMessage(), ioe ); 635 } 636 } 637 finally 638 { 639 unlockRead(); 640 } 641 642 if ( IS_DEBUG ) 643 { 644 OPERATION_LOG.debug( "<< CompareOperation successful" ); 645 } 646 647 if ( IS_TIME ) 648 { 649 OPERATION_TIME.debug( "Compare operation took {} ns", ( System.nanoTime() - opStart ) ); 650 } 651 652 return result; 653 } 654 655 656 /** 657 * {@inheritDoc} 658 */ 659 public void delete( DeleteOperationContext deleteContext ) throws LdapException 660 { 661 if ( IS_DEBUG ) 662 { 663 OPERATION_LOG.debug( ">> DeleteOperation : {}", deleteContext ); 664 } 665 666 long opStart = 0L; 667 668 if ( IS_TIME ) 669 { 670 opStart = System.nanoTime(); 671 } 672 673 ensureStarted(); 674 675 // Normalize the deleteContext Dn 676 Dn dn = deleteContext.getDn(); 677 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 678 deleteContext.setPartition( partition ); 679 680 if ( !dn.isSchemaAware() ) 681 { 682 dn = new Dn( directoryService.getSchemaManager(), dn ); 683 deleteContext.setDn( dn ); 684 } 685 686 // We have to deal with the referral first 687 directoryService.getReferralManager().lockRead(); 688 689 try 690 { 691 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 692 693 if ( parentEntry != null ) 694 { 695 // We have found a parent referral for the current Dn 696 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 697 698 if ( directoryService.getReferralManager().isReferral( dn ) ) 699 { 700 // This is a referral. We can delete it if the ManageDsaIt flag is true 701 // Otherwise, we just throw a LdapReferralException 702 if ( !deleteContext.isReferralIgnored() ) 703 { 704 // Throw a Referral Exception 705 throw buildReferralException( parentEntry, childDn ); 706 } 707 } 708 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 709 { 710 // We can't delete an entry which has an ancestor referral 711 712 // Depending on the Context.REFERRAL property value, we will throw 713 // a different exception. 714 if ( deleteContext.isReferralIgnored() ) 715 { 716 throw buildLdapPartialResultException( childDn ); 717 } 718 else 719 { 720 throw buildReferralException( parentEntry, childDn ); 721 } 722 } 723 } 724 } 725 finally 726 { 727 // Unlock the ReferralManager 728 directoryService.getReferralManager().unlock(); 729 } 730 731 // populate the context with the old entry 732 lockWrite(); 733 734 // Start a Write transaction right away 735 PartitionTxn transaction = deleteContext.getSession().getTransaction( partition ); 736 737 try 738 { 739 if ( transaction == null ) 740 { 741 transaction = partition.beginWriteTransaction(); 742 743 if ( deleteContext.getSession().hasSessionTransaction() ) 744 { 745 deleteContext.getSession().addTransaction( partition, transaction ); 746 } 747 } 748 749 deleteContext.setTransaction( transaction ); 750 751 eagerlyPopulateFields( deleteContext ); 752 753 // Call the Delete method 754 Interceptor head = directoryService.getInterceptor( deleteContext.getNextInterceptor() ); 755 756 head.delete( deleteContext ); 757 758 if ( !deleteContext.getSession().hasSessionTransaction() ) 759 { 760 transaction.commit(); 761 } 762 } 763 catch ( LdapException le ) 764 { 765 try 766 { 767 if ( transaction != null ) 768 { 769 transaction.abort(); 770 } 771 772 throw le; 773 } 774 catch ( IOException ioe ) 775 { 776 throw new LdapOtherException( ioe.getMessage(), ioe ); 777 } 778 } 779 catch ( IOException ioe ) 780 { 781 try 782 { 783 transaction.abort(); 784 785 throw new LdapOtherException( ioe.getMessage(), ioe ); 786 } 787 catch ( IOException ioe2 ) 788 { 789 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 790 } 791 } 792 finally 793 { 794 unlockWrite(); 795 } 796 797 if ( IS_DEBUG ) 798 { 799 OPERATION_LOG.debug( "<< DeleteOperation successful" ); 800 } 801 802 if ( IS_TIME ) 803 { 804 OPERATION_TIME.debug( "Delete operation took {} ns", ( System.nanoTime() - opStart ) ); 805 } 806 } 807 808 809 /** 810 * {@inheritDoc} 811 */ 812 public Entry getRootDse( GetRootDseOperationContext getRootDseContext ) throws LdapException 813 { 814 if ( IS_DEBUG ) 815 { 816 OPERATION_LOG.debug( ">> GetRootDseOperation : {}", getRootDseContext ); 817 } 818 819 long opStart = 0L; 820 821 if ( IS_TIME ) 822 { 823 opStart = System.nanoTime(); 824 } 825 826 ensureStarted(); 827 828 Interceptor head = directoryService.getInterceptor( getRootDseContext.getNextInterceptor() ); 829 Entry root; 830 831 try 832 { 833 lockRead(); 834 835 Partition partition = directoryService.getPartitionNexus().getPartition( Dn.ROOT_DSE ); 836 837 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 838 { 839 getRootDseContext.setPartition( partition ); 840 getRootDseContext.setTransaction( partitionTxn ); 841 842 root = head.getRootDse( getRootDseContext ); 843 } 844 catch ( IOException ioe ) 845 { 846 throw new LdapOtherException( ioe.getMessage(), ioe ); 847 } 848 } 849 finally 850 { 851 unlockRead(); 852 } 853 854 if ( IS_DEBUG ) 855 { 856 OPERATION_LOG.debug( "<< getRootDseOperation successful" ); 857 } 858 859 if ( IS_TIME ) 860 { 861 OPERATION_TIME.debug( "GetRootDSE operation took {} ns", ( System.nanoTime() - opStart ) ); 862 } 863 864 return root; 865 } 866 867 868 /** 869 * {@inheritDoc} 870 */ 871 public boolean hasEntry( HasEntryOperationContext hasEntryContext ) throws LdapException 872 { 873 if ( IS_DEBUG ) 874 { 875 OPERATION_LOG.debug( ">> hasEntryOperation : {}", hasEntryContext ); 876 } 877 878 long opStart = 0L; 879 880 if ( IS_TIME ) 881 { 882 opStart = System.nanoTime(); 883 } 884 885 ensureStarted(); 886 887 Interceptor head = directoryService.getInterceptor( hasEntryContext.getNextInterceptor() ); 888 889 boolean result = false; 890 891 lockRead(); 892 893 // Normalize the addContext Dn 894 Dn dn = hasEntryContext.getDn(); 895 896 if ( !dn.isSchemaAware() ) 897 { 898 dn = new Dn( directoryService.getSchemaManager(), dn ); 899 hasEntryContext.setDn( dn ); 900 } 901 902 try 903 { 904 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 905 906 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 907 { 908 hasEntryContext.setPartition( partition ); 909 hasEntryContext.setTransaction( partitionTxn ); 910 911 result = head.hasEntry( hasEntryContext ); 912 } 913 catch ( IOException ioe ) 914 { 915 throw new LdapOtherException( ioe.getMessage(), ioe ); 916 } 917 } 918 finally 919 { 920 unlockRead(); 921 } 922 923 if ( IS_DEBUG ) 924 { 925 OPERATION_LOG.debug( "<< HasEntryOperation successful" ); 926 } 927 928 if ( IS_TIME ) 929 { 930 OPERATION_TIME.debug( "HasEntry operation took {} ns", ( System.nanoTime() - opStart ) ); 931 } 932 933 return result; 934 } 935 936 937 /** 938 * {@inheritDoc} 939 */ 940 public Entry lookup( LookupOperationContext lookupContext ) throws LdapException 941 { 942 if ( IS_DEBUG ) 943 { 944 OPERATION_LOG.debug( ">> LookupOperation : {}", lookupContext ); 945 } 946 947 long opStart = 0L; 948 949 if ( IS_TIME ) 950 { 951 opStart = System.nanoTime(); 952 } 953 954 ensureStarted(); 955 956 Interceptor head = directoryService.getInterceptor( lookupContext.getNextInterceptor() ); 957 958 Entry entry = null; 959 960 // Normalize the modifyContext Dn 961 Dn dn = lookupContext.getDn(); 962 963 if ( !dn.isSchemaAware() ) 964 { 965 dn = new Dn( directoryService.getSchemaManager(), dn ); 966 lookupContext.setDn( dn ); 967 } 968 969 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 970 lookupContext.setPartition( partition ); 971 972 // Start a read transaction right away 973 try ( PartitionTxn transaction = partition.beginReadTransaction() ) 974 { 975 lookupContext.setTransaction( transaction ); 976 977 lockRead(); 978 979 try 980 { 981 entry = head.lookup( lookupContext ); 982 } 983 finally 984 { 985 unlockRead(); 986 } 987 } 988 catch ( IOException ioe ) 989 { 990 throw new LdapOtherException( ioe.getMessage(), ioe ); 991 } 992 993 if ( IS_DEBUG ) 994 { 995 OPERATION_LOG.debug( "<< LookupOperation successful" ); 996 } 997 998 if ( IS_TIME ) 999 { 1000 OPERATION_TIME.debug( "Lookup operation took {} ns", ( System.nanoTime() - opStart ) ); 1001 } 1002 1003 return entry; 1004 } 1005 1006 1007 /** 1008 * {@inheritDoc} 1009 */ 1010 public void modify( ModifyOperationContext modifyContext ) throws LdapException 1011 { 1012 if ( IS_DEBUG ) 1013 { 1014 OPERATION_LOG.debug( ">> ModifyOperation : {}", modifyContext ); 1015 } 1016 1017 long opStart = 0L; 1018 1019 if ( IS_TIME ) 1020 { 1021 opStart = System.nanoTime(); 1022 } 1023 1024 ensureStarted(); 1025 1026 // Normalize the modifyContext Dn 1027 Dn dn = modifyContext.getDn(); 1028 1029 if ( !dn.isSchemaAware() ) 1030 { 1031 dn = new Dn( directoryService.getSchemaManager(), dn ); 1032 modifyContext.setDn( dn ); 1033 } 1034 1035 ReferralManager referralManager = directoryService.getReferralManager(); 1036 1037 // We have to deal with the referral first 1038 referralManager.lockRead(); 1039 1040 try 1041 { 1042 // Check if we have an ancestor for this Dn 1043 Entry parentEntry = referralManager.getParentReferral( dn ); 1044 1045 if ( parentEntry != null ) 1046 { 1047 if ( referralManager.isReferral( dn ) ) 1048 { 1049 // This is a referral. We can delete it if the ManageDsaIt flag is true 1050 // Otherwise, we just throw a LdapReferralException 1051 if ( !modifyContext.isReferralIgnored() ) 1052 { 1053 // Throw a Referral Exception 1054 // We have found a parent referral for the current Dn 1055 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1056 1057 throw buildReferralException( parentEntry, childDn ); 1058 } 1059 } 1060 else if ( referralManager.hasParentReferral( dn ) ) 1061 { 1062 // We can't delete an entry which has an ancestor referral 1063 1064 // Depending on the Context.REFERRAL property value, we will throw 1065 // a different exception. 1066 if ( modifyContext.isReferralIgnored() ) 1067 { 1068 // We have found a parent referral for the current Dn 1069 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1070 1071 throw buildLdapPartialResultException( childDn ); 1072 } 1073 else 1074 { 1075 // We have found a parent referral for the current Dn 1076 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1077 1078 throw buildReferralException( parentEntry, childDn ); 1079 } 1080 } 1081 } 1082 } 1083 finally 1084 { 1085 // Unlock the ReferralManager 1086 referralManager.unlock(); 1087 } 1088 1089 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 1090 modifyContext.setPartition( partition ); 1091 1092 lockWrite(); 1093 1094 // Start a Write transaction right away 1095 PartitionTxn transaction = modifyContext.getSession().getTransaction( partition ); 1096 1097 try 1098 { 1099 if ( transaction == null ) 1100 { 1101 transaction = partition.beginWriteTransaction(); 1102 1103 if ( modifyContext.getSession().hasSessionTransaction() ) 1104 { 1105 modifyContext.getSession().addTransaction( partition, transaction ); 1106 } 1107 } 1108 1109 modifyContext.setTransaction( transaction ); 1110 1111 // populate the context with the old entry 1112 eagerlyPopulateFields( modifyContext ); 1113 1114 // Call the Modify method 1115 Interceptor head = directoryService.getInterceptor( modifyContext.getNextInterceptor() ); 1116 1117 head.modify( modifyContext ); 1118 1119 if ( !modifyContext.getSession().hasSessionTransaction() ) 1120 { 1121 transaction.commit(); 1122 } 1123 } 1124 catch ( LdapException le ) 1125 { 1126 try 1127 { 1128 if ( transaction != null ) 1129 { 1130 transaction.abort(); 1131 } 1132 1133 throw le; 1134 } 1135 catch ( IOException ioe ) 1136 { 1137 throw new LdapOtherException( ioe.getMessage(), ioe ); 1138 } 1139 } 1140 catch ( IOException ioe ) 1141 { 1142 try 1143 { 1144 transaction.abort(); 1145 1146 throw new LdapOtherException( ioe.getMessage(), ioe ); 1147 } 1148 catch ( IOException ioe2 ) 1149 { 1150 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 1151 } 1152 } 1153 finally 1154 { 1155 unlockWrite(); 1156 } 1157 1158 if ( IS_DEBUG ) 1159 { 1160 OPERATION_LOG.debug( "<< ModifyOperation successful" ); 1161 } 1162 1163 if ( IS_TIME ) 1164 { 1165 OPERATION_TIME.debug( "Modify operation took {} ns", ( System.nanoTime() - opStart ) ); 1166 } 1167 } 1168 1169 1170 /** 1171 * {@inheritDoc} 1172 */ 1173 public void move( MoveOperationContext moveContext ) throws LdapException 1174 { 1175 if ( IS_DEBUG ) 1176 { 1177 OPERATION_LOG.debug( ">> MoveOperation : {}", moveContext ); 1178 } 1179 1180 long opStart = 0L; 1181 1182 if ( IS_TIME ) 1183 { 1184 opStart = System.nanoTime(); 1185 } 1186 1187 ensureStarted(); 1188 1189 // Normalize the moveContext Dn 1190 Dn dn = moveContext.getDn(); 1191 1192 if ( !dn.isSchemaAware() ) 1193 { 1194 dn = new Dn( directoryService.getSchemaManager(), dn ); 1195 moveContext.setDn( dn ); 1196 } 1197 1198 // Normalize the moveContext superior Dn 1199 Dn newSuperiorDn = moveContext.getNewSuperior(); 1200 1201 if ( !newSuperiorDn.isSchemaAware() ) 1202 { 1203 newSuperiorDn = new Dn( directoryService.getSchemaManager(), newSuperiorDn ); 1204 moveContext.setNewSuperior( newSuperiorDn ); 1205 } 1206 1207 // We have to deal with the referral first 1208 directoryService.getReferralManager().lockRead(); 1209 1210 try 1211 { 1212 // Check if we have an ancestor for this Dn 1213 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 1214 1215 if ( parentEntry != null ) 1216 { 1217 // We have found a parent referral for the current Dn 1218 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1219 1220 if ( directoryService.getReferralManager().isReferral( dn ) ) 1221 { 1222 // This is a referral. We can delete it if the ManageDsaIt flag is true 1223 // Otherwise, we just throw a LdapReferralException 1224 if ( !moveContext.isReferralIgnored() ) 1225 { 1226 // Throw a Referral Exception 1227 throw buildReferralException( parentEntry, childDn ); 1228 } 1229 } 1230 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 1231 { 1232 // We can't delete an entry which has an ancestor referral 1233 1234 // Depending on the Context.REFERRAL property value, we will throw 1235 // a different exception. 1236 if ( moveContext.isReferralIgnored() ) 1237 { 1238 throw buildLdapPartialResultException( childDn ); 1239 } 1240 else 1241 { 1242 throw buildReferralException( parentEntry, childDn ); 1243 } 1244 } 1245 } 1246 1247 // Now, check the destination 1248 // If he parent Dn is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result 1249 // as stated by RFC 3296 Section 5.6.2 1250 if ( directoryService.getReferralManager().isReferral( newSuperiorDn ) 1251 || directoryService.getReferralManager().hasParentReferral( newSuperiorDn ) ) 1252 { 1253 throw new LdapAffectMultipleDsaException(); 1254 } 1255 1256 } 1257 finally 1258 { 1259 // Unlock the referral manager 1260 directoryService.getReferralManager().unlock(); 1261 } 1262 1263 lockWrite(); 1264 1265 // Find the working partition 1266 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 1267 moveContext.setPartition( partition ); 1268 1269 // Start a Write transaction right away 1270 PartitionTxn transaction = moveContext.getSession().getTransaction( partition ); 1271 1272 try 1273 { 1274 if ( transaction == null ) 1275 { 1276 transaction = partition.beginWriteTransaction(); 1277 1278 if ( moveContext.getSession().hasSessionTransaction() ) 1279 { 1280 moveContext.getSession().addTransaction( partition, transaction ); 1281 } 1282 } 1283 1284 moveContext.setTransaction( transaction ); 1285 Entry originalEntry = getOriginalEntry( moveContext ); 1286 1287 moveContext.setOriginalEntry( originalEntry ); 1288 1289 // Call the Move method 1290 Interceptor head = directoryService.getInterceptor( moveContext.getNextInterceptor() ); 1291 1292 head.move( moveContext ); 1293 1294 if ( !moveContext.getSession().hasSessionTransaction() ) 1295 { 1296 transaction.commit(); 1297 } 1298 } 1299 catch ( LdapException le ) 1300 { 1301 try 1302 { 1303 if ( transaction != null ) 1304 { 1305 transaction.abort(); 1306 } 1307 1308 throw le; 1309 } 1310 catch ( IOException ioe ) 1311 { 1312 throw new LdapOtherException( ioe.getMessage(), ioe ); 1313 } 1314 } 1315 catch ( IOException ioe ) 1316 { 1317 try 1318 { 1319 if ( transaction != null ) 1320 { 1321 transaction.abort(); 1322 } 1323 1324 throw new LdapOtherException( ioe.getMessage(), ioe ); 1325 } 1326 catch ( IOException ioe2 ) 1327 { 1328 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 1329 } 1330 } 1331 finally 1332 { 1333 unlockWrite(); 1334 } 1335 1336 if ( IS_DEBUG ) 1337 { 1338 OPERATION_LOG.debug( "<< MoveOperation successful" ); 1339 } 1340 1341 if ( IS_TIME ) 1342 { 1343 OPERATION_TIME.debug( "Move operation took {} ns", ( System.nanoTime() - opStart ) ); 1344 } 1345 } 1346 1347 1348 /** 1349 * {@inheritDoc} 1350 */ 1351 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException 1352 { 1353 if ( IS_DEBUG ) 1354 { 1355 OPERATION_LOG.debug( ">> MoveAndRenameOperation : {}", moveAndRenameContext ); 1356 } 1357 1358 long opStart = 0L; 1359 1360 if ( IS_TIME ) 1361 { 1362 opStart = System.nanoTime(); 1363 } 1364 1365 ensureStarted(); 1366 1367 // Normalize the moveAndRenameContext Dn 1368 Dn dn = moveAndRenameContext.getDn(); 1369 1370 if ( !dn.isSchemaAware() ) 1371 { 1372 dn = new Dn( directoryService.getSchemaManager(), dn ); 1373 moveAndRenameContext.setDn( dn ); 1374 } 1375 1376 // We have to deal with the referral first 1377 directoryService.getReferralManager().lockRead(); 1378 1379 try 1380 { 1381 // Check if we have an ancestor for this Dn 1382 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 1383 1384 if ( parentEntry != null ) 1385 { 1386 // We have found a parent referral for the current Dn 1387 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1388 1389 if ( directoryService.getReferralManager().isReferral( dn ) ) 1390 { 1391 // This is a referral. We can delete it if the ManageDsaIt flag is true 1392 // Otherwise, we just throw a LdapReferralException 1393 if ( !moveAndRenameContext.isReferralIgnored() ) 1394 { 1395 // Throw a Referral Exception 1396 throw buildReferralException( parentEntry, childDn ); 1397 } 1398 } 1399 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 1400 { 1401 // We can't delete an entry which has an ancestor referral 1402 1403 // Depending on the Context.REFERRAL property value, we will throw 1404 // a different exception. 1405 if ( moveAndRenameContext.isReferralIgnored() ) 1406 { 1407 throw buildLdapPartialResultException( childDn ); 1408 } 1409 else 1410 { 1411 throw buildReferralException( parentEntry, childDn ); 1412 } 1413 } 1414 } 1415 1416 // Now, check the destination 1417 // Normalize the moveAndRenameContext Dn 1418 Dn newSuperiorDn = moveAndRenameContext.getNewSuperiorDn(); 1419 1420 if ( !newSuperiorDn.isSchemaAware() ) 1421 { 1422 newSuperiorDn = new Dn( directoryService.getSchemaManager(), newSuperiorDn ); 1423 moveAndRenameContext.setNewSuperiorDn( newSuperiorDn ); 1424 } 1425 1426 // If he parent Dn is a referral, or has a referral ancestor, we have to issue a AffectMultipleDsas result 1427 // as stated by RFC 3296 Section 5.6.2 1428 if ( directoryService.getReferralManager().isReferral( newSuperiorDn ) 1429 || directoryService.getReferralManager().hasParentReferral( newSuperiorDn ) ) 1430 { 1431 // The parent Dn is a referral, we have to issue a AffectMultipleDsas result 1432 // as stated by RFC 3296 Section 5.6.2 1433 throw new LdapAffectMultipleDsaException(); 1434 } 1435 } 1436 finally 1437 { 1438 // Unlock the ReferralManager 1439 directoryService.getReferralManager().unlock(); 1440 } 1441 1442 // Find the working partition 1443 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 1444 moveAndRenameContext.setPartition( partition ); 1445 1446 lockWrite(); 1447 1448 // Start a Write transaction right away 1449 PartitionTxn transaction = moveAndRenameContext.getSession().getTransaction( partition ); 1450 1451 try 1452 { 1453 if ( transaction == null ) 1454 { 1455 transaction = partition.beginWriteTransaction(); 1456 1457 if ( moveAndRenameContext.getSession().hasSessionTransaction() ) 1458 { 1459 moveAndRenameContext.getSession().addTransaction( partition, transaction ); 1460 } 1461 } 1462 1463 moveAndRenameContext.setOriginalEntry( getOriginalEntry( moveAndRenameContext ) ); 1464 moveAndRenameContext.setModifiedEntry( moveAndRenameContext.getOriginalEntry().clone() ); 1465 moveAndRenameContext.setTransaction( transaction ); 1466 1467 // Call the MoveAndRename method 1468 Interceptor head = directoryService.getInterceptor( moveAndRenameContext.getNextInterceptor() ); 1469 1470 head.moveAndRename( moveAndRenameContext ); 1471 1472 if ( !moveAndRenameContext.getSession().hasSessionTransaction() ) 1473 { 1474 transaction.commit(); 1475 } 1476 } 1477 catch ( LdapException le ) 1478 { 1479 try 1480 { 1481 if ( transaction != null ) 1482 { 1483 transaction.abort(); 1484 } 1485 1486 throw le; 1487 } 1488 catch ( IOException ioe ) 1489 { 1490 throw new LdapOtherException( ioe.getMessage(), ioe ); 1491 } 1492 } 1493 catch ( IOException ioe ) 1494 { 1495 try 1496 { 1497 transaction.abort(); 1498 1499 throw new LdapOtherException( ioe.getMessage(), ioe ); 1500 } 1501 catch ( IOException ioe2 ) 1502 { 1503 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 1504 } 1505 } 1506 finally 1507 { 1508 unlockWrite(); 1509 } 1510 1511 if ( IS_DEBUG ) 1512 { 1513 OPERATION_LOG.debug( "<< MoveAndRenameOperation successful" ); 1514 } 1515 1516 if ( IS_TIME ) 1517 { 1518 OPERATION_TIME.debug( "MoveAndRename operation took {} ns", ( System.nanoTime() - opStart ) ); 1519 } 1520 } 1521 1522 1523 /** 1524 * {@inheritDoc} 1525 */ 1526 public void rename( RenameOperationContext renameContext ) throws LdapException 1527 { 1528 if ( IS_DEBUG ) 1529 { 1530 OPERATION_LOG.debug( ">> RenameOperation : {}", renameContext ); 1531 } 1532 1533 long opStart = 0L; 1534 1535 if ( IS_TIME ) 1536 { 1537 opStart = System.nanoTime(); 1538 } 1539 1540 ensureStarted(); 1541 1542 // Normalize the renameContext Dn 1543 Dn dn = renameContext.getDn(); 1544 1545 if ( !dn.isSchemaAware() ) 1546 { 1547 dn = new Dn( directoryService.getSchemaManager(), dn ); 1548 renameContext.setDn( dn ); 1549 } 1550 1551 // Inject the newDn into the operation context 1552 // Inject the new Dn into the context 1553 if ( !dn.isEmpty() ) 1554 { 1555 Dn newDn = dn.getParent(); 1556 Rdn newRdn = renameContext.getNewRdn(); 1557 1558 if ( !newRdn.isSchemaAware() ) 1559 { 1560 newRdn = new Rdn( directoryService.getSchemaManager(), newRdn ); 1561 renameContext.setNewRdn( newRdn ); 1562 } 1563 1564 newDn = newDn.add( renameContext.getNewRdn() ); 1565 renameContext.setNewDn( newDn ); 1566 } 1567 1568 // We have to deal with the referral first 1569 directoryService.getReferralManager().lockRead(); 1570 1571 try 1572 { 1573 // Check if we have an ancestor for this Dn 1574 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 1575 1576 if ( parentEntry != null ) 1577 { 1578 // We have found a parent referral for the current Dn 1579 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1580 1581 if ( directoryService.getReferralManager().isReferral( dn ) ) 1582 { 1583 // This is a referral. We can delete it if the ManageDsaIt flag is true 1584 // Otherwise, we just throw a LdapReferralException 1585 if ( !renameContext.isReferralIgnored() ) 1586 { 1587 // Throw a Referral Exception 1588 throw buildReferralException( parentEntry, childDn ); 1589 } 1590 } 1591 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 1592 { 1593 // We can't delete an entry which has an ancestor referral 1594 1595 // Depending on the Context.REFERRAL property value, we will throw 1596 // a different exception. 1597 if ( renameContext.isReferralIgnored() ) 1598 { 1599 throw buildLdapPartialResultException( childDn ); 1600 } 1601 else 1602 { 1603 throw buildReferralException( parentEntry, childDn ); 1604 } 1605 } 1606 } 1607 } 1608 finally 1609 { 1610 // Unlock the ReferralManager 1611 directoryService.getReferralManager().unlock(); 1612 } 1613 1614 lockWrite(); 1615 1616 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 1617 1618 // Start a Write transaction right away 1619 PartitionTxn transaction = renameContext.getSession().getTransaction( partition ); 1620 1621 // Call the rename method 1622 try 1623 { 1624 if ( transaction == null ) 1625 { 1626 transaction = partition.beginWriteTransaction(); 1627 1628 if ( renameContext.getSession().hasSessionTransaction() ) 1629 { 1630 renameContext.getSession().addTransaction( partition, transaction ); 1631 } 1632 } 1633 1634 renameContext.setPartition( partition ); 1635 1636 // populate the context with the old entry 1637 PartitionTxn partitionTxn = null; 1638 1639 try 1640 { 1641 partitionTxn = partition.beginReadTransaction(); 1642 1643 renameContext.setTransaction( partitionTxn ); 1644 1645 eagerlyPopulateFields( renameContext ); 1646 } 1647 finally 1648 { 1649 try 1650 { 1651 // Nothing to do 1652 if ( partitionTxn != null ) 1653 { 1654 partitionTxn.close(); 1655 } 1656 } 1657 catch ( IOException ioe ) 1658 { 1659 throw new LdapOtherException( ioe.getMessage(), ioe ); 1660 } 1661 } 1662 1663 Entry originalEntry = getOriginalEntry( renameContext ); 1664 renameContext.setOriginalEntry( originalEntry ); 1665 renameContext.setModifiedEntry( originalEntry.clone() ); 1666 Interceptor head = directoryService.getInterceptor( renameContext.getNextInterceptor() ); 1667 1668 // Start a Write transaction right away 1669 transaction = renameContext.getSession().getTransaction( partition ); 1670 1671 // Call the Rename method 1672 try 1673 { 1674 if ( transaction == null ) 1675 { 1676 transaction = partition.beginWriteTransaction(); 1677 1678 if ( renameContext.getSession().hasSessionTransaction() ) 1679 { 1680 renameContext.getSession().addTransaction( partition, transaction ); 1681 } 1682 } 1683 1684 renameContext.setTransaction( transaction ); 1685 1686 head.rename( renameContext ); 1687 1688 if ( !renameContext.getSession().hasSessionTransaction() ) 1689 { 1690 transaction.commit(); 1691 } 1692 } 1693 catch ( LdapException le ) 1694 { 1695 try 1696 { 1697 if ( transaction != null ) 1698 { 1699 transaction.abort(); 1700 } 1701 1702 throw le; 1703 } 1704 catch ( IOException ioe ) 1705 { 1706 throw new LdapOtherException( ioe.getMessage(), ioe ); 1707 } 1708 } 1709 catch ( IOException ioe ) 1710 { 1711 try 1712 { 1713 if ( transaction != null ) 1714 { 1715 transaction.abort(); 1716 } 1717 1718 throw new LdapOtherException( ioe.getMessage(), ioe ); 1719 } 1720 catch ( IOException ioe2 ) 1721 { 1722 throw new LdapOtherException( ioe2.getMessage(), ioe2 ); 1723 } 1724 } 1725 } 1726 finally 1727 { 1728 unlockWrite(); 1729 } 1730 1731 if ( IS_DEBUG ) 1732 { 1733 OPERATION_LOG.debug( "<< RenameOperation successful" ); 1734 } 1735 1736 if ( IS_TIME ) 1737 { 1738 OPERATION_TIME.debug( "Rename operation took {} ns", ( System.nanoTime() - opStart ) ); 1739 } 1740 } 1741 1742 1743 /** 1744 * {@inheritDoc} 1745 */ 1746 public EntryFilteringCursor search( SearchOperationContext searchContext ) throws LdapException 1747 { 1748 if ( IS_DEBUG ) 1749 { 1750 OPERATION_LOG.debug( ">> SearchOperation : {}", searchContext ); 1751 } 1752 1753 long opStart = 0L; 1754 1755 if ( IS_TIME ) 1756 { 1757 opStart = System.nanoTime(); 1758 } 1759 1760 ensureStarted(); 1761 1762 // Normalize the searchContext Dn 1763 Dn dn = searchContext.getDn(); 1764 1765 if ( !dn.isSchemaAware() ) 1766 { 1767 dn = new Dn( directoryService.getSchemaManager(), dn ); 1768 searchContext.setDn( dn ); 1769 } 1770 1771 // We have to deal with the referral first 1772 directoryService.getReferralManager().lockRead(); 1773 1774 try 1775 { 1776 // Check if we have an ancestor for this Dn 1777 Entry parentEntry = directoryService.getReferralManager().getParentReferral( dn ); 1778 1779 if ( parentEntry != null ) 1780 { 1781 // We have found a parent referral for the current Dn 1782 Dn childDn = dn.getDescendantOf( parentEntry.getDn() ); 1783 1784 if ( directoryService.getReferralManager().isReferral( dn ) ) 1785 { 1786 // This is a referral. We can return it if the ManageDsaIt flag is true 1787 // Otherwise, we just throw a LdapReferralException 1788 if ( !searchContext.isReferralIgnored() ) 1789 { 1790 // Throw a Referral Exception 1791 throw buildReferralExceptionForSearch( parentEntry, childDn, searchContext.getScope() ); 1792 } 1793 } 1794 else if ( directoryService.getReferralManager().hasParentReferral( dn ) ) 1795 { 1796 // We can't search an entry which has an ancestor referral 1797 1798 // Depending on the Context.REFERRAL property value, we will throw 1799 // a different exception. 1800 if ( searchContext.isReferralIgnored() ) 1801 { 1802 throw buildLdapPartialResultException( childDn ); 1803 } 1804 else 1805 { 1806 throw buildReferralExceptionForSearch( parentEntry, childDn, searchContext.getScope() ); 1807 } 1808 } 1809 } 1810 } 1811 finally 1812 { 1813 // Unlock the ReferralManager 1814 directoryService.getReferralManager().unlock(); 1815 } 1816 1817 // Call the Search method 1818 Interceptor head = directoryService.getInterceptor( searchContext.getNextInterceptor() ); 1819 1820 EntryFilteringCursor cursor = null; 1821 Partition partition = directoryService.getPartitionNexus().getPartition( dn ); 1822 1823 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 1824 { 1825 searchContext.setPartition( partition ); 1826 searchContext.setTransaction( partitionTxn ); 1827 lockRead(); 1828 1829 try 1830 { 1831 cursor = head.search( searchContext ); 1832 } 1833 finally 1834 { 1835 unlockRead(); 1836 } 1837 } 1838 catch ( IOException ioe ) 1839 { 1840 throw new LdapOtherException( ioe.getMessage(), ioe ); 1841 } 1842 1843 if ( IS_DEBUG ) 1844 { 1845 OPERATION_LOG.debug( "<< SearchOperation successful" ); 1846 } 1847 1848 if ( IS_TIME ) 1849 { 1850 OPERATION_TIME.debug( "Search operation took {} ns", ( System.nanoTime() - opStart ) ); 1851 } 1852 1853 return cursor; 1854 } 1855 1856 1857 /** 1858 * {@inheritDoc} 1859 */ 1860 public void unbind( UnbindOperationContext unbindContext ) throws LdapException 1861 { 1862 if ( IS_DEBUG ) 1863 { 1864 OPERATION_LOG.debug( ">> UnbindOperation : {}", unbindContext ); 1865 } 1866 1867 long opStart = 0L; 1868 1869 if ( IS_TIME ) 1870 { 1871 opStart = System.nanoTime(); 1872 } 1873 1874 ensureStarted(); 1875 1876 // Call the Unbind method 1877 Interceptor head = directoryService.getInterceptor( unbindContext.getNextInterceptor() ); 1878 1879 head.unbind( unbindContext ); 1880 1881 if ( IS_DEBUG ) 1882 { 1883 OPERATION_LOG.debug( "<< UnbindOperation successful" ); 1884 } 1885 1886 if ( IS_TIME ) 1887 { 1888 OPERATION_TIME.debug( "Unbind operation took {} ns", ( System.nanoTime() - opStart ) ); 1889 } 1890 } 1891 1892 1893 private void ensureStarted() throws LdapServiceUnavailableException 1894 { 1895 if ( !directoryService.isStarted() ) 1896 { 1897 throw new LdapServiceUnavailableException( ResultCodeEnum.UNAVAILABLE, I18n.err( I18n.ERR_316 ) ); 1898 } 1899 } 1900}