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