From fbda6e0892dcfcc8dd43d21f6fb134aabb8d0cac Mon Sep 17 00:00:00 2001
From: jarnou <jarnou@localhost>
Date: Tue, 03 Jul 2007 09:29:17 +0000
Subject: [PATCH] Commits the refactoring of the core server to provide support for proxy/distribution/virtual functionnalities. This includes the new set of local operations, as well as the workflow and networkgroup support.

---
 opends/src/server/org/opends/server/core/ModifyOperation.java | 2933 -----------------------------------------------------------
 1 files changed, 26 insertions(+), 2,907 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/ModifyOperation.java b/opends/src/server/org/opends/server/core/ModifyOperation.java
index e9661d4..ab03679 100644
--- a/opends/src/server/org/opends/server/core/ModifyOperation.java
+++ b/opends/src/server/org/opends/server/core/ModifyOperation.java
@@ -26,244 +26,29 @@
  */
 package org.opends.server.core;
 
-
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.concurrent.locks.Lock;
 
-import org.opends.server.api.AttributeSyntax;
-import org.opends.server.api.Backend;
-import org.opends.server.api.ChangeNotificationListener;
-import org.opends.server.api.ClientConnection;
-import org.opends.server.api.PasswordStorageScheme;
-import org.opends.server.api.SynchronizationProvider;
-import org.opends.server.api.plugin.PostOperationPluginResult;
-import org.opends.server.api.plugin.PreOperationPluginResult;
-import org.opends.server.api.plugin.PreParsePluginResult;
-import org.opends.server.controls.LDAPAssertionRequestControl;
-import org.opends.server.controls.LDAPPreReadRequestControl;
-import org.opends.server.controls.LDAPPreReadResponseControl;
-import org.opends.server.controls.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
-import org.opends.server.controls.ProxiedAuthV1Control;
-import org.opends.server.controls.ProxiedAuthV2Control;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPAttribute;
-import org.opends.server.protocols.ldap.LDAPModification;
-import org.opends.server.schema.AuthPasswordSyntax;
-import org.opends.server.schema.BooleanSyntax;
-import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.AcceptRejectWarn;
-import org.opends.server.types.AccountStatusNotificationType;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AuthenticationInfo;
 import org.opends.server.types.ByteString;
-import org.opends.server.types.CancelledOperationException;
-import org.opends.server.types.CancelRequest;
-import org.opends.server.types.CancelResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DisconnectReason;
 import org.opends.server.types.DN;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ErrorLogCategory;
-import org.opends.server.types.ErrorLogSeverity;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LockManager;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
 import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.Privilege;
 import org.opends.server.types.RawModification;
-import org.opends.server.types.RDN;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SynchronizationProviderResult;
-import org.opends.server.types.operation.PreParseModifyOperation;
-import org.opends.server.types.operation.PreOperationModifyOperation;
-import org.opends.server.types.operation.PostOperationModifyOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
-
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.core.CoreConstants.*;
-import static org.opends.server.loggers.AccessLogger.*;
-import static org.opends.server.loggers.ErrorLogger.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-import static org.opends.server.messages.CoreMessages.*;
-import static org.opends.server.messages.MessageHandler.getMessage;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
 
 /**
- * This class defines an operation that may be used to modify an entry in the
- * Directory Server.
+ * This interface defines an operation used to modify an entry in
+ * the Directory Server.
  */
-public class ModifyOperation
-       extends Operation
-       implements PreParseModifyOperation, PreOperationModifyOperation,
-                  PostOperationModifyOperation, PostResponseModifyOperation
+public interface ModifyOperation extends Operation
 {
   /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // The raw, unprocessed entry DN as included by the client request.
-  private ByteString rawEntryDN;
-
-  // The cancel request that has been issued for this modify operation.
-  private CancelRequest cancelRequest;
-
-  // The DN of the entry for the modify operation.
-  private DN entryDN;
-
-  // The proxied authorization target DN for this operation.
-  private DN proxiedAuthorizationDN;
-
-  // The current entry, before any changes are applied.
-  private Entry currentEntry;
-
-  // The modified entry that will be stored in the backend.
-  private Entry modifiedEntry;
-
-  // The set of clear-text current passwords (if any were provided).
-  private List<AttributeValue> currentPasswords;
-
-  // The set of clear-text new passwords (if any were provided).
-  private List<AttributeValue> newPasswords;
-
-  // The set of response controls for this modify operation.
-  private List<Control> responseControls;
-
-  // The raw, unprocessed set of modifications as included in the client
-  // request.
-  private List<RawModification> rawModifications;
-
-  // The set of modifications for this modify operation.
-  private List<Modification> modifications;
-
-  // The change number that has been assigned to this operation.
-  private long changeNumber;
-
-  // The time that processing started on this operation.
-  private long processingStartTime;
-
-  // The time that processing ended on this operation.
-  private long processingStopTime;
-
-
-
-  /**
-   * Creates a new modify operation with the provided information.
-   *
-   * @param  clientConnection  The client connection with which this operation
-   *                           is associated.
-   * @param  operationID       The operation ID for this operation.
-   * @param  messageID         The message ID of the request with which this
-   *                           operation is associated.
-   * @param  requestControls   The set of controls included in the request.
-   * @param  rawEntryDN        The raw, unprocessed DN of the entry to modify,
-   *                           as included in the client request.
-   * @param  rawModifications  The raw, unprocessed set of modifications for
-   *                           this modify operation as included in the client
-   *                           request.
-   */
-  public ModifyOperation(ClientConnection clientConnection, long operationID,
-                         int messageID, List<Control> requestControls,
-                         ByteString rawEntryDN,
-                         List<RawModification> rawModifications)
-  {
-    super(clientConnection, operationID, messageID, requestControls);
-
-
-    this.rawEntryDN       = rawEntryDN;
-    this.rawModifications = rawModifications;
-
-    entryDN          = null;
-    modifications    = null;
-    currentEntry     = null;
-    modifiedEntry    = null;
-    responseControls = new ArrayList<Control>();
-    cancelRequest    = null;
-    changeNumber     = -1;
-
-    currentPasswords = null;
-    newPasswords     = null;
-  }
-
-
-
-  /**
-   * Creates a new modify operation with the provided information.
-   *
-   * @param  clientConnection  The client connection with which this operation
-   *                           is associated.
-   * @param  operationID       The operation ID for this operation.
-   * @param  messageID         The message ID of the request with which this
-   *                           operation is associated.
-   * @param  requestControls   The set of controls included in the request.
-   * @param  entryDN           The entry DN for the modify operation.
-   * @param  modifications     The set of modifications for this modify
-   *                           operation.
-   */
-  public ModifyOperation(ClientConnection clientConnection, long operationID,
-                         int messageID, List<Control> requestControls,
-                         DN entryDN, List<Modification> modifications)
-  {
-    super(clientConnection, operationID, messageID, requestControls);
-
-
-    this.entryDN       = entryDN;
-    this.modifications = modifications;
-
-    rawEntryDN = new ASN1OctetString(entryDN.toString());
-
-    rawModifications = new ArrayList<RawModification>(modifications.size());
-    for (Modification m : modifications)
-    {
-      rawModifications.add(new LDAPModification(m.getModificationType(),
-                                    new LDAPAttribute(m.getAttribute())));
-    }
-
-    currentEntry     = null;
-    modifiedEntry    = null;
-    responseControls = new ArrayList<Control>();
-    cancelRequest    = null;
-    changeNumber     = -1;
-
-    currentPasswords = null;
-    newPasswords     = null;
-  }
-
-
-
-  /**
    * Retrieves the raw, unprocessed entry DN as included in the client request.
    * The DN that is returned may or may not be a valid DN, since no validation
    * will have been performed upon it.
    *
    * @return  The raw, unprocessed entry DN as included in the client request.
    */
-  public final ByteString getRawEntryDN()
-  {
-    return rawEntryDN;
-  }
-
-
+  public abstract ByteString getRawEntryDN();
 
   /**
    * Specifies the raw, unprocessed entry DN as included in the client request.
@@ -272,14 +57,7 @@
    * @param  rawEntryDN  The raw, unprocessed entry DN as included in the client
    *                     request.
    */
-  public final void setRawEntryDN(ByteString rawEntryDN)
-  {
-    this.rawEntryDN = rawEntryDN;
-
-    entryDN = null;
-  }
-
-
+  public abstract void setRawEntryDN(ByteString rawEntryDN);
 
   /**
    * Retrieves the DN of the entry to modify.  This should not be called by
@@ -289,12 +67,7 @@
    * @return  The DN of the entry to modify, or <CODE>null</CODE> if the raw
    *          entry DN has not yet been processed.
    */
-  public final DN getEntryDN()
-  {
-    return entryDN;
-  }
-
-
+  public abstract DN getEntryDN();
 
   /**
    * Retrieves the set of raw, unprocessed modifications as included in the
@@ -305,12 +78,7 @@
    * @return  The set of raw, unprocessed modifications as included in the
    *          client request.
    */
-  public final List<RawModification> getRawModifications()
-  {
-    return rawModifications;
-  }
-
-
+  public abstract List<RawModification> getRawModifications();
 
   /**
    * Adds the provided modification to the set of raw modifications for this
@@ -319,28 +87,15 @@
    * @param  rawModification  The modification to add to the set of raw
    *                          modifications for this modify operation.
    */
-  public final void addRawModification(RawModification rawModification)
-  {
-    rawModifications.add(rawModification);
-
-    modifications = null;
-  }
-
-
+  public abstract void addRawModification(RawModification rawModification);
 
   /**
    * Specifies the raw modifications for this modify operation.
    *
    * @param  rawModifications  The raw modifications for this modify operation.
    */
-  public final void setRawModifications(List<RawModification> rawModifications)
-  {
-    this.rawModifications = rawModifications;
-
-    modifications = null;
-  }
-
-
+  public abstract void setRawModifications(
+      List<RawModification> rawModifications);
 
   /**
    * Retrieves the set of modifications for this modify operation.  Its contents
@@ -350,12 +105,7 @@
    *          <CODE>null</CODE> if the modifications have not yet been
    *          processed.
    */
-  public final List<Modification> getModifications()
-  {
-    return modifications;
-  }
-
-
+  public abstract List<Modification> getModifications();
 
   /**
    * Adds the provided modification to the set of modifications to this modify
@@ -367,112 +117,8 @@
    * @throws  DirectoryException  If an unexpected problem occurs while applying
    *                              the modification to the entry.
    */
-  public final void addModification(Modification modification)
-         throws DirectoryException
-  {
-    modifiedEntry.applyModification(modification);
-    modifications.add(modification);
-  }
-
-
-
-  /**
-   * Retrieves the current entry before any modifications are applied.  This
-   * will not be available to pre-parse plugins.
-   *
-   * @return  The current entry, or <CODE>null</CODE> if it is not yet
-   *          available.
-   */
-  public final Entry getCurrentEntry()
-  {
-    return currentEntry;
-  }
-
-
-
-  /**
-   * Retrieves the modified entry that is to be written to the backend.  This
-   * will be available to pre-operation plugins, and if such a plugin does make
-   * a change to this entry, then it is also necessary to add that change to
-   * the set of modifications to ensure that the update will be consistent.
-   *
-   * @return  The modified entry that is to be written to the backend, or
-   *          <CODE>null</CODE> if it is not yet available.
-   */
-  public final Entry getModifiedEntry()
-  {
-    return modifiedEntry;
-  }
-
-
-
-  /**
-   * Retrieves the set of clear-text current passwords for the user, if
-   * available.  This will only be available if the modify operation contains
-   * one or more delete elements that target the password attribute and provide
-   * the values to delete in the clear.  It will not be available to pre-parse
-   * plugins.
-   *
-   * @return  The set of clear-text current password values as provided in the
-   *          modify request, or <CODE>null</CODE> if there were none or this
-   *          information is not yet available.
-   */
-  public final List<AttributeValue> getCurrentPasswords()
-  {
-    return currentPasswords;
-  }
-
-
-
-  /**
-   * Retrieves the set of clear-text new passwords for the user, if available.
-   * This will only be available if the modify operation contains one or more
-   * add or replace elements that target the password attribute and provide the
-   * values in the clear.  It will not be available to pre-parse plugins.
-   *
-   * @return  The set of clear-text new passwords as provided in the modify
-   *          request, or <CODE>null</CODE> if there were none or this
-   *          information is not yet available.
-   */
-  public final List<AttributeValue> getNewPasswords()
-  {
-    return newPasswords;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final long getProcessingStartTime()
-  {
-    return processingStartTime;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final long getProcessingStopTime()
-  {
-    return processingStopTime;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final long getProcessingTime()
-  {
-    return (processingStopTime - processingStartTime);
-  }
-
-
+  public abstract void addModification(Modification modification)
+      throws DirectoryException;
 
   /**
    * Retrieves the change number that has been assigned to this operation.
@@ -481,12 +127,7 @@
    *          if none has been assigned yet or if there is no applicable
    *          synchronization mechanism in place that uses change numbers.
    */
-  public final long getChangeNumber()
-  {
-    return changeNumber;
-  }
-
-
+  public abstract long getChangeNumber();
 
   /**
    * Specifies the change number that has been assigned to this operation by the
@@ -495,131 +136,7 @@
    * @param  changeNumber  The change number that has been assigned to this
    *                       operation by the synchronization mechanism.
    */
-  public final void setChangeNumber(long changeNumber)
-  {
-    this.changeNumber = changeNumber;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final void disconnectClient(DisconnectReason disconnectReason,
-                                     boolean sendNotification, String message,
-                                     int messageID)
-  {
-    // Before calling clientConnection.disconnect, we need to mark this
-    // operation as cancelled so that the attempt to cancel it later won't cause
-    // an unnecessary delay.
-    setCancelResult(CancelResult.CANCELED);
-
-    clientConnection.disconnect(disconnectReason, sendNotification, message,
-                                messageID);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final OperationType getOperationType()
-  {
-    // Note that no debugging will be done in this method because it is a likely
-    // candidate for being called by the logging subsystem.
-
-    return OperationType.MODIFY;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final String[][] getRequestLogElements()
-  {
-    // Note that no debugging will be done in this method because it is a likely
-    // candidate for being called by the logging subsystem.
-
-    return new String[][]
-    {
-      new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) }
-    };
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final String[][] getResponseLogElements()
-  {
-    // Note that no debugging will be done in this method because it is a likely
-    // candidate for being called by the logging subsystem.
-
-    String resultCode = String.valueOf(getResultCode().getIntValue());
-
-    String errorMessage;
-    StringBuilder errorMessageBuffer = getErrorMessage();
-    if (errorMessageBuffer == null)
-    {
-      errorMessage = null;
-    }
-    else
-    {
-      errorMessage = errorMessageBuffer.toString();
-    }
-
-    String matchedDNStr;
-    DN matchedDN = getMatchedDN();
-    if (matchedDN == null)
-    {
-      matchedDNStr = null;
-    }
-    else
-    {
-      matchedDNStr = matchedDN.toString();
-    }
-
-    String referrals;
-    List<String> referralURLs = getReferralURLs();
-    if ((referralURLs == null) || referralURLs.isEmpty())
-    {
-      referrals = null;
-    }
-    else
-    {
-      StringBuilder buffer = new StringBuilder();
-      Iterator<String> iterator = referralURLs.iterator();
-      buffer.append(iterator.next());
-
-      while (iterator.hasNext())
-      {
-        buffer.append(", ");
-        buffer.append(iterator.next());
-      }
-
-      referrals = buffer.toString();
-    }
-
-    String processingTime =
-         String.valueOf(processingStopTime - processingStartTime);
-
-    return new String[][]
-    {
-      new String[] { LOG_ELEMENT_RESULT_CODE, resultCode },
-      new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage },
-      new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr },
-      new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals },
-      new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime }
-    };
-  }
-
-
+  public abstract void setChangeNumber(long changeNumber);
 
   /**
    * Retrieves the proxied authorization DN for this operation if proxied
@@ -629,2415 +146,17 @@
    *          authorization has been requested, or {@code null} if proxied
    *          authorization has not been requested.
    */
-  public DN getProxiedAuthorizationDN()
-  {
-    return proxiedAuthorizationDN;
-  }
-
-
+  public abstract DN getProxiedAuthorizationDN();
 
   /**
-   * {@inheritDoc}
+   * Set the proxied authorization DN for this operation if proxied
+   * authorization has been requested.
+   *
+   * @param proxiedAuthorizationDN
+   *          The proxied authorization DN for this operation if proxied
+   *          authorization has been requested, or {@code null} if proxied
+   *          authorization has not been requested.
    */
-  @Override()
-  public final List<Control> getResponseControls()
-  {
-    return responseControls;
-  }
+  public abstract void setProxiedAuthorizationDN(DN proxiedAuthorizationDN);
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final void addResponseControl(Control control)
-  {
-    responseControls.add(control);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final void removeResponseControl(Control control)
-  {
-    responseControls.remove(control);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final void run()
-  {
-    setResultCode(ResultCode.UNDEFINED);
-
-
-    // Get the plugin config manager that will be used for invoking plugins.
-    PluginConfigManager pluginConfigManager =
-         DirectoryServer.getPluginConfigManager();
-    boolean skipPostOperation = false;
-
-
-    // Start the processing timer.
-    processingStartTime = System.currentTimeMillis();
-
-
-    // Check for and handle a request to cancel this operation.
-    if (cancelRequest != null)
-    {
-      indicateCancelled(cancelRequest);
-      processingStopTime = System.currentTimeMillis();
-      return;
-    }
-
-
-    // Create a labeled block of code that we can break out of if a problem is
-    // detected.
-modifyProcessing:
-    {
-      // Invoke the pre-parse modify plugins.
-      PreParsePluginResult preParseResult =
-           pluginConfigManager.invokePreParseModifyPlugins(this);
-      if (preParseResult.connectionTerminated())
-      {
-        // There's no point in continuing with anything.  Log the request and
-        // result and return.
-        setResultCode(ResultCode.CANCELED);
-
-        int msgID = MSGID_CANCELED_BY_PREPARSE_DISCONNECT;
-        appendErrorMessage(getMessage(msgID));
-
-        processingStopTime = System.currentTimeMillis();
-
-        logModifyRequest(this);
-        logModifyResponse(this);
-        pluginConfigManager.invokePostResponseModifyPlugins(this);
-        return;
-      }
-      else if (preParseResult.sendResponseImmediately())
-      {
-        skipPostOperation = true;
-        logModifyRequest(this);
-        break modifyProcessing;
-      }
-      else if (preParseResult.skipCoreProcessing())
-      {
-        skipPostOperation = false;
-        break modifyProcessing;
-      }
-
-
-      // Log the modify request message.
-      logModifyRequest(this);
-
-
-      // Check for and handle a request to cancel this operation.
-      if (cancelRequest != null)
-      {
-        indicateCancelled(cancelRequest);
-        processingStopTime = System.currentTimeMillis();
-        logModifyResponse(this);
-        pluginConfigManager.invokePostResponseModifyPlugins(this);
-        return;
-      }
-
-
-      // Process the entry DN to convert it from the raw form to the form
-      // required for the rest of the modify processing.
-      try
-      {
-        if (entryDN == null)
-        {
-          entryDN = DN.decode(rawEntryDN);
-        }
-      }
-      catch (DirectoryException de)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, de);
-        }
-
-        setResultCode(de.getResultCode());
-        appendErrorMessage(de.getErrorMessage());
-        skipPostOperation = true;
-
-        break modifyProcessing;
-      }
-
-
-      // Process the modifications to convert them from their raw form to the
-      // form required for the rest of the modify processing.
-      if (modifications == null)
-      {
-        modifications = new ArrayList<Modification>(rawModifications.size());
-        for (RawModification m : rawModifications)
-        {
-          try
-          {
-            modifications.add(m.toModification());
-          }
-          catch (LDAPException le)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, le);
-            }
-
-            setResultCode(ResultCode.valueOf(le.getResultCode()));
-            appendErrorMessage(le.getMessage());
-
-            break modifyProcessing;
-          }
-        }
-      }
-
-      if (modifications.isEmpty())
-      {
-        setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-        appendErrorMessage(getMessage(MSGID_MODIFY_NO_MODIFICATIONS,
-                                      String.valueOf(entryDN)));
-        break modifyProcessing;
-      }
-
-
-      // If the user must change their password before doing anything else, and
-      // if the target of the modify operation isn't the user's own entry, then
-      // reject the request.
-      if ((! isInternalOperation()) && clientConnection.mustChangePassword())
-      {
-        DN authzDN = getAuthorizationDN();
-        if ((authzDN != null) && (! authzDN.equals(entryDN)))
-        {
-          // The user will not be allowed to do anything else before
-          // the password gets changed.
-          setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-          int msgID = MSGID_MODIFY_MUST_CHANGE_PASSWORD;
-          appendErrorMessage(getMessage(msgID));
-          break modifyProcessing;
-        }
-      }
-
-
-      // Check for and handle a request to cancel this operation.
-      if (cancelRequest != null)
-      {
-        indicateCancelled(cancelRequest);
-        processingStopTime = System.currentTimeMillis();
-        logModifyResponse(this);
-        pluginConfigManager.invokePostResponseModifyPlugins(this);
-        return;
-      }
-
-
-      // Acquire a write lock on the target entry.
-      Lock entryLock = null;
-      for (int i=0; i < 3; i++)
-      {
-        entryLock = LockManager.lockWrite(entryDN);
-        if (entryLock != null)
-        {
-          break;
-        }
-      }
-
-      if (entryLock == null)
-      {
-        setResultCode(DirectoryServer.getServerErrorResultCode());
-        appendErrorMessage(getMessage(MSGID_MODIFY_CANNOT_LOCK_ENTRY,
-                                      String.valueOf(entryDN)));
-
-        skipPostOperation = true;
-        break modifyProcessing;
-      }
-
-
-      try
-      {
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logModifyResponse(this);
-          pluginConfigManager.invokePostResponseModifyPlugins(this);
-          return;
-        }
-
-
-        // Get the entry to modify.  If it does not exist, then fail.
-        try
-        {
-          currentEntry = DirectoryServer.getEntry(entryDN);
-        }
-        catch (DirectoryException de)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, de);
-          }
-
-          setResultCode(de.getResultCode());
-          appendErrorMessage(de.getErrorMessage());
-          setMatchedDN(de.getMatchedDN());
-          setReferralURLs(de.getReferralURLs());
-
-          break modifyProcessing;
-        }
-
-        if (currentEntry == null)
-        {
-          setResultCode(ResultCode.NO_SUCH_OBJECT);
-          appendErrorMessage(getMessage(MSGID_MODIFY_NO_SUCH_ENTRY,
-                                        String.valueOf(entryDN)));
-
-          // See if one of the entry's ancestors exists.
-          DN parentDN = entryDN.getParentDNInSuffix();
-          while (parentDN != null)
-          {
-            try
-            {
-              if (DirectoryServer.entryExists(parentDN))
-              {
-                setMatchedDN(parentDN);
-                break;
-              }
-            }
-            catch (Exception e)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, e);
-              }
-              break;
-            }
-
-            parentDN = parentDN.getParentDNInSuffix();
-          }
-
-          break modifyProcessing;
-        }
-
-        // Check to see if there are any controls in the request.  If so, then
-        // see if there is any special processing required.
-        boolean                    noOp            = false;
-        LDAPPreReadRequestControl  preReadRequest  = null;
-        LDAPPostReadRequestControl postReadRequest = null;
-        List<Control> requestControls = getRequestControls();
-        if ((requestControls != null) && (! requestControls.isEmpty()))
-        {
-          for (int i=0; i < requestControls.size(); i++)
-          {
-            Control c   = requestControls.get(i);
-            String  oid = c.getOID();
-
-            if (oid.equals(OID_LDAP_ASSERTION))
-            {
-              LDAPAssertionRequestControl assertControl;
-              if (c instanceof LDAPAssertionRequestControl)
-              {
-                assertControl = (LDAPAssertionRequestControl) c;
-              }
-              else
-              {
-                try
-                {
-                  assertControl = LDAPAssertionRequestControl.decodeControl(c);
-                  requestControls.set(i, assertControl);
-                }
-                catch (LDAPException le)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                  }
-
-                  setResultCode(ResultCode.valueOf(le.getResultCode()));
-                  appendErrorMessage(le.getMessage());
-
-                  break modifyProcessing;
-                }
-              }
-
-              try
-              {
-                // FIXME -- We need to determine whether the current user has
-                //          permission to make this determination.
-                SearchFilter filter = assertControl.getSearchFilter();
-                if (! filter.matchesEntry(currentEntry))
-                {
-                  setResultCode(ResultCode.ASSERTION_FAILED);
-
-                  appendErrorMessage(getMessage(MSGID_MODIFY_ASSERTION_FAILED,
-                                                String.valueOf(entryDN)));
-
-                  break modifyProcessing;
-                }
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(ResultCode.PROTOCOL_ERROR);
-
-                int msgID = MSGID_MODIFY_CANNOT_PROCESS_ASSERTION_FILTER;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              de.getErrorMessage()));
-
-                break modifyProcessing;
-              }
-            }
-            else if (oid.equals(OID_LDAP_NOOP_OPENLDAP_ASSIGNED))
-            {
-              noOp = true;
-            }
-            else if (oid.equals(OID_LDAP_READENTRY_PREREAD))
-            {
-              if (c instanceof LDAPAssertionRequestControl)
-              {
-                preReadRequest = (LDAPPreReadRequestControl) c;
-              }
-              else
-              {
-                try
-                {
-                  preReadRequest = LDAPPreReadRequestControl.decodeControl(c);
-                  requestControls.set(i, preReadRequest);
-                }
-                catch (LDAPException le)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                  }
-
-                  setResultCode(ResultCode.valueOf(le.getResultCode()));
-                  appendErrorMessage(le.getMessage());
-
-                  break modifyProcessing;
-                }
-              }
-            }
-            else if (oid.equals(OID_LDAP_READENTRY_POSTREAD))
-            {
-              if (c instanceof LDAPAssertionRequestControl)
-              {
-                postReadRequest = (LDAPPostReadRequestControl) c;
-              }
-              else
-              {
-                try
-                {
-                  postReadRequest = LDAPPostReadRequestControl.decodeControl(c);
-                  requestControls.set(i, postReadRequest);
-                }
-                catch (LDAPException le)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                  }
-
-                  setResultCode(ResultCode.valueOf(le.getResultCode()));
-                  appendErrorMessage(le.getMessage());
-
-                  break modifyProcessing;
-                }
-              }
-            }
-            else if (oid.equals(OID_PROXIED_AUTH_V1))
-            {
-              // The requester must have the PROXIED_AUTH privilige in order to
-              // be able to use this control.
-              if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
-              {
-                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
-                appendErrorMessage(getMessage(msgID));
-                setResultCode(ResultCode.AUTHORIZATION_DENIED);
-                break modifyProcessing;
-              }
-
-
-              ProxiedAuthV1Control proxyControl;
-              if (c instanceof ProxiedAuthV1Control)
-              {
-                proxyControl = (ProxiedAuthV1Control) c;
-              }
-              else
-              {
-                try
-                {
-                  proxyControl = ProxiedAuthV1Control.decodeControl(c);
-                }
-                catch (LDAPException le)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                  }
-
-                  setResultCode(ResultCode.valueOf(le.getResultCode()));
-                  appendErrorMessage(le.getMessage());
-
-                  break modifyProcessing;
-                }
-              }
-
-
-              Entry authorizationEntry;
-              try
-              {
-                authorizationEntry = proxyControl.getAuthorizationEntry();
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(de.getResultCode());
-                appendErrorMessage(de.getErrorMessage());
-
-                break modifyProcessing;
-              }
-              if (AccessControlConfigManager.getInstance().
-                      getAccessControlHandler().isProxiedAuthAllowed(this,
-                      authorizationEntry) == false) {
-                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyProcessing;
-              }
-
-              setAuthorizationEntry(authorizationEntry);
-              if (authorizationEntry == null)
-              {
-                proxiedAuthorizationDN = DN.nullDN();
-              }
-              else
-              {
-                proxiedAuthorizationDN = authorizationEntry.getDN();
-              }
-            }
-            else if (oid.equals(OID_PROXIED_AUTH_V2))
-            {
-              // The requester must have the PROXIED_AUTH privilige in order to
-              // be able to use this control.
-              if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
-              {
-                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
-                appendErrorMessage(getMessage(msgID));
-                setResultCode(ResultCode.AUTHORIZATION_DENIED);
-                break modifyProcessing;
-              }
-
-
-              ProxiedAuthV2Control proxyControl;
-              if (c instanceof ProxiedAuthV2Control)
-              {
-                proxyControl = (ProxiedAuthV2Control) c;
-              }
-              else
-              {
-                try
-                {
-                  proxyControl = ProxiedAuthV2Control.decodeControl(c);
-                }
-                catch (LDAPException le)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
-                  }
-
-                  setResultCode(ResultCode.valueOf(le.getResultCode()));
-                  appendErrorMessage(le.getMessage());
-
-                  break modifyProcessing;
-                }
-              }
-
-
-              Entry authorizationEntry;
-              try
-              {
-                authorizationEntry = proxyControl.getAuthorizationEntry();
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(de.getResultCode());
-                appendErrorMessage(de.getErrorMessage());
-
-                break modifyProcessing;
-              }
-
-              if (AccessControlConfigManager.getInstance().
-                      getAccessControlHandler().isProxiedAuthAllowed(this,
-                      authorizationEntry) == false) {
-                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break modifyProcessing;
-              }
-              setAuthorizationEntry(authorizationEntry);
-              if (authorizationEntry == null)
-              {
-                proxiedAuthorizationDN = DN.nullDN();
-              }
-              else
-              {
-                proxiedAuthorizationDN = authorizationEntry.getDN();
-              }
-            }
-
-            // NYI -- Add support for additional controls.
-            else if (c.isCritical())
-            {
-              Backend backend = DirectoryServer.getBackend(entryDN);
-              if ((backend == null) || (! backend.supportsControl(oid)))
-              {
-                setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
-
-                int msgID = MSGID_MODIFY_UNSUPPORTED_CRITICAL_CONTROL;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              oid));
-
-                break modifyProcessing;
-              }
-            }
-          }
-        }
-
-
-        // Get the password policy state object for the entry that can be used
-        // to perform any appropriate password policy processing.  Also, see if
-        // the entry is being updated by the end user or an administrator.
-        PasswordPolicyState pwPolicyState;
-        boolean selfChange = entryDN.equals(getAuthorizationDN());
-        try
-        {
-          // FIXME -- Need a way to enable debug mode.
-          pwPolicyState = new PasswordPolicyState(currentEntry, false, false);
-        }
-        catch (DirectoryException de)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, de);
-          }
-
-          setResultCode(de.getResultCode());
-          appendErrorMessage(de.getErrorMessage());
-
-          break modifyProcessing;
-        }
-
-
-        // Create a duplicate of the entry and apply the changes to it.
-        modifiedEntry = currentEntry.duplicate(false);
-
-        if (! noOp)
-        {
-          // Invoke any conflict resolution processing that might be needed by
-          // the synchronization provider.
-          for (SynchronizationProvider provider :
-               DirectoryServer.getSynchronizationProviders())
-          {
-            try
-            {
-              SynchronizationProviderResult result =
-                   provider.handleConflictResolution(this);
-              if (! result.continueOperationProcessing())
-              {
-                break modifyProcessing;
-              }
-            }
-            catch (DirectoryException de)
-            {
-              if (debugEnabled())
-              {
-                TRACER.debugCaught(DebugLogLevel.ERROR, de);
-              }
-
-              logError(ErrorLogCategory.SYNCHRONIZATION,
-                       ErrorLogSeverity.SEVERE_ERROR,
-                       MSGID_MODIFY_SYNCH_CONFLICT_RESOLUTION_FAILED,
-                       getConnectionID(), getOperationID(),
-                       getExceptionMessage(de));
-
-              setResponseData(de);
-              break modifyProcessing;
-            }
-          }
-        }
-
-
-        // Declare variables used for password policy state processing.
-        boolean passwordChanged = false;
-        boolean currentPasswordProvided = false;
-        boolean isEnabled = true;
-        boolean enabledStateChanged = false;
-        int numPasswords;
-        if (currentEntry.hasAttribute(
-                pwPolicyState.getPolicy().getPasswordAttribute()))
-        {
-          // It may actually have more than one, but we can't tell the
-          // difference if the values are encoded, and its enough for our
-          // purposes just to know that there is at least one.
-          numPasswords = 1;
-        }
-        else
-        {
-          numPasswords = 0;
-        }
-
-
-        // If it's not an internal or synchronization operation, then iterate
-        // through the set of modifications to see if a password is included in
-        // the changes.  If so, then add the appropriate state changes to the
-        // set of modifications.
-        if (! (isInternalOperation() || isSynchronizationOperation()))
-        {
-          for (Modification m : modifications)
-          {
-            if (m.getAttribute().getAttributeType().equals(
-                     pwPolicyState.getPolicy().getPasswordAttribute()))
-            {
-              passwordChanged = true;
-              if (! selfChange)
-              {
-                if (! clientConnection.hasPrivilege(Privilege.PASSWORD_RESET,
-                                                    this))
-                {
-                  int msgID = MSGID_MODIFY_PWRESET_INSUFFICIENT_PRIVILEGES;
-                  appendErrorMessage(getMessage(msgID));
-                  setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-                  break modifyProcessing;
-                }
-              }
-
-              break;
-            }
-          }
-        }
-
-
-        for (Modification m : modifications)
-        {
-          Attribute     a = m.getAttribute();
-          AttributeType t = a.getAttributeType();
-
-
-          // If the attribute type is marked "NO-USER-MODIFICATION" then fail
-          // unless this is an internal operation or is related to
-          // synchronization in some way.
-          if (t.isNoUserModification())
-          {
-            if (! (isInternalOperation() || isSynchronizationOperation() ||
-                   m.isInternal()))
-            {
-              setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-              appendErrorMessage(getMessage(MSGID_MODIFY_ATTR_IS_NO_USER_MOD,
-                                            String.valueOf(entryDN),
-                                            a.getName()));
-              break modifyProcessing;
-            }
-          }
-
-          // If the attribute type is marked "OBSOLETE" and the modification
-          // is setting new values, then fail unless this is an internal
-          // operation or is related to synchronization in some way.
-          if (t.isObsolete())
-          {
-            if (a.hasValue() &&
-                (m.getModificationType() != ModificationType.DELETE))
-            {
-              if (! (isInternalOperation() || isSynchronizationOperation() ||
-                     m.isInternal()))
-              {
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                appendErrorMessage(getMessage(MSGID_MODIFY_ATTR_IS_OBSOLETE,
-                                              String.valueOf(entryDN),
-                                              a.getName()));
-                break modifyProcessing;
-              }
-            }
-          }
-
-
-          // See if the attribute is one which controls the privileges available
-          // for a user.  If it is, then the client must have the
-          // PRIVILEGE_CHANGE privilege.
-          if (t.hasName(OP_ATTR_PRIVILEGE_NAME))
-          {
-            if (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE,
-                                                this))
-            {
-              int msgID = MSGID_MODIFY_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES;
-              appendErrorMessage(getMessage(msgID));
-              setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-              break modifyProcessing;
-            }
-          }
-
-
-          // If the modification is updating the password attribute, then
-          // perform any necessary password policy processing.  This processing
-          // should be skipped for synchronization operations.
-          boolean isPassword
-                  = t.equals(pwPolicyState.getPolicy().getPasswordAttribute());
-          if (isPassword && (!(isSynchronizationOperation())))
-          {
-           // If the attribute contains any options, then reject it.  Passwords
-           // will not be allowed to have options. Skipped for internal
-           // operations.
-           if(!isInternalOperation())
-           {
-            if (a.hasOptions())
-            {
-              setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-              int msgID = MSGID_MODIFY_PASSWORDS_CANNOT_HAVE_OPTIONS;
-              appendErrorMessage(getMessage(msgID));
-              break modifyProcessing;
-            }
-
-
-            // If it's a self change, then see if that's allowed.
-            if (selfChange &&
-                 (! pwPolicyState.getPolicy().allowUserPasswordChanges()))
-            {
-              setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-              int msgID = MSGID_MODIFY_NO_USER_PW_CHANGES;
-              appendErrorMessage(getMessage(msgID));
-              break modifyProcessing;
-            }
-
-
-            // If we require secure password changes, then makes sure it's a
-            // secure communication channel.
-            if (pwPolicyState.getPolicy().requireSecurePasswordChanges() &&
-                (! clientConnection.isSecure()))
-            {
-              setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-              int msgID = MSGID_MODIFY_REQUIRE_SECURE_CHANGES;
-              appendErrorMessage(getMessage(msgID));
-              break modifyProcessing;
-            }
-
-
-            // If it's a self change and it's not been long enough since the
-            // previous change, then reject it.
-            if (selfChange && pwPolicyState.isWithinMinimumAge())
-            {
-              setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-              int msgID = MSGID_MODIFY_WITHIN_MINIMUM_AGE;
-              appendErrorMessage(getMessage(msgID));
-              break modifyProcessing;
-            }
-           }
-
-            // Check to see whether this will adding, deleting, or replacing
-            // password values (increment doesn't make any sense for passwords).
-            // Then perform the appropriate type of processing for that kind of
-            // modification.
-            boolean isAdd = false;
-            LinkedHashSet<AttributeValue> pwValues = a.getValues();
-            LinkedHashSet<AttributeValue> encodedValues =
-                 new LinkedHashSet<AttributeValue>();
-            switch (m.getModificationType())
-            {
-              case ADD:
-              case REPLACE:
-                int passwordsToAdd = pwValues.size();
-
-                if (m.getModificationType() == ModificationType.ADD)
-                {
-                  numPasswords += passwordsToAdd;
-                  isAdd = true;
-                }
-                else
-                {
-                  numPasswords = passwordsToAdd;
-                }
-                // If there were multiple password values provided, then make
-                // sure that's OK.
-
-                if (! isInternalOperation() &&
-                    ! pwPolicyState.getPolicy().allowExpiredPasswordChanges() &&
-                    (passwordsToAdd > 1))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                  int msgID = MSGID_MODIFY_MULTIPLE_VALUES_NOT_ALLOWED;
-                  appendErrorMessage(getMessage(msgID));
-                  break modifyProcessing;
-                }
-
-                // Iterate through the password values and see if any of them
-                // are pre-encoded.  If so, then check to see if we'll allow it.
-                // Otherwise, store the clear-text values for later validation
-                // and update the attribute with the encoded values.
-                for (AttributeValue v : pwValues)
-                {
-                  if (pwPolicyState.passwordIsPreEncoded(v.getValue()))
-                  {
-                    if ((!isInternalOperation()) &&
-                         ! pwPolicyState.getPolicy().allowPreEncodedPasswords())
-                    {
-                      setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                      int msgID = MSGID_MODIFY_NO_PREENCODED_PASSWORDS;
-                      appendErrorMessage(getMessage(msgID));
-                      break modifyProcessing;
-                    }
-                    else
-                    {
-                      encodedValues.add(v);
-                    }
-                  }
-                  else
-                  {
-                    if (isAdd)
-                    {
-                      // Make sure that the password value doesn't already
-                      // exist.
-                      if (pwPolicyState.passwordMatches(v.getValue()))
-                      {
-                        setResultCode(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS);
-
-                        int msgID = MSGID_MODIFY_PASSWORD_EXISTS;
-                        appendErrorMessage(getMessage(msgID));
-                        break modifyProcessing;
-                      }
-                    }
-
-                    if (newPasswords == null)
-                    {
-                      newPasswords = new LinkedList<AttributeValue>();
-                    }
-
-                    newPasswords.add(v);
-
-                    try
-                    {
-                      for (ByteString s :
-                           pwPolicyState.encodePassword(v.getValue()))
-                      {
-                        encodedValues.add(new AttributeValue(
-                                                   a.getAttributeType(), s));
-                      }
-                    }
-                    catch (DirectoryException de)
-                    {
-                      if (debugEnabled())
-                      {
-                        TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                      }
-
-                      setResultCode(de.getResultCode());
-                      appendErrorMessage(de.getErrorMessage());
-                      break modifyProcessing;
-                    }
-                  }
-                }
-
-                a.setValues(encodedValues);
-
-                break;
-
-              case DELETE:
-                // Iterate through the password values and see if any of them
-                // are pre-encoded.  We will never allow pre-encoded passwords
-                // for user password changes, but we will allow them for
-                // administrators.  For each clear-text value, verify that at
-                // least one value in the entry matches and replace the
-                // clear-text value with the appropriate encoded forms.
-                for (AttributeValue v : pwValues)
-                {
-                  if (pwPolicyState.passwordIsPreEncoded(v.getValue()))
-                  {
-                    if ((!isInternalOperation()) && selfChange)
-                    {
-                      setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                      int msgID = MSGID_MODIFY_NO_PREENCODED_PASSWORDS;
-                      appendErrorMessage(getMessage(msgID));
-                      break modifyProcessing;
-                    }
-                    else
-                    {
-                      encodedValues.add(v);
-                    }
-                  }
-                  else
-                  {
-                    List<Attribute> attrList = currentEntry.getAttribute(t);
-                    if ((attrList == null) || (attrList.isEmpty()))
-                    {
-                      setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                      int msgID = MSGID_MODIFY_NO_EXISTING_VALUES;
-                      appendErrorMessage(getMessage(msgID));
-                      break modifyProcessing;
-                    }
-                    boolean found = false;
-                    for (Attribute attr : attrList)
-                    {
-                      for (AttributeValue av : attr.getValues())
-                      {
-                        if (pwPolicyState.getPolicy().usesAuthPasswordSyntax())
-                        {
-                          if (AuthPasswordSyntax.isEncoded(av.getValue()))
-                          {
-                            try
-                            {
-                              StringBuilder[] compoenents =
-                                   AuthPasswordSyntax.decodeAuthPassword(
-                                        av.getStringValue());
-                              PasswordStorageScheme scheme =
-                                   DirectoryServer.
-                                        getAuthPasswordStorageScheme(
-                                             compoenents[0].toString());
-                              if (scheme != null)
-                              {
-                                if (scheme.authPasswordMatches(
-                                     v.getValue(),
-                                     compoenents[1].toString(),
-                                     compoenents[2].toString()))
-                                {
-                                  encodedValues.add(av);
-                                  found = true;
-                                }
-                              }
-                            }
-                            catch (DirectoryException de)
-                            {
-                              if (debugEnabled())
-                              {
-                                TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                              }
-
-                              setResultCode(de.getResultCode());
-
-                              int msgID = MSGID_MODIFY_CANNOT_DECODE_PW;
-                              appendErrorMessage(
-                                   getMessage(msgID, de.getErrorMessage()));
-                              break modifyProcessing;
-                            }
-                          }
-                          else
-                          {
-                            if (av.equals(v))
-                            {
-                              encodedValues.add(v);
-                              found = true;
-                            }
-                          }
-                        }
-                        else
-                        {
-                          if (UserPasswordSyntax.isEncoded(av.getValue()))
-                          {
-                            try
-                            {
-                              String[] compoenents =
-                                   UserPasswordSyntax.decodeUserPassword(
-                                        av.getStringValue());
-                              PasswordStorageScheme scheme =
-                                   DirectoryServer.getPasswordStorageScheme(
-                                        toLowerCase(compoenents[0]));
-                              if (scheme != null)
-                              {
-                                if (scheme.passwordMatches(
-                                     v.getValue(),
-                                     new ASN1OctetString(compoenents[1])))
-                                {
-                                  encodedValues.add(av);
-                                  found = true;
-                                }
-                              }
-                            }
-                            catch (DirectoryException de)
-                            {
-                              if (debugEnabled())
-                              {
-                                TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                              }
-
-                              setResultCode(de.getResultCode());
-
-                              int msgID = MSGID_MODIFY_CANNOT_DECODE_PW;
-                              appendErrorMessage(getMessage(msgID,
-                                                         de.getErrorMessage()));
-                              break modifyProcessing;
-                            }
-                          }
-                          else
-                          {
-                            if (av.equals(v))
-                            {
-                              encodedValues.add(v);
-                              found = true;
-                            }
-                          }
-                        }
-                      }
-                    }
-
-                    if (found)
-                    {
-                      if (currentPasswords == null)
-                      {
-                        currentPasswords = new LinkedList<AttributeValue>();
-                      }
-                      currentPasswords.add(v);
-
-                      numPasswords--;
-                    }
-                    else
-                    {
-                      setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                      int msgID = MSGID_MODIFY_INVALID_PASSWORD;
-                      appendErrorMessage(getMessage(msgID));
-                      break modifyProcessing;
-                    }
-
-                    currentPasswordProvided = true;
-                  }
-                }
-
-                a.setValues(encodedValues);
-
-                break;
-
-              default:
-                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                int msgID = MSGID_MODIFY_INVALID_MOD_TYPE_FOR_PASSWORD;
-                appendErrorMessage(getMessage(msgID,
-                     String.valueOf(m.getModificationType()), a.getName()));
-
-                break modifyProcessing;
-            }
-          }
-          else
-          {
-            // See if it's an attribute used to maintain the account
-            // enabled/disabled state.
-            AttributeType disabledAttr =
-                 DirectoryServer.getAttributeType(OP_ATTR_ACCOUNT_DISABLED,
-                                                  true);
-            if (t.equals(disabledAttr))
-            {
-              enabledStateChanged = true;
-              for (AttributeValue v : a.getValues())
-              {
-                try
-                {
-                  isEnabled = (! BooleanSyntax.decodeBooleanValue(
-                                                    v.getNormalizedValue()));
-                }
-                catch (DirectoryException de)
-                {
-                  setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                  int msgID = MSGID_MODIFY_INVALID_DISABLED_VALUE;
-                  String message =
-                       getMessage(msgID, OP_ATTR_ACCOUNT_DISABLED,
-                                  String.valueOf(de.getErrorMessage()));
-                  appendErrorMessage(message);
-                  break modifyProcessing;
-                }
-              }
-            }
-          }
-
-
-          switch (m.getModificationType())
-          {
-            case ADD:
-              // Make sure that one or more values have been provided for the
-              // attribute.
-              LinkedHashSet<AttributeValue> newValues = a.getValues();
-              if ((newValues == null) || newValues.isEmpty())
-              {
-                setResultCode(ResultCode.PROTOCOL_ERROR);
-                appendErrorMessage(getMessage(MSGID_MODIFY_ADD_NO_VALUES,
-                                              String.valueOf(entryDN),
-                                              a.getName()));
-                break modifyProcessing;
-              }
-
-
-              // Make sure that all the new values are valid according to the
-              // associated syntax.
-              if (DirectoryServer.checkSchema())
-              {
-                AcceptRejectWarn syntaxPolicy =
-                     DirectoryServer.getSyntaxEnforcementPolicy();
-                AttributeSyntax syntax = t.getSyntax();
-
-                if (syntaxPolicy == AcceptRejectWarn.REJECT)
-                {
-                  StringBuilder invalidReason = new StringBuilder();
-
-                  for (AttributeValue v : newValues)
-                  {
-                    if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
-                    {
-                      setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                      int msgID = MSGID_MODIFY_ADD_INVALID_SYNTAX;
-                      appendErrorMessage(getMessage(msgID,
-                                                    String.valueOf(entryDN),
-                                                    a.getName(),
-                                                    v.getStringValue(),
-                                                    invalidReason.toString()));
-
-                      break modifyProcessing;
-                    }
-                  }
-                }
-                else if (syntaxPolicy == AcceptRejectWarn.WARN)
-                {
-                  StringBuilder invalidReason = new StringBuilder();
-
-                  for (AttributeValue v : newValues)
-                  {
-                    if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
-                    {
-                      setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                      int msgID = MSGID_MODIFY_ADD_INVALID_SYNTAX;
-                      logError(ErrorLogCategory.SCHEMA,
-                               ErrorLogSeverity.SEVERE_WARNING, msgID,
-                               String.valueOf(entryDN), a.getName(),
-                               v.getStringValue(), invalidReason.toString());
-
-                      invalidReason = new StringBuilder();
-                    }
-                  }
-                }
-              }
-
-
-              // Add the provided attribute or merge an existing attribute with
-              // the values of the new attribute.  If there are any duplicates,
-              // then fail.
-              LinkedList<AttributeValue> duplicateValues =
-                   new LinkedList<AttributeValue>();
-              if (a.getAttributeType().isObjectClassType())
-              {
-                try
-                {
-                  modifiedEntry.addObjectClasses(newValues);
-                  break;
-                }
-                catch (DirectoryException de)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                  }
-
-                  setResponseData(de);
-                  break modifyProcessing;
-                }
-              }
-              else
-              {
-                modifiedEntry.addAttribute(a, duplicateValues);
-                if (duplicateValues.isEmpty())
-                {
-                  break;
-                }
-                else
-                {
-                  StringBuilder buffer = new StringBuilder();
-                  Iterator<AttributeValue> iterator =
-                       duplicateValues.iterator();
-                  buffer.append(iterator.next().getStringValue());
-                  while (iterator.hasNext())
-                  {
-                    buffer.append(", ");
-                    buffer.append(iterator.next().getStringValue());
-                  }
-
-                  setResultCode(ResultCode.ATTRIBUTE_OR_VALUE_EXISTS);
-
-                  int msgID = MSGID_MODIFY_ADD_DUPLICATE_VALUE;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                a.getName(),
-                                                buffer.toString()));
-
-                  break modifyProcessing;
-                }
-              }
-
-
-            case DELETE:
-              // Remove the specified attribute values or the entire attribute
-              // from the value.  If there are any specified values that were
-              // not present, then fail.  If the RDN attribute value would be
-              // removed, then fail.
-              LinkedList<AttributeValue> missingValues =
-                   new LinkedList<AttributeValue>();
-              boolean attrExists =
-                   modifiedEntry.removeAttribute(a, missingValues);
-
-              if (attrExists)
-              {
-                if (missingValues.isEmpty())
-                {
-                  RDN rdn = modifiedEntry.getDN().getRDN();
-                  if ((rdn != null) && rdn.hasAttributeType(t) &&
-                      (! modifiedEntry.hasValue(t, a.getOptions(),
-                                                rdn.getAttributeValue(t))))
-                  {
-                    setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
-                    int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
-                    appendErrorMessage(getMessage(msgID,
-                                                  String.valueOf(entryDN),
-                                                  a.getName()));
-                    break modifyProcessing;
-                  }
-
-                  break;
-                }
-                else
-                {
-                  StringBuilder buffer = new StringBuilder();
-                  Iterator<AttributeValue> iterator = missingValues.iterator();
-                  buffer.append(iterator.next().getStringValue());
-                  while (iterator.hasNext())
-                  {
-                    buffer.append(", ");
-                    buffer.append(iterator.next().getStringValue());
-                  }
-
-                  setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
-
-                  int msgID = MSGID_MODIFY_DELETE_MISSING_VALUES;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                a.getName(),
-                                                buffer.toString()));
-
-                  break modifyProcessing;
-                }
-              }
-              else
-              {
-                setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
-
-                int msgID = MSGID_MODIFY_DELETE_NO_SUCH_ATTR;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-                break modifyProcessing;
-              }
-
-
-            case REPLACE:
-              // If it is the objectclass attribute, then treat that separately.
-              if (a.getAttributeType().isObjectClassType())
-              {
-                try
-                {
-                  modifiedEntry.setObjectClasses(a.getValues());
-                  break;
-                }
-                catch (DirectoryException de)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                  }
-
-                  setResponseData(de);
-                  break modifyProcessing;
-                }
-              }
-
-
-              // If the provided attribute does not have any values, then we
-              // will simply remove the attribute from the entry (if it exists).
-              if (! a.hasValue())
-              {
-                modifiedEntry.removeAttribute(t, a.getOptions());
-                RDN rdn = modifiedEntry.getDN().getRDN();
-                if ((rdn != null) && rdn.hasAttributeType(t) &&
-                    (! modifiedEntry.hasValue(t, a.getOptions(),
-                                              rdn.getAttributeValue(t))))
-                {
-                  setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
-                  int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                a.getName()));
-                  break modifyProcessing;
-                }
-                break;
-              }
-
-
-              // Make sure that all the new values are valid according to the
-              // associated syntax.
-              newValues = a.getValues();
-              if (DirectoryServer.checkSchema())
-              {
-                AcceptRejectWarn syntaxPolicy =
-                     DirectoryServer.getSyntaxEnforcementPolicy();
-                AttributeSyntax syntax = t.getSyntax();
-
-                if (syntaxPolicy == AcceptRejectWarn.REJECT)
-                {
-                  StringBuilder invalidReason = new StringBuilder();
-
-                  for (AttributeValue v : newValues)
-                  {
-                    if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
-                    {
-                      setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                      int msgID = MSGID_MODIFY_REPLACE_INVALID_SYNTAX;
-                      appendErrorMessage(getMessage(msgID,
-                                                    String.valueOf(entryDN),
-                                                    a.getName(),
-                                                    v.getStringValue(),
-                                                    invalidReason.toString()));
-
-                      break modifyProcessing;
-                    }
-                  }
-                }
-                else if (syntaxPolicy == AcceptRejectWarn.WARN)
-                {
-                  StringBuilder invalidReason = new StringBuilder();
-
-                  for (AttributeValue v : newValues)
-                  {
-                    if (! syntax.valueIsAcceptable(v.getValue(), invalidReason))
-                    {
-                      setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                      int msgID = MSGID_MODIFY_REPLACE_INVALID_SYNTAX;
-                      logError(ErrorLogCategory.SCHEMA,
-                               ErrorLogSeverity.SEVERE_WARNING, msgID,
-                               String.valueOf(entryDN), a.getName(),
-                               v.getStringValue(), invalidReason.toString());
-
-                      invalidReason = new StringBuilder();
-                    }
-                  }
-                }
-              }
-
-
-              // If the provided attribute does not have any options, then we
-              // will simply use it in place of any existing attribute of the
-              // provided type (or add it if it doesn't exist).
-              if (! a.hasOptions())
-              {
-                List<Attribute> attrList = new ArrayList<Attribute>(1);
-                attrList.add(a);
-                modifiedEntry.putAttribute(t, attrList);
-
-                RDN rdn = modifiedEntry.getDN().getRDN();
-                if ((rdn != null) && rdn.hasAttributeType(t) &&
-                    (! modifiedEntry.hasValue(t, a.getOptions(),
-                                              rdn.getAttributeValue(t))))
-                {
-                  setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
-                  int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                a.getName()));
-                  break modifyProcessing;
-                }
-                break;
-              }
-
-
-              // See if there is an existing attribute of the provided type.  If
-              // not, then we'll use the new one.
-              List<Attribute> attrList = modifiedEntry.getAttribute(t);
-              if ((attrList == null) || attrList.isEmpty())
-              {
-                attrList = new ArrayList<Attribute>(1);
-                attrList.add(a);
-                modifiedEntry.putAttribute(t, attrList);
-
-                RDN rdn = modifiedEntry.getDN().getRDN();
-                if ((rdn != null) && rdn.hasAttributeType(t) &&
-                    (! modifiedEntry.hasValue(t, a.getOptions(),
-                                              rdn.getAttributeValue(t))))
-                {
-                  setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
-                  int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                a.getName()));
-                  break modifyProcessing;
-                }
-                break;
-              }
-
-
-              // There must be an existing occurrence of the provided attribute
-              // in the entry.  If there is a version with exactly the set of
-              // options provided, then replace it.  Otherwise, add a new one.
-              boolean found = false;
-              for (int i=0; i < attrList.size(); i++)
-              {
-                if (attrList.get(i).optionsEqual(a.getOptions()))
-                {
-                  attrList.set(i, a);
-                  found = true;
-                  break;
-                }
-              }
-
-              if (! found)
-              {
-                attrList.add(a);
-              }
-
-              RDN rdn = modifiedEntry.getDN().getRDN();
-              if ((rdn != null) && rdn.hasAttributeType(t) &&
-                  (! modifiedEntry.hasValue(t, a.getOptions(),
-                                            rdn.getAttributeValue(t))))
-              {
-                setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-
-                int msgID = MSGID_MODIFY_DELETE_RDN_ATTR;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-                break modifyProcessing;
-              }
-              break;
-
-
-            case INCREMENT:
-              // The specified attribute type must not be an RDN attribute.
-              rdn = modifiedEntry.getDN().getRDN();
-              if ((rdn != null) && rdn.hasAttributeType(t))
-              {
-                setResultCode(ResultCode.NOT_ALLOWED_ON_RDN);
-                appendErrorMessage(getMessage(MSGID_MODIFY_INCREMENT_RDN,
-                                              String.valueOf(entryDN),
-                                              a.getName()));
-              }
-
-
-              // The provided attribute must have a single value, and it must be
-              // an integer.
-              LinkedHashSet<AttributeValue> values = a.getValues();
-              if ((values == null) || values.isEmpty())
-              {
-                setResultCode(ResultCode.PROTOCOL_ERROR);
-
-                int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_VALUE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-
-                break modifyProcessing;
-              }
-              else if (values.size() > 1)
-              {
-                setResultCode(ResultCode.PROTOCOL_ERROR);
-
-                int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_SINGLE_VALUE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-                break modifyProcessing;
-              }
-
-              AttributeValue v = values.iterator().next();
-
-              long incrementValue;
-              try
-              {
-                incrementValue = Long.parseLong(v.getNormalizedStringValue());
-              }
-              catch (Exception e)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
-                }
-
-                setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                int msgID = MSGID_MODIFY_INCREMENT_PROVIDED_VALUE_NOT_INTEGER;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName(), v.getStringValue()));
-
-                break modifyProcessing;
-              }
-
-
-              // Get the corresponding attribute from the entry and make sure
-              // that it has a single integer value.
-              attrList = modifiedEntry.getAttribute(t, a.getOptions());
-              if ((attrList == null) || attrList.isEmpty())
-              {
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-
-                break modifyProcessing;
-              }
-
-              boolean updated = false;
-              for (Attribute attr : attrList)
-              {
-                LinkedHashSet<AttributeValue> valueList = attr.getValues();
-                if ((valueList == null) || valueList.isEmpty())
-                {
-                  continue;
-                }
-
-                LinkedHashSet<AttributeValue> newValueList =
-                     new LinkedHashSet<AttributeValue>(valueList.size());
-                for (AttributeValue existingValue : valueList)
-                {
-                  long newIntValue;
-                  try
-                  {
-                    long existingIntValue =
-                         Long.parseLong(existingValue.getStringValue());
-                    newIntValue = existingIntValue + incrementValue;
-                  }
-                  catch (Exception e)
-                  {
-                    if (debugEnabled())
-                    {
-                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
-                    }
-
-                    setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-
-                    int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_INTEGER_VALUE;
-                    appendErrorMessage(getMessage(msgID,
-                                            String.valueOf(entryDN),
-                                            a.getName(),
-                                            existingValue.getStringValue()));
-                    break modifyProcessing;
-                  }
-
-                  ByteString newValue =
-                       new ASN1OctetString(String.valueOf(newIntValue));
-                  newValueList.add(new AttributeValue(t, newValue));
-                }
-
-                attr.setValues(newValueList);
-                updated = true;
-              }
-
-              if (! updated)
-              {
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                int msgID = MSGID_MODIFY_INCREMENT_REQUIRES_EXISTING_VALUE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              a.getName()));
-
-                break modifyProcessing;
-              }
-
-              break;
-
-            default:
-          }
-        }
-
-
-        // If there was a password change, then perform any additional checks
-        // that may be necessary.
-        if (passwordChanged)
-        {
-          // If it was a self change, then see if the current password was
-          // provided and handle accordingly.
-          if (selfChange &&
-              pwPolicyState.getPolicy().requireCurrentPassword() &&
-              (! currentPasswordProvided))
-          {
-            setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-            int msgID = MSGID_MODIFY_PW_CHANGE_REQUIRES_CURRENT_PW;
-            appendErrorMessage(getMessage(msgID));
-            break modifyProcessing;
-          }
-
-
-          // If this change would result in multiple password values, then see
-          // if that's OK.
-          if ((numPasswords > 1) &&
-              (! pwPolicyState.getPolicy().allowMultiplePasswordValues()))
-          {
-            setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-            int msgID = MSGID_MODIFY_MULTIPLE_PASSWORDS_NOT_ALLOWED;
-            appendErrorMessage(getMessage(msgID));
-            break modifyProcessing;
-          }
-
-
-          // If any of the password values should be validated, then do so now.
-          if (selfChange ||
-               (! pwPolicyState.getPolicy().skipValidationForAdministrators()))
-          {
-            if (newPasswords != null)
-            {
-              HashSet<ByteString> clearPasswords = new HashSet<ByteString>();
-              clearPasswords.addAll(pwPolicyState.getClearPasswords());
-
-              if (currentPasswords != null)
-              {
-                if (clearPasswords.isEmpty())
-                {
-                  for (AttributeValue v : currentPasswords)
-                  {
-                    clearPasswords.add(v.getValue());
-                  }
-                }
-                else
-                {
-                  // NOTE:  We can't rely on the fact that Set doesn't allow
-                  // duplicates because technically it's possible that the
-                  // values aren't duplicates if they are ASN.1 elements with
-                  // different types (like 0x04 for a standard universal octet
-                  // string type versus 0x80 for a simple password in a bind
-                  // operation).  So we have to manually check for duplicates.
-                  for (AttributeValue v : currentPasswords)
-                  {
-                    ByteString pw = v.getValue();
-
-                    boolean found = false;
-                    for (ByteString s : clearPasswords)
-                    {
-                      if (Arrays.equals(s.value(), pw.value()))
-                      {
-                        found = true;
-                        break;
-                      }
-                    }
-
-                    if (! found)
-                    {
-                      clearPasswords.add(pw);
-                    }
-                  }
-                }
-              }
-
-              for (AttributeValue v : newPasswords)
-              {
-                StringBuilder invalidReason = new StringBuilder();
-                if (! pwPolicyState.passwordIsAcceptable(this, modifiedEntry,
-                                                         v.getValue(),
-                                                         clearPasswords,
-                                                         invalidReason))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-                  int msgID = MSGID_MODIFY_PW_VALIDATION_FAILED;
-                  appendErrorMessage(getMessage(msgID,
-                                                invalidReason.toString()));
-                  break modifyProcessing;
-                }
-              }
-            }
-          }
-        }
-
-
-        // Check to see if the client has permission to perform the
-        // modify.
-        // The access control check is not made any earlier because the
-        // handler needs access to the modified entry.
-
-        // FIXME: for now assume that this will check all permission
-        // pertinent to the operation. This includes proxy authorization
-        // and any other controls specified.
-
-        // FIXME: earlier checks to see if the entry already exists may
-        // have already exposed sensitive information to the client.
-        if (!AccessControlConfigManager.getInstance()
-             .getAccessControlHandler().isAllowed(this)) {
-          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-          int msgID = MSGID_MODIFY_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-          appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-          skipPostOperation = true;
-          break modifyProcessing;
-        }
-
-        boolean wasLocked = false;
-        if (passwordChanged)
-        {
-          // See if the account was locked for any reason.
-          wasLocked = pwPolicyState.lockedDueToIdleInterval() ||
-               pwPolicyState.lockedDueToMaximumResetAge() ||
-               pwPolicyState.lockedDueToFailures();
-
-          // Update the password policy state attributes in the user's entry.
-          // If the modification fails, then these changes won't be applied.
-          pwPolicyState.setPasswordChangedTime();
-          pwPolicyState.clearFailureLockout();
-          pwPolicyState.clearGraceLoginTimes();
-          pwPolicyState.clearWarnedTime();
-
-          if(pwPolicyState.getPolicy().forceChangeOnAdd()
-             || pwPolicyState.getPolicy().forceChangeOnReset())
-          {
-            if (selfChange)
-            {
-              pwPolicyState.setMustChangePassword(false);
-            }
-            else
-            {
-              pwPolicyState.setMustChangePassword(
-                   pwPolicyState.getPolicy().forceChangeOnReset());
-            }
-          }
-
-          if (pwPolicyState.getPolicy().getRequireChangeByTime() > 0)
-          {
-            pwPolicyState.setRequiredChangeTime();
-          }
-          modifications.addAll(pwPolicyState.getModifications());
-          //Apply pwd Policy modifications to modified entry.
-          try {
-            modifiedEntry.applyModifications(pwPolicyState.getModifications());
-          } catch (DirectoryException e) {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
-
-            setResponseData(e);
-            break modifyProcessing;
-          }
-        }
-        else if ((! isInternalOperation()) &&
-                 pwPolicyState.mustChangePassword())
-        {
-          // The user will not be allowed to do anything else before
-          // the password gets changed.
-          setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-
-          int msgID = MSGID_MODIFY_MUST_CHANGE_PASSWORD;
-          appendErrorMessage(getMessage(msgID));
-          break modifyProcessing;
-        }
-
-        // Make sure that the new entry is valid per the server schema.
-        if (DirectoryServer.checkSchema())
-        {
-          StringBuilder invalidReason = new StringBuilder();
-          if (! modifiedEntry.conformsToSchema(null, false, false, false,
-                                               invalidReason))
-          {
-            setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
-            appendErrorMessage(getMessage(MSGID_MODIFY_VIOLATES_SCHEMA,
-                                          String.valueOf(entryDN),
-                                          invalidReason.toString()));
-            break modifyProcessing;
-          }
-        }
-
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logModifyResponse(this);
-          pluginConfigManager.invokePostResponseModifyPlugins(this);
-          return;
-        }
-
-        // If the operation is not a synchronization operation,
-        // Invoke the pre-operation modify plugins.
-        if (!isSynchronizationOperation())
-        {
-          PreOperationPluginResult preOpResult =
-            pluginConfigManager.invokePreOperationModifyPlugins(this);
-          if (preOpResult.connectionTerminated())
-          {
-            // There's no point in continuing with anything.  Log the result
-            // and return.
-            setResultCode(ResultCode.CANCELED);
-
-            int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
-            appendErrorMessage(getMessage(msgID));
-
-            processingStopTime = System.currentTimeMillis();
-
-            logModifyResponse(this);
-            pluginConfigManager.invokePostResponseModifyPlugins(this);
-            return;
-          }
-          else if (preOpResult.sendResponseImmediately())
-          {
-            skipPostOperation = true;
-            break modifyProcessing;
-          }
-          else if (preOpResult.skipCoreProcessing())
-          {
-            skipPostOperation = false;
-            break modifyProcessing;
-          }
-        }
-
-
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logModifyResponse(this);
-          pluginConfigManager.invokePostResponseModifyPlugins(this);
-          return;
-        }
-
-
-        // Actually perform the modify operation.  This should also include
-        // taking care of any synchronization that might be needed.
-        Backend backend = DirectoryServer.getBackend(entryDN);
-        if (backend == null)
-        {
-          setResultCode(ResultCode.NO_SUCH_OBJECT);
-          appendErrorMessage(getMessage(MSGID_MODIFY_NO_BACKEND_FOR_ENTRY,
-                                        String.valueOf(entryDN)));
-          break modifyProcessing;
-        }
-
-        try
-        {
-          // If it is not a private backend, then check to see if the server or
-          // backend is operating in read-only mode.
-          if (! backend.isPrivateBackend())
-          {
-            switch (DirectoryServer.getWritabilityMode())
-            {
-              case DISABLED:
-                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                appendErrorMessage(getMessage(MSGID_MODIFY_SERVER_READONLY,
-                                              String.valueOf(entryDN)));
-                break modifyProcessing;
-
-              case INTERNAL_ONLY:
-                if (! (isInternalOperation() || isSynchronizationOperation()))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                  appendErrorMessage(getMessage(MSGID_MODIFY_SERVER_READONLY,
-                                                String.valueOf(entryDN)));
-                  break modifyProcessing;
-                }
-            }
-
-            switch (backend.getWritabilityMode())
-            {
-              case DISABLED:
-                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                appendErrorMessage(getMessage(MSGID_MODIFY_BACKEND_READONLY,
-                                              String.valueOf(entryDN)));
-                break modifyProcessing;
-
-              case INTERNAL_ONLY:
-                if (! (isInternalOperation() || isSynchronizationOperation()))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                  appendErrorMessage(getMessage(MSGID_MODIFY_BACKEND_READONLY,
-                                                String.valueOf(entryDN)));
-                  break modifyProcessing;
-                }
-            }
-          }
-
-
-          if (noOp)
-          {
-            appendErrorMessage(getMessage(MSGID_MODIFY_NOOP));
-
-            // FIXME -- We must set a result code other than SUCCESS.
-          }
-          else
-          {
-            for (SynchronizationProvider provider :
-                 DirectoryServer.getSynchronizationProviders())
-            {
-              try
-              {
-                SynchronizationProviderResult result =
-                     provider.doPreOperation(this);
-                if (! result.continueOperationProcessing())
-                {
-                  break modifyProcessing;
-                }
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                logError(ErrorLogCategory.SYNCHRONIZATION,
-                         ErrorLogSeverity.SEVERE_ERROR,
-                         MSGID_MODIFY_SYNCH_PREOP_FAILED, getConnectionID(),
-                         getOperationID(), getExceptionMessage(de));
-
-                setResponseData(de);
-                break modifyProcessing;
-              }
-            }
-
-            backend.replaceEntry(modifiedEntry, this);
-
-
-            // If the modification was successful, then see if there's any other
-            // work that we need to do here before handing off to postop
-            // plugins.
-            if (passwordChanged)
-            {
-              if (selfChange)
-              {
-                AuthenticationInfo authInfo =
-                     clientConnection.getAuthenticationInfo();
-                if (authInfo.getAuthenticationDN().equals(entryDN))
-                {
-                  clientConnection.setMustChangePassword(false);
-                }
-
-                int    msgID   = MSGID_MODIFY_PASSWORD_CHANGED;
-                String message = getMessage(msgID);
-                pwPolicyState.generateAccountStatusNotification(
-                     AccountStatusNotificationType.PASSWORD_CHANGED, entryDN,
-                     msgID, message);
-              }
-              else
-              {
-                int    msgID   = MSGID_MODIFY_PASSWORD_RESET;
-                String message = getMessage(msgID);
-                pwPolicyState.generateAccountStatusNotification(
-                     AccountStatusNotificationType.PASSWORD_RESET, entryDN,
-                     msgID, message);
-              }
-            }
-
-            if (enabledStateChanged)
-            {
-              if (isEnabled)
-              {
-                int    msgID   = MSGID_MODIFY_ACCOUNT_ENABLED;
-                String message = getMessage(msgID);
-                pwPolicyState.generateAccountStatusNotification(
-                     AccountStatusNotificationType.ACCOUNT_ENABLED, entryDN,
-                     msgID, message);
-              }
-              else
-              {
-                int    msgID   = MSGID_MODIFY_ACCOUNT_DISABLED;
-                String message = getMessage(msgID);
-                pwPolicyState.generateAccountStatusNotification(
-                     AccountStatusNotificationType.ACCOUNT_DISABLED, entryDN,
-                     msgID, message);
-              }
-            }
-
-            if (wasLocked)
-            {
-              int    msgID   = MSGID_MODIFY_ACCOUNT_UNLOCKED;
-              String message = getMessage(msgID);
-              pwPolicyState.generateAccountStatusNotification(
-                   AccountStatusNotificationType.ACCOUNT_UNLOCKED, entryDN,
-                   msgID, message);
-            }
-          }
-
-          if (preReadRequest != null)
-          {
-            Entry entry = currentEntry.duplicate(true);
-
-            if (! preReadRequest.allowsAttribute(
-                       DirectoryServer.getObjectClassAttributeType()))
-            {
-              entry.removeAttribute(
-                   DirectoryServer.getObjectClassAttributeType());
-            }
-
-            if (! preReadRequest.returnAllUserAttributes())
-            {
-              Iterator<AttributeType> iterator =
-                   entry.getUserAttributes().keySet().iterator();
-              while (iterator.hasNext())
-              {
-                AttributeType attrType = iterator.next();
-                if (! preReadRequest.allowsAttribute(attrType))
-                {
-                  iterator.remove();
-                }
-              }
-            }
-
-            if (! preReadRequest.returnAllOperationalAttributes())
-            {
-              Iterator<AttributeType> iterator =
-                   entry.getOperationalAttributes().keySet().iterator();
-              while (iterator.hasNext())
-              {
-                AttributeType attrType = iterator.next();
-                if (! preReadRequest.allowsAttribute(attrType))
-                {
-                  iterator.remove();
-                }
-              }
-            }
-
-            // FIXME -- Check access controls on the entry to see if it should
-            //          be returned or if any attributes need to be stripped
-            //          out..
-            SearchResultEntry searchEntry = new SearchResultEntry(entry);
-            LDAPPreReadResponseControl responseControl =
-                 new LDAPPreReadResponseControl(preReadRequest.getOID(),
-                                                preReadRequest.isCritical(),
-                                                searchEntry);
-
-            responseControls.add(responseControl);
-          }
-
-          if (postReadRequest != null)
-          {
-            Entry entry = modifiedEntry.duplicate(true);
-
-            if (! postReadRequest.allowsAttribute(
-                       DirectoryServer.getObjectClassAttributeType()))
-            {
-              entry.removeAttribute(
-                   DirectoryServer.getObjectClassAttributeType());
-            }
-
-            if (! postReadRequest.returnAllUserAttributes())
-            {
-              Iterator<AttributeType> iterator =
-                   entry.getUserAttributes().keySet().iterator();
-              while (iterator.hasNext())
-              {
-                AttributeType attrType = iterator.next();
-                if (! postReadRequest.allowsAttribute(attrType))
-                {
-                  iterator.remove();
-                }
-              }
-            }
-
-            if (! postReadRequest.returnAllOperationalAttributes())
-            {
-              Iterator<AttributeType> iterator =
-                   entry.getOperationalAttributes().keySet().iterator();
-              while (iterator.hasNext())
-              {
-                AttributeType attrType = iterator.next();
-                if (! postReadRequest.allowsAttribute(attrType))
-                {
-                  iterator.remove();
-                }
-              }
-            }
-
-            // FIXME -- Check access controls on the entry to see if it should
-            //          be returned or if any attributes need to be stripped
-            //          out..
-            SearchResultEntry searchEntry = new SearchResultEntry(entry);
-            LDAPPostReadResponseControl responseControl =
-                 new LDAPPostReadResponseControl(postReadRequest.getOID(),
-                                                 postReadRequest.isCritical(),
-                                                 searchEntry);
-
-            responseControls.add(responseControl);
-          }
-
-          setResultCode(ResultCode.SUCCESS);
-        }
-        catch (DirectoryException de)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, de);
-          }
-
-          setResultCode(de.getResultCode());
-          appendErrorMessage(de.getErrorMessage());
-          setMatchedDN(de.getMatchedDN());
-          setReferralURLs(de.getReferralURLs());
-
-          break modifyProcessing;
-        }
-        catch (CancelledOperationException coe)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, coe);
-          }
-
-          CancelResult cancelResult = coe.getCancelResult();
-
-          setCancelResult(cancelResult);
-          setResultCode(cancelResult.getResultCode());
-
-          String message = coe.getMessage();
-          if ((message != null) && (message.length() > 0))
-          {
-            appendErrorMessage(message);
-          }
-
-          break modifyProcessing;
-        }
-      }
-      finally
-      {
-        LockManager.unlock(entryDN, entryLock);
-
-        for (SynchronizationProvider provider :
-             DirectoryServer.getSynchronizationProviders())
-        {
-          try
-          {
-            provider.doPostOperation(this);
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            logError(ErrorLogCategory.SYNCHRONIZATION,
-                     ErrorLogSeverity.SEVERE_ERROR,
-                     MSGID_MODIFY_SYNCH_POSTOP_FAILED, getConnectionID(),
-                     getOperationID(), getExceptionMessage(de));
-
-            setResponseData(de);
-            break;
-          }
-        }
-      }
-    }
-
-
-    // Indicate that it is now too late to attempt to cancel the operation.
-    setCancelResult(CancelResult.TOO_LATE);
-
-
-    // Invoke the post-operation modify plugins.
-    if (! skipPostOperation)
-    {
-      // FIXME -- Should this also be done while holding the locks?
-      PostOperationPluginResult postOpResult =
-           pluginConfigManager.invokePostOperationModifyPlugins(this);
-      if (postOpResult.connectionTerminated())
-      {
-        // There's no point in continuing with anything.  Log the result and
-        // return.
-        setResultCode(ResultCode.CANCELED);
-
-        int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
-        appendErrorMessage(getMessage(msgID));
-
-        processingStopTime = System.currentTimeMillis();
-
-        logModifyResponse(this);
-        pluginConfigManager.invokePostResponseModifyPlugins(this);
-        return;
-      }
-    }
-
-
-    // Notify any change notification listeners that might be registered with
-    // the server.
-    if (getResultCode() == ResultCode.SUCCESS)
-    {
-      for (ChangeNotificationListener changeListener :
-           DirectoryServer.getChangeNotificationListeners())
-      {
-        try
-        {
-          changeListener.handleModifyOperation(this, currentEntry,
-                                               modifiedEntry);
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          int    msgID   = MSGID_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER;
-          String message = getMessage(msgID, getExceptionMessage(e));
-          logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
-                   message, msgID);
-        }
-      }
-    }
-
-
-    // Stop the processing timer.
-    processingStopTime = System.currentTimeMillis();
-
-
-    // Send the modify response to the client.
-    clientConnection.sendResponse(this);
-
-
-    // Log the modify response.
-    logModifyResponse(this);
-
-
-    // Notify any persistent searches that might be registered with the server.
-    if (getResultCode() == ResultCode.SUCCESS)
-    {
-      for (PersistentSearch persistentSearch :
-           DirectoryServer.getPersistentSearches())
-      {
-        try
-        {
-          persistentSearch.processModify(this, currentEntry, modifiedEntry);
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          int    msgID   = MSGID_MODIFY_ERROR_NOTIFYING_PERSISTENT_SEARCH;
-          String message = getMessage(msgID, String.valueOf(persistentSearch),
-                                      getExceptionMessage(e));
-          logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
-                   message, msgID);
-
-          DirectoryServer.deregisterPersistentSearch(persistentSearch);
-        }
-      }
-    }
-
-
-    // Invoke the post-response modify plugins.
-    pluginConfigManager.invokePostResponseModifyPlugins(this);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final CancelResult cancel(CancelRequest cancelRequest)
-  {
-    this.cancelRequest = cancelRequest;
-
-    CancelResult cancelResult = getCancelResult();
-    long stopWaitingTime = System.currentTimeMillis() + 5000;
-    while ((cancelResult == null) &&
-           (System.currentTimeMillis() < stopWaitingTime))
-    {
-      try
-      {
-        Thread.sleep(50);
-      }
-      catch (Exception e)
-      {
-        if (debugEnabled())
-        {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-      }
-
-      cancelResult = getCancelResult();
-    }
-
-    if (cancelResult == null)
-    {
-      // This can happen in some rare cases (e.g., if a client disconnects and
-      // there is still a lot of data to send to that client), and in this case
-      // we'll prevent the cancel thread from blocking for a long period of
-      // time.
-      cancelResult = CancelResult.CANNOT_CANCEL;
-    }
-
-    return cancelResult;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final CancelRequest getCancelRequest()
-  {
-    return cancelRequest;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  protected boolean setCancelRequest(CancelRequest cancelRequest)
-  {
-    this.cancelRequest = cancelRequest;
-    return true;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override()
-  public final void toString(StringBuilder buffer)
-  {
-    buffer.append("ModifyOperation(connID=");
-    buffer.append(clientConnection.getConnectionID());
-    buffer.append(", opID=");
-    buffer.append(operationID);
-    buffer.append(", dn=");
-    buffer.append(rawEntryDN);
-    buffer.append(")");
-  }
-}
-
+}
\ No newline at end of file

--
Gitblit v1.10.0