001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2007-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.core; 028 import org.opends.messages.Message; 029 import org.opends.messages.MessageBuilder; 030 031 032 import static org.opends.server.config.ConfigConstants.ATTR_OBJECTCLASS; 033 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_ENTRY_DN; 034 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_ERROR_MESSAGE; 035 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_MATCHED_DN; 036 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_PROCESSING_TIME; 037 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_REFERRAL_URLS; 038 import static org.opends.server.core.CoreConstants.LOG_ELEMENT_RESULT_CODE; 039 import static org.opends.server.loggers.AccessLogger.logAddRequest; 040 import static org.opends.server.loggers.AccessLogger.logAddResponse; 041 import static org.opends.server.loggers.ErrorLogger.logError; 042 import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; 043 import static org.opends.messages.CoreMessages.*; 044 import static org.opends.server.util.StaticUtils.getExceptionMessage; 045 import static org.opends.server.util.StaticUtils.toLowerCase; 046 047 import java.util.ArrayList; 048 import java.util.HashMap; 049 import java.util.Iterator; 050 import java.util.LinkedHashSet; 051 import java.util.List; 052 import java.util.Map; 053 054 import org.opends.server.api.ClientConnection; 055 import org.opends.server.api.plugin.PluginResult; 056 import org.opends.server.loggers.debug.DebugLogger; 057 import org.opends.server.loggers.debug.DebugTracer; 058 import org.opends.server.protocols.asn1.ASN1OctetString; 059 import org.opends.server.protocols.ldap.LDAPAttribute; 060 import org.opends.server.types.*; 061 import org.opends.server.types.operation.PostResponseAddOperation; 062 import org.opends.server.types.operation.PreParseAddOperation; 063 import org.opends.server.workflowelement.localbackend.LocalBackendAddOperation; 064 065 066 067 068 /** 069 * This class defines an operation that may be used to add a new entry to the 070 * Directory Server. 071 */ 072 public class AddOperationBasis 073 extends AbstractOperation 074 implements PreParseAddOperation, AddOperation, Runnable, 075 PostResponseAddOperation 076 { 077 078 /** 079 * The tracer object for the debug logger. 080 */ 081 private static final DebugTracer TRACER = DebugLogger.getTracer(); 082 083 // The set of response controls to send to the client. 084 private ArrayList<Control> responseControls; 085 086 // The raw, unprocessed entry DN as provided in the request. This may or may 087 // not be a valid DN. 088 private ByteString rawEntryDN; 089 090 // The processed DN of the entry to add. 091 private DN entryDN; 092 093 // The proxied authorization target DN for this operation. 094 private DN proxiedAuthorizationDN; 095 096 // The set of attributes (including the objectclass attribute) in a raw, 097 // unprocessed form as provided in the request. One or more of these 098 // attributes may be invalid. 099 private List<RawAttribute> rawAttributes; 100 101 // The set of operational attributes for the entry to add. 102 private Map<AttributeType,List<Attribute>> operationalAttributes; 103 104 // The set of user attributes for the entry to add. 105 private Map<AttributeType,List<Attribute>> userAttributes; 106 107 // The set of objectclasses for the entry to add. 108 private Map<ObjectClass,String> objectClasses; 109 110 // The change number that has been assigned to this operation. 111 private long changeNumber; 112 113 114 /** 115 * Creates a new add operation with the provided information. 116 * 117 * @param clientConnection The client connection with which this operation 118 * is associated. 119 * @param operationID The operation ID for this operation. 120 * @param messageID The message ID of the request with which this 121 * operation is associated. 122 * @param requestControls The set of controls included in the request. 123 * @param rawEntryDN The raw DN of the entry to add from the client 124 * request. This may or may not be a valid DN. 125 * @param rawAttributes The raw set of attributes from the client 126 * request (including the objectclass attribute). 127 * This may contain invalid attributes. 128 */ 129 public AddOperationBasis(ClientConnection clientConnection, long operationID, 130 int messageID, List<Control> requestControls, 131 ByteString rawEntryDN, List<RawAttribute> rawAttributes) 132 { 133 super(clientConnection, operationID, messageID, requestControls); 134 135 136 this.rawEntryDN = rawEntryDN; 137 this.rawAttributes = rawAttributes; 138 139 responseControls = new ArrayList<Control>(); 140 cancelRequest = null; 141 entryDN = null; 142 userAttributes = null; 143 operationalAttributes = null; 144 objectClasses = null; 145 proxiedAuthorizationDN = null; 146 changeNumber = -1; 147 } 148 149 150 151 /** 152 * Creates a new add operation with the provided information. 153 * 154 * @param clientConnection The client connection with which this 155 * operation is associated. 156 * @param operationID The operation ID for this operation. 157 * @param messageID The message ID of the request with which 158 * this operation is associated. 159 * @param requestControls The set of controls included in the request. 160 * @param entryDN The DN for the entry. 161 * @param objectClasses The set of objectclasses for the entry. 162 * @param userAttributes The set of user attributes for the entry. 163 * @param operationalAttributes The set of operational attributes for the 164 * entry. 165 */ 166 public AddOperationBasis(ClientConnection clientConnection, long operationID, 167 int messageID, List<Control> requestControls, 168 DN entryDN, Map<ObjectClass,String> objectClasses, 169 Map<AttributeType,List<Attribute>> userAttributes, 170 Map<AttributeType,List<Attribute>> operationalAttributes) 171 { 172 super(clientConnection, operationID, messageID, requestControls); 173 174 175 this.entryDN = entryDN; 176 this.objectClasses = objectClasses; 177 this.userAttributes = userAttributes; 178 this.operationalAttributes = operationalAttributes; 179 180 rawEntryDN = new ASN1OctetString(entryDN.toString()); 181 182 rawAttributes = new ArrayList<RawAttribute>(); 183 184 ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>(); 185 for (String s : objectClasses.values()) 186 { 187 ocValues.add(new ASN1OctetString(s)); 188 } 189 190 LDAPAttribute ocAttr = new LDAPAttribute(ATTR_OBJECTCLASS, ocValues); 191 rawAttributes.add(ocAttr); 192 193 for (List<Attribute> attrList : userAttributes.values()) 194 { 195 for (Attribute a : attrList) 196 { 197 rawAttributes.add(new LDAPAttribute(a)); 198 } 199 } 200 201 for (List<Attribute> attrList : operationalAttributes.values()) 202 { 203 for (Attribute a : attrList) 204 { 205 rawAttributes.add(new LDAPAttribute(a)); 206 } 207 } 208 209 responseControls = new ArrayList<Control>(); 210 proxiedAuthorizationDN = null; 211 cancelRequest = null; 212 changeNumber = -1; 213 } 214 215 216 /** 217 * {@inheritDoc} 218 */ 219 public final ByteString getRawEntryDN() 220 { 221 return rawEntryDN; 222 } 223 224 /** 225 * {@inheritDoc} 226 */ 227 public final void setRawEntryDN(ByteString rawEntryDN) 228 { 229 this.rawEntryDN = rawEntryDN; 230 231 entryDN = null; 232 } 233 234 235 /** 236 * {@inheritDoc} 237 */ 238 public final DN getEntryDN() 239 { 240 try 241 { 242 if (entryDN == null) 243 { 244 entryDN = DN.decode(rawEntryDN); 245 } 246 } 247 catch (DirectoryException de) 248 { 249 if (debugEnabled()) 250 { 251 TRACER.debugCaught(DebugLogLevel.ERROR, de); 252 } 253 254 setResultCode(de.getResultCode()); 255 appendErrorMessage(de.getMessageObject()); 256 setMatchedDN(de.getMatchedDN()); 257 setReferralURLs(de.getReferralURLs()); 258 } 259 return entryDN; 260 } 261 262 263 /** 264 * {@inheritDoc} 265 */ 266 public final List<RawAttribute> getRawAttributes() 267 { 268 return rawAttributes; 269 } 270 271 272 /** 273 * {@inheritDoc} 274 */ 275 public final void addRawAttribute(RawAttribute rawAttribute) 276 { 277 rawAttributes.add(rawAttribute); 278 279 objectClasses = null; 280 userAttributes = null; 281 operationalAttributes = null; 282 } 283 284 285 /** 286 * {@inheritDoc} 287 */ 288 public final void setRawAttributes(List<RawAttribute> rawAttributes) 289 { 290 this.rawAttributes = rawAttributes; 291 292 objectClasses = null; 293 userAttributes = null; 294 operationalAttributes = null; 295 } 296 297 298 299 /** 300 * {@inheritDoc} 301 */ 302 public final Map<ObjectClass,String> getObjectClasses() 303 { 304 if (objectClasses == null){ 305 computeObjectClassesAndAttributes(); 306 } 307 return objectClasses; 308 } 309 310 311 312 /** 313 * {@inheritDoc} 314 */ 315 public final void addObjectClass(ObjectClass objectClass, String name) 316 { 317 objectClasses.put(objectClass, name); 318 } 319 320 321 322 /** 323 * {@inheritDoc} 324 */ 325 public final void removeObjectClass(ObjectClass objectClass) 326 { 327 objectClasses.remove(objectClass); 328 } 329 330 331 332 /** 333 * {@inheritDoc} 334 */ 335 public final Map<AttributeType,List<Attribute>> getUserAttributes() 336 { 337 if (userAttributes == null){ 338 computeObjectClassesAndAttributes(); 339 } 340 return userAttributes; 341 } 342 343 344 /** 345 * {@inheritDoc} 346 */ 347 public final Map<AttributeType,List<Attribute>> getOperationalAttributes() 348 { 349 if (operationalAttributes == null){ 350 computeObjectClassesAndAttributes(); 351 } 352 return operationalAttributes; 353 } 354 355 /** 356 * Build the objectclasses, the user attributes and the operational attributes 357 * if there are not already computed. 358 */ 359 private final void computeObjectClassesAndAttributes() 360 { 361 if ((objectClasses == null) || (userAttributes == null) || 362 (operationalAttributes == null)) 363 { 364 objectClasses = new HashMap<ObjectClass,String>(); 365 userAttributes = new HashMap<AttributeType,List<Attribute>>(); 366 operationalAttributes = new HashMap<AttributeType,List<Attribute>>(); 367 368 for (RawAttribute a : rawAttributes) 369 { 370 try 371 { 372 Attribute attr = a.toAttribute(); 373 AttributeType attrType = attr.getAttributeType(); 374 375 // If the attribute type is marked "NO-USER-MODIFICATION" then fail 376 // unless this is an internal operation or is related to 377 // synchronization in some way. 378 if (attrType.isNoUserModification()) 379 { 380 if (! (isInternalOperation() || isSynchronizationOperation())) 381 { 382 setResultCode(ResultCode.UNWILLING_TO_PERFORM); 383 appendErrorMessage(ERR_ADD_ATTR_IS_NO_USER_MOD.get( 384 String.valueOf(entryDN), 385 attr.getName())); 386 387 objectClasses = null; 388 userAttributes = null; 389 operationalAttributes = null; 390 return; 391 } 392 } 393 394 if (attrType.isObjectClassType()) 395 { 396 for (ByteString os : a.getValues()) 397 { 398 String ocName = os.toString(); 399 ObjectClass oc = 400 DirectoryServer.getObjectClass(toLowerCase(ocName)); 401 if (oc == null) 402 { 403 oc = DirectoryServer.getDefaultObjectClass(ocName); 404 } 405 406 objectClasses.put(oc,ocName); 407 } 408 } 409 else if (attrType.isOperational()) 410 { 411 List<Attribute> attrs = operationalAttributes.get(attrType); 412 if (attrs == null) 413 { 414 attrs = new ArrayList<Attribute>(1); 415 attrs.add(attr); 416 operationalAttributes.put(attrType, attrs); 417 } 418 else 419 { 420 attrs.add(attr); 421 } 422 } 423 else 424 { 425 List<Attribute> attrs = userAttributes.get(attrType); 426 if (attrs == null) 427 { 428 attrs = new ArrayList<Attribute>(1); 429 attrs.add(attr); 430 userAttributes.put(attrType, attrs); 431 } 432 else 433 { 434 // Check to see if any of the existing attributes in the list 435 // have the same set of options. If so, then add the values 436 // to that attribute. 437 boolean attributeSeen = false; 438 for (Attribute ea : attrs) 439 { 440 if (ea.optionsEqual(attr.getOptions())) 441 { 442 LinkedHashSet<AttributeValue> valueSet = ea.getValues(); 443 valueSet.addAll(attr.getValues()); 444 attributeSeen = true; 445 } 446 } 447 if (!attributeSeen) 448 { 449 // This is the first occurrence of the attribute and options. 450 attrs.add(attr); 451 } 452 } 453 } 454 } 455 catch (LDAPException le) 456 { 457 setResultCode(ResultCode.valueOf(le.getResultCode())); 458 appendErrorMessage(le.getMessageObject()); 459 460 objectClasses = null; 461 userAttributes = null; 462 operationalAttributes = null; 463 } 464 } 465 } 466 } 467 468 /** 469 * {@inheritDoc} 470 */ 471 public final void setAttribute(AttributeType attributeType, 472 List<Attribute> attributeList) 473 { 474 if (attributeType.isOperational()) 475 { 476 if ((attributeList == null) || (attributeList.isEmpty())) 477 { 478 operationalAttributes.remove(attributeType); 479 } 480 else 481 { 482 operationalAttributes.put(attributeType, attributeList); 483 } 484 } 485 else 486 { 487 if ((attributeList == null) || (attributeList.isEmpty())) 488 { 489 userAttributes.remove(attributeType); 490 } 491 else 492 { 493 userAttributes.put(attributeType, attributeList); 494 } 495 } 496 } 497 498 499 /** 500 * {@inheritDoc} 501 */ 502 public final void removeAttribute(AttributeType attributeType) 503 { 504 if (attributeType.isOperational()) 505 { 506 operationalAttributes.remove(attributeType); 507 } 508 else 509 { 510 userAttributes.remove(attributeType); 511 } 512 } 513 514 /** 515 * {@inheritDoc} 516 */ 517 public final long getChangeNumber() 518 { 519 return changeNumber; 520 } 521 522 523 /** 524 * {@inheritDoc} 525 */ 526 public final void setChangeNumber(long changeNumber) 527 { 528 this.changeNumber = changeNumber; 529 } 530 531 532 /** 533 * {@inheritDoc} 534 */ 535 public final OperationType getOperationType() 536 { 537 // Note that no debugging will be done in this method because it is a likely 538 // candidate for being called by the logging subsystem. 539 540 return OperationType.ADD; 541 } 542 543 544 /** 545 * {@inheritDoc} 546 */ 547 public final String[][] getRequestLogElements() 548 { 549 // Note that no debugging will be done in this method because it is a likely 550 // candidate for being called by the logging subsystem. 551 552 return new String[][] 553 { 554 new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) } 555 }; 556 } 557 558 559 560 /** 561 * {@inheritDoc} 562 */ 563 public final String[][] getResponseLogElements() 564 { 565 // Note that no debugging will be done in this method because it is a likely 566 // candidate for being called by the logging subsystem. 567 568 String resultCode = String.valueOf(getResultCode().getIntValue()); 569 570 String errorMessage; 571 MessageBuilder errorMessageBuffer = getErrorMessage(); 572 if (errorMessageBuffer == null) 573 { 574 errorMessage = null; 575 } 576 else 577 { 578 errorMessage = errorMessageBuffer.toString(); 579 } 580 581 String matchedDNStr; 582 DN matchedDN = getMatchedDN(); 583 if (matchedDN == null) 584 { 585 matchedDNStr = null; 586 } 587 else 588 { 589 matchedDNStr = matchedDN.toString(); 590 } 591 592 String referrals; 593 List<String> referralURLs = getReferralURLs(); 594 if ((referralURLs == null) || referralURLs.isEmpty()) 595 { 596 referrals = null; 597 } 598 else 599 { 600 StringBuilder buffer = new StringBuilder(); 601 Iterator<String> iterator = referralURLs.iterator(); 602 buffer.append(iterator.next()); 603 604 while (iterator.hasNext()) 605 { 606 buffer.append(", "); 607 buffer.append(iterator.next()); 608 } 609 610 referrals = buffer.toString(); 611 } 612 613 String processingTime = 614 String.valueOf(getProcessingTime()); 615 616 return new String[][] 617 { 618 new String[] { LOG_ELEMENT_RESULT_CODE, resultCode }, 619 new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage }, 620 new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr }, 621 new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals }, 622 new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime } 623 }; 624 } 625 626 /** 627 * {@inheritDoc} 628 */ 629 public DN getProxiedAuthorizationDN() 630 { 631 return proxiedAuthorizationDN; 632 } 633 634 /** 635 * {@inheritDoc} 636 */ 637 public final ArrayList<Control> getResponseControls() 638 { 639 return responseControls; 640 } 641 642 643 644 /** 645 * {@inheritDoc} 646 */ 647 public final void addResponseControl(Control control) 648 { 649 responseControls.add(control); 650 } 651 652 653 654 /** 655 * {@inheritDoc} 656 */ 657 public final void removeResponseControl(Control control) 658 { 659 responseControls.remove(control); 660 } 661 662 663 664 /** 665 * {@inheritDoc} 666 */ 667 public final void toString(StringBuilder buffer) 668 { 669 buffer.append("AddOperation(connID="); 670 buffer.append(clientConnection.getConnectionID()); 671 buffer.append(", opID="); 672 buffer.append(operationID); 673 buffer.append(", dn="); 674 buffer.append(rawEntryDN); 675 buffer.append(")"); 676 } 677 678 /** 679 * {@inheritDoc} 680 */ 681 public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN) 682 { 683 this.proxiedAuthorizationDN = proxiedAuthorizationDN; 684 } 685 686 /** 687 * {@inheritDoc} 688 */ 689 public final void run() 690 { 691 setResultCode(ResultCode.UNDEFINED); 692 693 // Start the processing timer. 694 setProcessingStartTime(); 695 696 // Log the add request message. 697 logAddRequest(this); 698 699 // Get the plugin config manager that will be used for invoking plugins. 700 PluginConfigManager pluginConfigManager = 701 DirectoryServer.getPluginConfigManager(); 702 703 // This flag is set to true as soon as a workflow has been executed. 704 boolean workflowExecuted = false; 705 706 try 707 { 708 // Check for and handle a request to cancel this operation. 709 checkIfCanceled(false); 710 711 // Invoke the pre-parse add plugins. 712 PluginResult.PreParse preParseResult = 713 pluginConfigManager.invokePreParseAddPlugins(this); 714 715 if(!preParseResult.continueProcessing()) 716 { 717 setResultCode(preParseResult.getResultCode()); 718 appendErrorMessage(preParseResult.getErrorMessage()); 719 setMatchedDN(preParseResult.getMatchedDN()); 720 setReferralURLs(preParseResult.getReferralURLs()); 721 return; 722 } 723 724 // Check for and handle a request to cancel this operation. 725 checkIfCanceled(false); 726 727 // Process the entry DN and set of attributes to convert them from their 728 // raw forms as provided by the client to the forms required for the rest 729 // of the add processing. 730 DN entryDN = getEntryDN(); 731 if (entryDN == null){ 732 return; 733 } 734 735 // Retrieve the network group attached to the client connection 736 // and get a workflow to process the operation. 737 NetworkGroup ng = getClientConnection().getNetworkGroup(); 738 Workflow workflow = ng.getWorkflowCandidate(entryDN); 739 if (workflow == null) 740 { 741 // We have found no workflow for the requested base DN, just return 742 // a no such entry result code and stop the processing. 743 updateOperationErrMsgAndResCode(); 744 return; 745 } 746 workflow.execute(this); 747 workflowExecuted = true; 748 749 } 750 catch(CanceledOperationException coe) 751 { 752 if (debugEnabled()) 753 { 754 TRACER.debugCaught(DebugLogLevel.ERROR, coe); 755 } 756 757 setResultCode(ResultCode.CANCELED); 758 cancelResult = new CancelResult(ResultCode.CANCELED, null); 759 760 appendErrorMessage(coe.getCancelRequest().getCancelReason()); 761 } 762 finally 763 { 764 // Stop the processing timer. 765 setProcessingStopTime(); 766 767 if(cancelRequest == null || cancelResult == null || 768 cancelResult.getResultCode() != ResultCode.CANCELED || 769 cancelRequest.notifyOriginalRequestor() || 770 DirectoryServer.notifyAbandonedOperations()) 771 { 772 clientConnection.sendResponse(this); 773 } 774 775 776 // Log the add response message. 777 logAddResponse(this); 778 779 // Notifies any persistent searches that might be registered with the 780 // server. 781 notifyPersistentSearches(workflowExecuted); 782 783 // Invoke the post-response add plugins. 784 invokePostResponsePlugins(workflowExecuted); 785 786 // If no cancel result, set it 787 if(cancelResult == null) 788 { 789 cancelResult = new CancelResult(ResultCode.TOO_LATE, null); 790 } 791 } 792 } 793 794 795 /** 796 * Invokes the post response plugins. If a workflow has been executed 797 * then invoke the post response plugins provided by the workflow 798 * elements of the worklfow, otherwise invoke the post reponse plugins 799 * that have been registered with the current operation. 800 * 801 * @param workflowExecuted <code>true</code> if a workflow has been 802 * executed 803 */ 804 private void invokePostResponsePlugins(boolean workflowExecuted) 805 { 806 // Get the plugin config manager that will be used for invoking plugins. 807 PluginConfigManager pluginConfigManager = 808 DirectoryServer.getPluginConfigManager(); 809 810 // Invoke the post response plugins 811 if (workflowExecuted) 812 { 813 // Invoke the post response plugins that have been registered by 814 // the workflow elements 815 List localOperations = 816 (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); 817 818 if (localOperations != null) 819 { 820 for (Object localOp : localOperations) 821 { 822 LocalBackendAddOperation localOperation = 823 (LocalBackendAddOperation)localOp; 824 pluginConfigManager.invokePostResponseAddPlugins(localOperation); 825 } 826 } 827 } 828 else 829 { 830 // Invoke the post response plugins that have been registered with 831 // the current operation 832 pluginConfigManager.invokePostResponseAddPlugins(this); 833 } 834 } 835 836 837 /** 838 * Notifies any persistent searches that might be registered with the server. 839 * If no workflow has been executed then don't notify persistent searches. 840 * 841 * @param workflowExecuted <code>true</code> if a workflow has been 842 * executed 843 */ 844 private void notifyPersistentSearches(boolean workflowExecuted) 845 { 846 if (! workflowExecuted) 847 { 848 return; 849 } 850 851 List localOperations = 852 (List)getAttachment(Operation.LOCALBACKENDOPERATIONS); 853 854 if (localOperations != null) 855 { 856 for (Object localOp : localOperations) 857 { 858 LocalBackendAddOperation localOperation = 859 (LocalBackendAddOperation)localOp; 860 861 if ((getResultCode() == ResultCode.SUCCESS) && 862 (localOperation.getEntryToAdd() != null)) 863 { 864 for (PersistentSearch persistentSearch : 865 DirectoryServer.getPersistentSearches()) 866 { 867 try 868 { 869 persistentSearch.processAdd(localOperation, 870 localOperation.getEntryToAdd()); 871 } 872 catch (Exception e) 873 { 874 if (debugEnabled()) 875 { 876 TRACER.debugCaught(DebugLogLevel.ERROR, e); 877 } 878 879 Message message = ERR_ADD_ERROR_NOTIFYING_PERSISTENT_SEARCH.get( 880 String.valueOf(persistentSearch), getExceptionMessage(e)); 881 logError(message); 882 883 DirectoryServer.deregisterPersistentSearch(persistentSearch); 884 } 885 } 886 } 887 } 888 } 889 } 890 891 892 /** 893 * Updates the error message and the result code of the operation. 894 * 895 * This method is called because no workflows were found to process 896 * the operation. 897 */ 898 private void updateOperationErrMsgAndResCode() 899 { 900 DN entryDN = getEntryDN(); 901 DN parentDN = entryDN.getParentDNInSuffix(); 902 if (parentDN == null) 903 { 904 // Either this entry is a suffix or doesn't belong in the directory. 905 if (DirectoryServer.isNamingContext(entryDN)) 906 { 907 // This is fine. This entry is one of the configured suffixes. 908 return; 909 } 910 if (entryDN.isNullDN()) 911 { 912 // This is not fine. The root DSE cannot be added. 913 setResultCode(ResultCode.UNWILLING_TO_PERFORM); 914 appendErrorMessage(ERR_ADD_CANNOT_ADD_ROOT_DSE.get()); 915 return; 916 } 917 // The entry doesn't have a parent but isn't a suffix. This is not 918 // allowed. 919 setResultCode(ResultCode.NO_SUCH_OBJECT); 920 appendErrorMessage(ERR_ADD_ENTRY_NOT_SUFFIX.get( 921 String.valueOf(entryDN))); 922 return; 923 } 924 // The suffix does not exist 925 setResultCode(ResultCode.NO_SUCH_OBJECT); 926 appendErrorMessage(ERR_ADD_ENTRY_UNKNOWN_SUFFIX.get( 927 String.valueOf(entryDN))); 928 } 929 930 931 /** 932 * {@inheritDoc} 933 * 934 * This method always returns null. 935 */ 936 public Entry getEntryToAdd() 937 { 938 return null; 939 } 940 941 } 942