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