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/AddOperation.java | 2516 +----------------------------------------------------------
 1 files changed, 57 insertions(+), 2,459 deletions(-)

diff --git a/opends/src/server/org/opends/server/core/AddOperation.java b/opends/src/server/org/opends/server/core/AddOperation.java
index 8b265d1..a81b672 100644
--- a/opends/src/server/org/opends/server/core/AddOperation.java
+++ b/opends/src/server/org/opends/server/core/AddOperation.java
@@ -26,248 +26,23 @@
  */
 package org.opends.server.core;
 
-
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-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.PasswordValidator;
-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.LDAPPostReadRequestControl;
-import org.opends.server.controls.LDAPPostReadResponseControl;
-import org.opends.server.controls.ProxiedAuthV1Control;
-import org.opends.server.controls.ProxiedAuthV2Control;
-import org.opends.server.schema.AuthPasswordSyntax;
-import org.opends.server.schema.BooleanSyntax;
-import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.protocols.asn1.ASN1OctetString;
-import org.opends.server.protocols.ldap.LDAPAttribute;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
 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.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.ObjectClass;
 import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.Privilege;
 import org.opends.server.types.RawAttribute;
-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.PostOperationAddOperation;
-import org.opends.server.types.operation.PostResponseAddOperation;
-import org.opends.server.types.operation.PreOperationAddOperation;
-import org.opends.server.types.operation.PreParseAddOperation;
-import org.opends.server.util.TimeThread;
-
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.core.CoreConstants.*;
-import static org.opends.server.loggers.AccessLogger.*;
-import org.opends.server.types.DebugLogLevel;
-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.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
-
-
 
 /**
- * This class defines an operation that may be used to add a new entry to the
- * Directory Server.
+ * This interface defines an operation that may be used to add a new entry to
+ * the Directory Server.
  */
-public class AddOperation
-       extends Operation
-       implements PreParseAddOperation, PreOperationAddOperation,
-                  PostOperationAddOperation, PostResponseAddOperation
+public interface AddOperation extends Operation
 {
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // The set of response controls to send to the client.
-  private ArrayList<Control> responseControls;
-
-  // The raw, unprocessed entry DN as provided in the request.  This may or may
-  // not be a valid DN.
-  private ByteString rawEntryDN;
-
-  // The cancel request that has been issued for this add operation.
-  private CancelRequest cancelRequest;
-
-  // The processed DN of the entry to add.
-  private DN entryDN;
-
-  // The proxied authorization target DN for this operation.
-  private DN proxiedAuthorizationDN;
-
-  // The entry being added to the server.
-  private Entry entry;
-
-  // The set of attributes (including the objectclass attribute) in a raw,
-  // unprocessed form as provided in the request.  One or more of these
-  // attributes may be invalid.
-  private List<RawAttribute> rawAttributes;
-
-  // The set of operational attributes for the entry to add.
-  private Map<AttributeType,List<Attribute>> operationalAttributes;
-
-  // The set of user attributes for the entry to add.
-  private Map<AttributeType,List<Attribute>> userAttributes;
-
-  // The set of objectclasses for the entry to add.
-  private Map<ObjectClass,String> objectClasses;
-
-  // 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 add 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 DN of the entry to add from the client
-   *                           request.  This may or may not be a valid DN.
-   * @param  rawAttributes     The raw set of attributes from the client
-   *                           request (including the objectclass attribute).
-   *                           This may contain invalid attributes.
-   */
-  public AddOperation(ClientConnection clientConnection, long operationID,
-                      int messageID, List<Control> requestControls,
-                      ByteString rawEntryDN, List<RawAttribute> rawAttributes)
-  {
-    super(clientConnection, operationID, messageID, requestControls);
-
-
-    this.rawEntryDN    = rawEntryDN;
-    this.rawAttributes = rawAttributes;
-
-    responseControls       = new ArrayList<Control>();
-    cancelRequest          = null;
-    entry                  = null;
-    entryDN                = null;
-    userAttributes         = null;
-    operationalAttributes  = null;
-    objectClasses          = null;
-    proxiedAuthorizationDN = null;
-    changeNumber           = -1;
-  }
-
-
-
-  /**
-   * Creates a new add 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 DN for the entry.
-   * @param  objectClasses          The set of objectclasses for the entry.
-   * @param  userAttributes         The set of user attributes for the entry.
-   * @param  operationalAttributes  The set of operational attributes for the
-   *                                entry.
-   */
-  public AddOperation(ClientConnection clientConnection, long operationID,
-                      int messageID, List<Control> requestControls,
-                      DN entryDN, Map<ObjectClass,String> objectClasses,
-                      Map<AttributeType,List<Attribute>> userAttributes,
-                      Map<AttributeType,List<Attribute>> operationalAttributes)
-  {
-    super(clientConnection, operationID, messageID, requestControls);
-
-
-    this.entryDN               = entryDN;
-    this.objectClasses         = objectClasses;
-    this.userAttributes        = userAttributes;
-    this.operationalAttributes = operationalAttributes;
-
-    entry = null;
-
-    rawEntryDN = new ASN1OctetString(entryDN.toString());
-
-    rawAttributes = new ArrayList<RawAttribute>();
-
-    ArrayList<ASN1OctetString> ocValues = new ArrayList<ASN1OctetString>();
-    for (String s : objectClasses.values())
-    {
-      ocValues.add(new ASN1OctetString(s));
-    }
-
-    LDAPAttribute ocAttr = new LDAPAttribute(ATTR_OBJECTCLASS, ocValues);
-    rawAttributes.add(ocAttr);
-
-    for (List<Attribute> attrList : userAttributes.values())
-    {
-      for (Attribute a : attrList)
-      {
-        rawAttributes.add(new LDAPAttribute(a));
-      }
-    }
-
-    for (List<Attribute> attrList : operationalAttributes.values())
-    {
-      for (Attribute a : attrList)
-      {
-        rawAttributes.add(new LDAPAttribute(a));
-      }
-    }
-
-    responseControls       = new ArrayList<Control>();
-    proxiedAuthorizationDN = null;
-    cancelRequest          = null;
-    changeNumber           = -1;
-  }
-
-
 
   /**
    * Retrieves the DN of the entry to add in a raw, unparsed form as it was
@@ -276,12 +51,7 @@
    *
    * @return  The DN of the entry in a raw, unparsed form.
    */
-  public final ByteString getRawEntryDN()
-  {
-    return rawEntryDN;
-  }
-
-
+  public abstract ByteString getRawEntryDN();
 
   /**
    * Specifies the raw entry DN for the entry to add.  This should only be
@@ -292,14 +62,7 @@
    *
    * @param  rawEntryDN  The raw entry DN for the entry to add.
    */
-  public final void setRawEntryDN(ByteString rawEntryDN)
-  {
-    this.rawEntryDN = rawEntryDN;
-
-    entryDN = null;
-  }
-
-
+  public abstract void setRawEntryDN(ByteString rawEntryDN);
 
   /**
    * Retrieves the DN of the entry to add.  This method should not be called
@@ -309,12 +72,7 @@
    * @return  The DN of the entry to add, or <CODE>null</CODE> if it has not yet
    *          been parsed from the raw DN.
    */
-  public final DN getEntryDN()
-  {
-    return entryDN;
-  }
-
-
+  public abstract DN getEntryDN();
 
   /**
    * Retrieves the set of attributes in their raw, unparsed form as read from
@@ -325,12 +83,7 @@
    * @return  The set of attributes in their raw, unparsed form as read from the
    *          client request.
    */
-  public final List<RawAttribute> getRawAttributes()
-  {
-    return rawAttributes;
-  }
-
-
+  public abstract List<RawAttribute> getRawAttributes();
 
   /**
    * Adds the provided attribute to the set of raw attributes for this add
@@ -339,16 +92,7 @@
    * @param  rawAttribute  The attribute to add to the set of raw attributes for
    *                       this add operation.
    */
-  public final void addRawAttribute(RawAttribute rawAttribute)
-  {
-    rawAttributes.add(rawAttribute);
-
-    objectClasses         = null;
-    userAttributes        = null;
-    operationalAttributes = null;
-  }
-
-
+  public abstract void addRawAttribute(RawAttribute rawAttribute);
 
   /**
    * Replaces the set of raw attributes for this add operation.  This should
@@ -356,65 +100,7 @@
    *
    * @param  rawAttributes  The set of raw attributes for this add operation.
    */
-  public final void setRawAttributes(List<RawAttribute> rawAttributes)
-  {
-    this.rawAttributes = rawAttributes;
-
-    objectClasses         = null;
-    userAttributes        = null;
-    operationalAttributes = null;
-  }
-
-
-
-  /**
-   * Retrieves the set of processed objectclasses for the entry to add.  This
-   * should not be called by pre-parse plugins because this information will not
-   * yet be available.  The contents of the returned map may not be altered by
-   * the caller.
-   *
-   * @return  The set of processed objectclasses for the entry to add, or
-   *          <CODE>null</CODE> if that information is not yet available.
-   */
-  public final Map<ObjectClass,String> getObjectClasses()
-  {
-    return objectClasses;
-  }
-
-
-
-  /**
-   * Adds the provided objectclass to the entry to add.  This should only be
-   * called from pre-operation plugins.  Note that pre-operation plugin
-   * processing is invoked after access control and schema validation, so
-   * plugins should be careful to only make changes that will not violate either
-   * schema or access control rules.
-   *
-   * @param  objectClass  The objectclass to add to the entry.
-   * @param  name         The name to use for the objectclass.
-   */
-  public final void addObjectClass(ObjectClass objectClass, String name)
-  {
-    objectClasses.put(objectClass, name);
-  }
-
-
-
-  /**
-   * Removes the provided objectclass from the entry to add.  This should only
-   * be called from pre-operation plugins.  Note that pre-operation plugin
-   * processing is invoked after access control and schema validation, so
-   * plugins should be careful to only make changes that will not violate either
-   * schema or access control rules.
-   *
-   * @param  objectClass  The objectclass to remove from the entry.
-   */
-  public final void removeObjectClass(ObjectClass objectClass)
-  {
-    objectClasses.remove(objectClass);
-  }
-
-
+  public abstract void setRawAttributes(List<RawAttribute> rawAttributes);
 
   /**
    * Retrieves the set of processed user attributes for the entry to add.  This
@@ -425,28 +111,7 @@
    * @return  The set of processed user attributes for the entry to add, or
    *          <CODE>null</CODE> if that information is not yet available.
    */
-  public final Map<AttributeType,List<Attribute>> getUserAttributes()
-  {
-    return userAttributes;
-  }
-
-
-
-  /**
-   * Retrieves the set of processed operational attributes for the entry to add.
-   * This should not be called by pre-parse plugins because this information
-   * will not yet be available.  The contents of the returned map may be altered
-   * by the caller.
-   *
-   * @return  The set of processed operational attributes for the entry to add,
-   *          or <CODE>null</CODE> if that information is not yet available.
-   */
-  public final Map<AttributeType,List<Attribute>> getOperationalAttributes()
-  {
-    return operationalAttributes;
-  }
-
-
+  public abstract Map<AttributeType, List<Attribute>> getUserAttributes();
 
   /**
    * Sets the specified attribute in the entry to add, overwriting any existing
@@ -459,34 +124,8 @@
    * @param  attributeType  The attribute type for the attribute.
    * @param  attributeList  The attribute list for the provided attribute type.
    */
-  public final void setAttribute(AttributeType attributeType,
-                                 List<Attribute> attributeList)
-  {
-    if (attributeType.isOperational())
-    {
-      if ((attributeList == null) || (attributeList.isEmpty()))
-      {
-        operationalAttributes.remove(attributeType);
-      }
-      else
-      {
-        operationalAttributes.put(attributeType, attributeList);
-      }
-    }
-    else
-    {
-      if ((attributeList == null) || (attributeList.isEmpty()))
-      {
-        userAttributes.remove(attributeType);
-      }
-      else
-      {
-        userAttributes.put(attributeType, attributeList);
-      }
-    }
-  }
-
-
+  public abstract void setAttribute(AttributeType attributeType,
+      List<Attribute> attributeList);
 
   /**
    * Removes the specified attribute from the entry to add. This should only be
@@ -497,67 +136,7 @@
    *
    * @param  attributeType  The attribute tyep for the attribute to remove.
    */
-  public final void removeAttribute(AttributeType attributeType)
-  {
-    if (attributeType.isOperational())
-    {
-      operationalAttributes.remove(attributeType);
-    }
-    else
-    {
-      userAttributes.remove(attributeType);
-    }
-  }
-
-
-
-  /**
-   * Retrieves the entry to be added to the server.  Note that this will not be
-   * available to pre-parse plugins or during the conflict resolution portion of
-   * the synchronization processing.
-   *
-   * @return  The entry to be added to the server, or <CODE>null</CODE> if it is
-   *          not yet available.
-   */
-  public final Entry getEntryToAdd()
-  {
-    return entry;
-  }
-
-
-
-  /**
-   * {@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 removeAttribute(AttributeType attributeType);
 
   /**
    * Retrieves the change number that has been assigned to this operation.
@@ -566,12 +145,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
@@ -580,131 +154,52 @@
    * @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;
-  }
-
-
+  public abstract void setChangeNumber(long changeNumber);
 
   /**
-   * {@inheritDoc}
+   * Retrieves the set of processed objectclasses for the entry to add.  This
+   * should not be called by pre-parse plugins because this information will not
+   * yet be available.  The contents of the returned map may not be altered by
+   * the caller.
+   *
+   * @return  The set of processed objectclasses for the entry to add, or
+   *          <CODE>null</CODE> if that information is not yet available.
    */
-  @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.ADD;
-  }
-
-
+  public abstract Map<ObjectClass,String> getObjectClasses();
 
   /**
-   * {@inheritDoc}
+   * Adds the provided objectclass to the entry to add.  This should only be
+   * called from pre-operation plugins.  Note that pre-operation plugin
+   * processing is invoked after access control and schema validation, so
+   * plugins should be careful to only make changes that will not violate either
+   * schema or access control rules.
+   *
+   * @param  objectClass  The objectclass to add to the entry.
+   * @param  name         The name to use for the objectclass.
    */
-  @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);
-  }
-
-
+  public abstract void addObjectClass(ObjectClass objectClass, String name);
 
   /**
-   * {@inheritDoc}
+   * Removes the provided objectclass from the entry to add.  This should only
+   * be called from pre-operation plugins.  Note that pre-operation plugin
+   * processing is invoked after access control and schema validation, so
+   * plugins should be careful to only make changes that will not violate either
+   * schema or access control rules.
+   *
+   * @param  objectClass  The objectclass to remove from the entry.
    */
-  @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) }
-    };
-  }
-
-
+  public abstract void removeObjectClass(ObjectClass objectClass);
 
   /**
-   * {@inheritDoc}
+   * Retrieves the set of processed operational attributes for the entry to add.
+   * This should not be called by pre-parse plugins because this information
+   * will not yet be available.  The contents of the returned map may be altered
+   * by the caller.
+   *
+   * @return  The set of processed operational attributes for the entry to add,
+   *          or <CODE>null</CODE> if that information is not yet available.
    */
-  @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 Map<AttributeType,List<Attribute>> getOperationalAttributes();
 
   /**
    * Retrieves the proxied authorization DN for this operation if proxied
@@ -714,1914 +209,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}
-   */
-  @Override()
-  public final ArrayList<Control> getResponseControls()
-  {
-    return responseControls;
-  }
-
-
-
-  /**
-   * {@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()
-  {
-    // Start the processing timer.
-    processingStartTime = System.currentTimeMillis();
-    setResultCode(ResultCode.UNDEFINED);
-
-
-    // Check for and handle a request to cancel this operation.
-    if (cancelRequest != null)
-    {
-      indicateCancelled(cancelRequest);
-      processingStopTime = System.currentTimeMillis();
-      return;
-    }
-
-
-    // Get the plugin config manager that will be used for invoking plugins.
-    PluginConfigManager pluginConfigManager =
-         DirectoryServer.getPluginConfigManager();
-    boolean skipPostOperation = false;
-
-
-    // Create a labeled block of code that we can break out of if a problem is
-    // detected.
-addProcessing:
-    {
-      // Invoke the pre-parse add plugins.
-      PreParsePluginResult preParseResult =
-           pluginConfigManager.invokePreParseAddPlugins(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();
-
-        logAddRequest(this);
-        logAddResponse(this);
-        pluginConfigManager.invokePostResponseAddPlugins(this);
-        return;
-      }
-      else if (preParseResult.sendResponseImmediately())
-      {
-        skipPostOperation = true;
-        logAddRequest(this);
-        break addProcessing;
-      }
-      else if (preParseResult.skipCoreProcessing())
-      {
-        skipPostOperation = false;
-        break addProcessing;
-      }
-
-
-      // Log the add request message.
-      logAddRequest(this);
-
-
-      // Check for and handle a request to cancel this operation.
-      if (cancelRequest != null)
-      {
-        indicateCancelled(cancelRequest);
-        processingStopTime = System.currentTimeMillis();
-        logAddResponse(this);
-        pluginConfigManager.invokePostResponseAddPlugins(this);
-        return;
-      }
-
-
-      // Process the entry DN and set of attributes to convert them from their
-      // raw forms as provided by the client to the forms required for the rest
-      // of the add 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());
-        setMatchedDN(de.getMatchedDN());
-        setReferralURLs(de.getReferralURLs());
-
-        break addProcessing;
-      }
-
-
-      if ((objectClasses == null) || (userAttributes == null) ||
-          (operationalAttributes == null))
-      {
-        objectClasses         = new HashMap<ObjectClass,String>();
-        userAttributes        = new HashMap<AttributeType,List<Attribute>>();
-        operationalAttributes = new HashMap<AttributeType,List<Attribute>>();
-        for (RawAttribute a : rawAttributes)
-        {
-          try
-          {
-            Attribute attr = a.toAttribute();
-            AttributeType attrType = attr.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 (attrType.isNoUserModification())
-            {
-              if (! (isInternalOperation() || isSynchronizationOperation()))
-              {
-                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                appendErrorMessage(getMessage(MSGID_ADD_ATTR_IS_NO_USER_MOD,
-                                              String.valueOf(entryDN),
-                                              attr.getName()));
-                break addProcessing;
-              }
-            }
-
-
-            if (attrType.isObjectClassType())
-            {
-              for (ByteString os : a.getValues())
-              {
-                String ocName = os.toString();
-                ObjectClass oc =
-                     DirectoryServer.getObjectClass(toLowerCase(ocName));
-                if (oc == null)
-                {
-                  oc = DirectoryServer.getDefaultObjectClass(ocName);
-                }
-
-                objectClasses.put(oc,ocName);
-              }
-            }
-            else if (attrType.isOperational())
-            {
-              List<Attribute> attrs = operationalAttributes.get(attrType);
-              if (attrs == null)
-              {
-                attrs = new ArrayList<Attribute>(1);
-                attrs.add(attr);
-                operationalAttributes.put(attrType, attrs);
-              }
-              else
-              {
-                attrs.add(attr);
-              }
-            }
-            else
-            {
-              List<Attribute> attrs = userAttributes.get(attrType);
-              if (attrs == null)
-              {
-                attrs = new ArrayList<Attribute>(1);
-                attrs.add(attr);
-                userAttributes.put(attrType, attrs);
-              }
-              else
-              {
-                // Check to see if any of the existing attributes in the list
-                // have the same set of options.  If so, then add the values
-                // to that attribute.
-                boolean attributeSeen = false;
-                for (Attribute ea : attrs)
-                {
-                  if (ea.optionsEqual(attr.getOptions()))
-                  {
-                    LinkedHashSet<AttributeValue> valueSet = ea.getValues();
-                    valueSet.addAll(attr.getValues());
-                    attributeSeen = true;
-                  }
-                }
-                if (!attributeSeen)
-                {
-                  // This is the first occurrence of the attribute and options.
-                  attrs.add(attr);
-                }
-              }
-            }
-          }
-          catch (LDAPException le)
-          {
-            setResultCode(ResultCode.valueOf(le.getResultCode()));
-            appendErrorMessage(le.getMessage());
-
-            break addProcessing;
-          }
-        }
-      }
-
-
-      // Check for and handle a request to cancel this operation.
-      if (cancelRequest != null)
-      {
-        indicateCancelled(cancelRequest);
-        processingStopTime = System.currentTimeMillis();
-        logAddResponse(this);
-        pluginConfigManager.invokePostResponseAddPlugins(this);
-        return;
-      }
-
-
-      // Grab a read lock on the parent entry, if there is one.  We need to do
-      // this to ensure that the parent is not deleted or renamed while this add
-      // is in progress, and we could also need it to check the entry against
-      // a DIT structure rule.
-      Lock parentLock = null;
-      Lock entryLock  = null;
-
-      DN parentDN = entryDN.getParentDNInSuffix();
-      if (parentDN == null)
-      {
-        // Either this entry is a suffix or doesn't belong in the directory.
-        if (DirectoryServer.isNamingContext(entryDN))
-        {
-          // This is fine.  This entry is one of the configured suffixes.
-          parentLock = null;
-        }
-        else if (entryDN.isNullDN())
-        {
-          // This is not fine.  The root DSE cannot be added.
-          setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-          appendErrorMessage(getMessage(MSGID_ADD_CANNOT_ADD_ROOT_DSE));
-          break addProcessing;
-        }
-        else
-        {
-          // The entry doesn't have a parent but isn't a suffix.  This is not
-          // allowed.
-          setResultCode(ResultCode.NO_SUCH_OBJECT);
-          appendErrorMessage(getMessage(MSGID_ADD_ENTRY_NOT_SUFFIX,
-                                        String.valueOf(entryDN)));
-          break addProcessing;
-        }
-      }
-      else
-      {
-        for (int i=0; i < 3; i++)
-        {
-          parentLock = LockManager.lockRead(parentDN);
-          if (parentLock != null)
-          {
-            break;
-          }
-        }
-
-        if (parentLock == null)
-        {
-          setResultCode(DirectoryServer.getServerErrorResultCode());
-          appendErrorMessage(getMessage(MSGID_ADD_CANNOT_LOCK_PARENT,
-                                        String.valueOf(entryDN),
-                                        String.valueOf(parentDN)));
-
-          skipPostOperation = true;
-          break addProcessing;
-        }
-      }
-
-
-      try
-      {
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logAddResponse(this);
-          pluginConfigManager.invokePostResponseAddPlugins(this);
-          return;
-        }
-
-
-        // Grab a write lock on the target entry.  We'll need to do this
-        // eventually anyway, and we want to make sure that the two locks are
-        // always released when exiting this method, no matter what.  Since
-        // the entry shouldn't exist yet, locking earlier than necessary
-        // shouldn't cause a problem.
-        for (int i=0; i < 3; i++)
-        {
-          entryLock = LockManager.lockWrite(entryDN);
-          if (entryLock != null)
-          {
-            break;
-          }
-        }
-
-        if (entryLock == null)
-        {
-          setResultCode(DirectoryServer.getServerErrorResultCode());
-          appendErrorMessage(getMessage(MSGID_ADD_CANNOT_LOCK_ENTRY,
-                                        String.valueOf(entryDN)));
-
-          skipPostOperation = true;
-          break addProcessing;
-        }
-
-
-        // 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 addProcessing;
-            }
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            logError(ErrorLogCategory.SYNCHRONIZATION,
-                     ErrorLogSeverity.SEVERE_ERROR,
-                     MSGID_ADD_SYNCH_CONFLICT_RESOLUTION_FAILED,
-                     getConnectionID(), getOperationID(),
-                     getExceptionMessage(de));
-
-            setResponseData(de);
-            break addProcessing;
-          }
-        }
-
-
-        // Check to see if the entry already exists.  We do this before
-        // checking whether the parent exists to ensure a referral entry
-        // above the parent results in a correct referral.
-        try
-        {
-          if (DirectoryServer.entryExists(entryDN))
-          {
-            setResultCode(ResultCode.ENTRY_ALREADY_EXISTS);
-            appendErrorMessage(getMessage(MSGID_ADD_ENTRY_ALREADY_EXISTS,
-                                          String.valueOf(entryDN)));
-            break addProcessing;
-          }
-        }
-        catch (DirectoryException de)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, de);
-          }
-
-          setResultCode(de.getResultCode());
-          appendErrorMessage(de.getErrorMessage());
-          setMatchedDN(de.getMatchedDN());
-          setReferralURLs(de.getReferralURLs());
-          break addProcessing;
-        }
-
-
-        // Get the parent entry, if it exists.
-        Entry parentEntry = null;
-        if (parentDN != null)
-        {
-          try
-          {
-            parentEntry = DirectoryServer.getEntry(parentDN);
-
-            if (parentEntry == null)
-            {
-              DN matchedDN = parentDN.getParentDNInSuffix();
-              while (matchedDN != null)
-              {
-                try
-                {
-                  if (DirectoryServer.entryExists(matchedDN))
-                  {
-                    setMatchedDN(matchedDN);
-                    break;
-                  }
-                }
-                catch (Exception e)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
-                  }
-                  break;
-                }
-
-                matchedDN = matchedDN.getParentDNInSuffix();
-              }
-
-
-              // The parent doesn't exist, so this add can't be successful.
-              setResultCode(ResultCode.NO_SUCH_OBJECT);
-              appendErrorMessage(getMessage(MSGID_ADD_NO_PARENT,
-                                            String.valueOf(entryDN),
-                                            String.valueOf(parentDN)));
-              break addProcessing;
-            }
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            setResultCode(de.getResultCode());
-            appendErrorMessage(de.getErrorMessage());
-            setMatchedDN(de.getMatchedDN());
-            setReferralURLs(de.getReferralURLs());
-            break addProcessing;
-          }
-        }
-
-
-        // Check to make sure that all of the RDN attributes are included as
-        // attribute values.  If not, then either add them or report an error.
-        RDN rdn = entryDN.getRDN();
-        int numAVAs = rdn.getNumValues();
-        for (int i=0; i < numAVAs; i++)
-        {
-          AttributeType  t = rdn.getAttributeType(i);
-          AttributeValue v = rdn.getAttributeValue(i);
-          String         n = rdn.getAttributeName(i);
-          if (t.isOperational())
-          {
-            List<Attribute> attrList = operationalAttributes.get(t);
-            if (attrList == null)
-            {
-              if (isSynchronizationOperation() ||
-                  DirectoryServer.addMissingRDNAttributes())
-              {
-                LinkedHashSet<AttributeValue> valueList =
-                     new LinkedHashSet<AttributeValue>(1);
-                valueList.add(v);
-
-                attrList = new ArrayList<Attribute>();
-                attrList.add(new Attribute(t, n, valueList));
-
-                operationalAttributes.put(t, attrList);
-              }
-              else
-              {
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                int msgID = MSGID_ADD_MISSING_RDN_ATTRIBUTE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              n));
-
-                break addProcessing;
-              }
-            }
-            else
-            {
-              boolean found = false;
-              for (Attribute a : attrList)
-              {
-                if (a.hasOptions())
-                {
-                  continue;
-                }
-                else
-                {
-                  if (! a.hasValue(v))
-                  {
-                    a.getValues().add(v);
-                  }
-
-                  found = true;
-                  break;
-                }
-              }
-
-              if (! found)
-              {
-                if (isSynchronizationOperation() ||
-                    DirectoryServer.addMissingRDNAttributes())
-                {
-                  LinkedHashSet<AttributeValue> valueList =
-                       new LinkedHashSet<AttributeValue>(1);
-                  valueList.add(v);
-                  attrList.add(new Attribute(t, n, valueList));
-                }
-                else
-                {
-                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                  int msgID = MSGID_ADD_MISSING_RDN_ATTRIBUTE;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                n));
-
-                  break addProcessing;
-                }
-              }
-            }
-          }
-          else
-          {
-            List<Attribute> attrList = userAttributes.get(t);
-            if (attrList == null)
-            {
-              if (isSynchronizationOperation() ||
-                  DirectoryServer.addMissingRDNAttributes())
-              {
-                LinkedHashSet<AttributeValue> valueList =
-                     new LinkedHashSet<AttributeValue>(1);
-                valueList.add(v);
-
-                attrList = new ArrayList<Attribute>();
-                attrList.add(new Attribute(t, n, valueList));
-
-                userAttributes.put(t, attrList);
-              }
-              else
-              {
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                int msgID = MSGID_ADD_MISSING_RDN_ATTRIBUTE;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              n));
-
-                break addProcessing;
-              }
-            }
-            else
-            {
-              boolean found = false;
-              for (Attribute a : attrList)
-              {
-                if (a.hasOptions())
-                {
-                  continue;
-                }
-                else
-                {
-                  if (! a.hasValue(v))
-                  {
-                    a.getValues().add(v);
-                  }
-
-                  found = true;
-                  break;
-                }
-              }
-
-              if (! found)
-              {
-                if (isSynchronizationOperation() ||
-                    DirectoryServer.addMissingRDNAttributes())
-                {
-                  LinkedHashSet<AttributeValue> valueList =
-                       new LinkedHashSet<AttributeValue>(1);
-                  valueList.add(v);
-                  attrList.add(new Attribute(t, n, valueList));
-                }
-                else
-                {
-                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-
-                  int msgID = MSGID_ADD_MISSING_RDN_ATTRIBUTE;
-                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                                n));
-
-                  break addProcessing;
-                }
-              }
-            }
-          }
-        }
-
-
-        // Check to make sure that all objectclasses have their superior classes
-        // listed in the entry.  If not, then add them.
-        HashSet<ObjectClass> additionalClasses = null;
-        for (ObjectClass oc : objectClasses.keySet())
-        {
-          ObjectClass superiorClass = oc.getSuperiorClass();
-          if ((superiorClass != null) &&
-              (! objectClasses.containsKey(superiorClass)))
-          {
-            if (additionalClasses == null)
-            {
-              additionalClasses = new HashSet<ObjectClass>();
-            }
-
-            additionalClasses.add(superiorClass);
-          }
-        }
-
-        if (additionalClasses != null)
-        {
-          for (ObjectClass oc : additionalClasses)
-          {
-            addObjectClassChain(oc);
-          }
-        }
-
-
-        // Create an entry object to encapsulate the set of attributes and
-        // objectclasses.
-        entry = new Entry(entryDN, objectClasses, userAttributes,
-                          operationalAttributes);
-
-
-        // Check to see if the entry includes a privilege specification.  If so,
-        // then the requester must have the PRIVILEGE_CHANGE privilege.
-        AttributeType privType =
-             DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME, true);
-        if (entry.hasAttribute(privType) &&
-            (! clientConnection.hasPrivilege(Privilege.PRIVILEGE_CHANGE, this)))
-        {
-          int msgID = MSGID_ADD_CHANGE_PRIVILEGE_INSUFFICIENT_PRIVILEGES;
-          appendErrorMessage(getMessage(msgID));
-          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-          break addProcessing;
-        }
-
-        // If it's not a synchronization operation, then check
-        // to see if the entry contains one or more passwords and if they
-        // are valid in accordance with the password policies associated with
-        // the user.  Also perform any encoding that might be required by
-        // password storage schemes.
-        if (! isSynchronizationOperation())
-        {
-          // FIXME -- We need to check to see if the password policy subentry
-          //          might be specified virtually rather than as a real
-          //          attribute.
-          PasswordPolicy pwPolicy = null;
-          List<Attribute> pwAttrList =
-               entry.getAttribute(OP_ATTR_PWPOLICY_POLICY_DN);
-          if ((pwAttrList != null) && (! pwAttrList.isEmpty()))
-          {
-            Attribute a = pwAttrList.get(0);
-            LinkedHashSet<AttributeValue> valueSet = a.getValues();
-            Iterator<AttributeValue> iterator = valueSet.iterator();
-            if (iterator.hasNext())
-            {
-              DN policyDN;
-              try
-              {
-                policyDN = DN.decode(iterator.next().getValue());
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                int msgID = MSGID_ADD_INVALID_PWPOLICY_DN_SYNTAX;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              de.getErrorMessage()));
-
-                setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-                break addProcessing;
-              }
-
-              pwPolicy = DirectoryServer.getPasswordPolicy(policyDN);
-              if (pwPolicy == null)
-              {
-                int msgID = MSGID_ADD_NO_SUCH_PWPOLICY;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              String.valueOf(policyDN)));
-
-                setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-                break addProcessing;
-              }
-            }
-          }
-
-          if (pwPolicy == null)
-          {
-            pwPolicy = DirectoryServer.getDefaultPasswordPolicy();
-          }
-
-          try
-          {
-            handlePasswordPolicy(pwPolicy, entry);
-          }
-          catch (DirectoryException de)
-          {
-            if (debugEnabled())
-            {
-              TRACER.debugCaught(DebugLogLevel.ERROR, de);
-            }
-
-            setResponseData(de);
-            break addProcessing;
-          }
-        }
-
-
-        // Check to see if the entry is valid according to the server schema,
-        // and also whether its attributes are valid according to their syntax.
-        if (DirectoryServer.checkSchema())
-        {
-          StringBuilder invalidReason = new StringBuilder();
-          if (! entry.conformsToSchema(parentEntry, true, true, true,
-                                       invalidReason))
-          {
-            setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
-            setErrorMessage(invalidReason);
-            break addProcessing;
-          }
-          else
-          {
-            switch (DirectoryServer.getSyntaxEnforcementPolicy())
-            {
-              case REJECT:
-                invalidReason = new StringBuilder();
-                for (List<Attribute> attrList : userAttributes.values())
-                {
-                  for (Attribute a : attrList)
-                  {
-                    AttributeSyntax syntax = a.getAttributeType().getSyntax();
-                    if (syntax != null)
-                    {
-                      for (AttributeValue v : a.getValues())
-                      {
-                        if (! syntax.valueIsAcceptable(v.getValue(),
-                                                       invalidReason))
-                        {
-                          String message =
-                               getMessage(MSGID_ADD_OP_INVALID_SYNTAX,
-                                          String.valueOf(entryDN),
-                                          String.valueOf(v.getStringValue()),
-                                          String.valueOf(a.getName()),
-                                          String.valueOf(invalidReason));
-                          invalidReason = new StringBuilder(message);
-
-                          setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-                          setErrorMessage(invalidReason);
-                          break addProcessing;
-                        }
-                      }
-                    }
-                  }
-                }
-
-                for (List<Attribute> attrList :
-                     operationalAttributes.values())
-                {
-                  for (Attribute a : attrList)
-                  {
-                    AttributeSyntax syntax = a.getAttributeType().getSyntax();
-                    if (syntax != null)
-                    {
-                      for (AttributeValue v : a.getValues())
-                      {
-                        if (! syntax.valueIsAcceptable(v.getValue(),
-                                                       invalidReason))
-                        {
-                          String message =
-                               getMessage(MSGID_ADD_OP_INVALID_SYNTAX,
-                                          String.valueOf(entryDN),
-                                          String.valueOf(v.getStringValue()),
-                                          String.valueOf(a.getName()),
-                                          String.valueOf(invalidReason));
-                          invalidReason = new StringBuilder(message);
-
-                          setResultCode(ResultCode.INVALID_ATTRIBUTE_SYNTAX);
-                          setErrorMessage(invalidReason);
-                          break addProcessing;
-                        }
-                      }
-                    }
-                  }
-                }
-
-                break;
-
-
-              case WARN:
-                invalidReason = new StringBuilder();
-                for (List<Attribute> attrList : userAttributes.values())
-                {
-                  for (Attribute a : attrList)
-                  {
-                    AttributeSyntax syntax = a.getAttributeType().getSyntax();
-                    if (syntax != null)
-                    {
-                      for (AttributeValue v : a.getValues())
-                      {
-                        if (! syntax.valueIsAcceptable(v.getValue(),
-                                                       invalidReason))
-                        {
-                          logError(ErrorLogCategory.SCHEMA,
-                                   ErrorLogSeverity.SEVERE_WARNING,
-                                   MSGID_ADD_OP_INVALID_SYNTAX,
-                                   String.valueOf(entryDN),
-                                   String.valueOf(v.getStringValue()),
-                                   String.valueOf(a.getName()),
-                                   String.valueOf(invalidReason));
-                        }
-                      }
-                    }
-                  }
-                }
-
-                for (List<Attribute> attrList : operationalAttributes.values())
-                {
-                  for (Attribute a : attrList)
-                  {
-                    AttributeSyntax syntax = a.getAttributeType().getSyntax();
-                    if (syntax != null)
-                    {
-                      for (AttributeValue v : a.getValues())
-                      {
-                        if (! syntax.valueIsAcceptable(v.getValue(),
-                                                       invalidReason))
-                        {
-                          logError(ErrorLogCategory.SCHEMA,
-                                   ErrorLogSeverity.SEVERE_WARNING,
-                                   MSGID_ADD_OP_INVALID_SYNTAX,
-                                   String.valueOf(entryDN),
-                                   String.valueOf(v.getStringValue()),
-                                   String.valueOf(a.getName()),
-                                   String.valueOf(invalidReason));
-                        }
-                      }
-                    }
-                  }
-                }
-
-                break;
-            }
-          }
-
-
-          // See if the entry contains any attributes or object classes marked
-          // OBSOLETE.  If so, then reject the entry.
-          for (AttributeType at : userAttributes.keySet())
-          {
-            if (at.isObsolete())
-            {
-              int    msgID   = MSGID_ADD_ATTR_IS_OBSOLETE;
-              String message = getMessage(msgID, String.valueOf(entryDN),
-                                          at.getNameOrOID());
-              appendErrorMessage(message);
-              setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              break addProcessing;
-            }
-          }
-
-          for (AttributeType at : operationalAttributes.keySet())
-          {
-            if (at.isObsolete())
-            {
-              int    msgID   = MSGID_ADD_ATTR_IS_OBSOLETE;
-              String message = getMessage(msgID, String.valueOf(entryDN),
-                                          at.getNameOrOID());
-              appendErrorMessage(message);
-              setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              break addProcessing;
-            }
-          }
-
-          for (ObjectClass oc : objectClasses.keySet())
-          {
-            if (oc.isObsolete())
-            {
-              int    msgID   = MSGID_ADD_OC_IS_OBSOLETE;
-              String message = getMessage(msgID, String.valueOf(entryDN),
-                                          oc.getNameOrOID());
-              appendErrorMessage(message);
-              setResultCode(ResultCode.CONSTRAINT_VIOLATION);
-              break addProcessing;
-            }
-          }
-        }
-
-        // 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;
-        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 addProcessing;
-                }
-              }
-
-              try
-              {
-                // FIXME -- We need to determine whether the current user has
-                //          permission to make this determination.
-                SearchFilter filter = assertControl.getSearchFilter();
-                if (! filter.matchesEntry(entry))
-                {
-                  setResultCode(ResultCode.ASSERTION_FAILED);
-
-                  appendErrorMessage(getMessage(MSGID_ADD_ASSERTION_FAILED,
-                                                String.valueOf(entryDN)));
-
-                  break addProcessing;
-                }
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(ResultCode.PROTOCOL_ERROR);
-
-                int msgID = MSGID_ADD_CANNOT_PROCESS_ASSERTION_FILTER;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              de.getErrorMessage()));
-
-                break addProcessing;
-              }
-            }
-            else if (oid.equals(OID_LDAP_NOOP_OPENLDAP_ASSIGNED))
-            {
-              noOp = true;
-            }
-            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 addProcessing;
-                }
-              }
-            }
-            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 addProcessing;
-              }
-
-
-              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 addProcessing;
-                }
-              }
-
-
-              Entry authorizationEntry;
-              try
-              {
-                authorizationEntry = proxyControl.getAuthorizationEntry();
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(de.getResultCode());
-                appendErrorMessage(de.getErrorMessage());
-
-                break addProcessing;
-              }
-
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(this,
-                      authorizationEntry) == false) {
-                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break addProcessing;
-              }
-              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 addProcessing;
-              }
-
-
-              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 addProcessing;
-                }
-              }
-
-
-              Entry authorizationEntry;
-              try
-              {
-                authorizationEntry = proxyControl.getAuthorizationEntry();
-              }
-              catch (DirectoryException de)
-              {
-                if (debugEnabled())
-                {
-                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                }
-
-                setResultCode(de.getResultCode());
-                appendErrorMessage(de.getErrorMessage());
-
-                break addProcessing;
-              }
-
-              if (AccessControlConfigManager.getInstance()
-                      .getAccessControlHandler().isProxiedAuthAllowed(this,
-                      authorizationEntry) == false) {
-                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-                int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-                skipPostOperation = true;
-                break addProcessing;
-              }
-              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_ADD_UNSUPPORTED_CRITICAL_CONTROL;
-                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
-                                              oid));
-
-                break addProcessing;
-              }
-            }
-          }
-        }
-
-
-        // Check to see if the client has permission to perform the add.
-
-        // 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 or
-        // if the parent entry does not exist may have already exposed
-        // sensitive information to the client.
-        if (AccessControlConfigManager.getInstance()
-            .getAccessControlHandler().isAllowed(this) == false) {
-          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
-
-          int msgID = MSGID_ADD_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
-          appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
-
-          skipPostOperation = true;
-          break addProcessing;
-        }
-
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logAddResponse(this);
-          pluginConfigManager.invokePostResponseAddPlugins(this);
-          return;
-        }
-
-
-        // If the operation is not a synchronization operation,
-        // Invoke the pre-operation modify plugins.
-        if (!isSynchronizationOperation())
-        {
-          PreOperationPluginResult preOpResult =
-            pluginConfigManager.invokePreOperationAddPlugins(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();
-
-            logAddResponse(this);
-            pluginConfigManager.invokePostResponseAddPlugins(this);
-            return;
-          }
-          else if (preOpResult.sendResponseImmediately())
-          {
-            skipPostOperation = true;
-            break addProcessing;
-          }
-          else if (preOpResult.skipCoreProcessing())
-          {
-            skipPostOperation = false;
-            break addProcessing;
-          }
-        }
-
-
-        // Check for and handle a request to cancel this operation.
-        if (cancelRequest != null)
-        {
-          indicateCancelled(cancelRequest);
-          processingStopTime = System.currentTimeMillis();
-          logAddResponse(this);
-          pluginConfigManager.invokePostResponseAddPlugins(this);
-          return;
-        }
-
-
-        // Actually perform the add 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("No backend for entry " + entryDN.toString());
-        }
-        else
-        {
-          // 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_ADD_SERVER_READONLY,
-                                              String.valueOf(entryDN)));
-                break addProcessing;
-
-              case INTERNAL_ONLY:
-                if (! (isInternalOperation() || isSynchronizationOperation()))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                  appendErrorMessage(getMessage(MSGID_ADD_SERVER_READONLY,
-                                                String.valueOf(entryDN)));
-                  break addProcessing;
-                }
-            }
-
-            switch (backend.getWritabilityMode())
-            {
-              case DISABLED:
-                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                appendErrorMessage(getMessage(MSGID_ADD_BACKEND_READONLY,
-                                              String.valueOf(entryDN)));
-                break addProcessing;
-
-              case INTERNAL_ONLY:
-                if (! (isInternalOperation() || isSynchronizationOperation()))
-                {
-                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
-                  appendErrorMessage(getMessage(MSGID_ADD_BACKEND_READONLY,
-                                                String.valueOf(entryDN)));
-                  break addProcessing;
-                }
-            }
-          }
-
-
-          try
-          {
-            if (noOp)
-            {
-              appendErrorMessage(getMessage(MSGID_ADD_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 addProcessing;
-                  }
-                }
-                catch (DirectoryException de)
-                {
-                  if (debugEnabled())
-                  {
-                    TRACER.debugCaught(DebugLogLevel.ERROR, de);
-                  }
-
-                  logError(ErrorLogCategory.SYNCHRONIZATION,
-                           ErrorLogSeverity.SEVERE_ERROR,
-                           MSGID_ADD_SYNCH_PREOP_FAILED, getConnectionID(),
-                           getOperationID(), getExceptionMessage(de));
-
-                  setResponseData(de);
-                  break addProcessing;
-                }
-              }
-
-              backend.addEntry(entry, this);
-            }
-
-            if (postReadRequest != null)
-            {
-              Entry addedEntry = entry.duplicate(true);
-
-              if (! postReadRequest.allowsAttribute(
-                         DirectoryServer.getObjectClassAttributeType()))
-              {
-                addedEntry.removeAttribute(
-                     DirectoryServer.getObjectClassAttributeType());
-              }
-
-              if (! postReadRequest.returnAllUserAttributes())
-              {
-                Iterator<AttributeType> iterator =
-                     addedEntry.getUserAttributes().keySet().iterator();
-                while (iterator.hasNext())
-                {
-                  AttributeType attrType = iterator.next();
-                  if (! postReadRequest.allowsAttribute(attrType))
-                  {
-                    iterator.remove();
-                  }
-                }
-              }
-
-              if (! postReadRequest.returnAllOperationalAttributes())
-              {
-                Iterator<AttributeType> iterator =
-                     addedEntry.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(addedEntry);
-              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 addProcessing;
-          }
-          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 addProcessing;
-          }
-        }
-      }
-      finally
-      {
-        if (entryLock != null)
-        {
-          LockManager.unlock(entryDN, entryLock);
-        }
-
-        if (parentLock != null)
-        {
-          LockManager.unlock(parentDN, parentLock);
-        }
-
-
-        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_ADD_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 add plugins.
-    if (! skipPostOperation)
-    {
-      // FIXME -- Should this also be done while holding the locks?
-      PostOperationPluginResult postOpResult =
-           pluginConfigManager.invokePostOperationAddPlugins(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();
-
-        logAddResponse(this);
-        pluginConfigManager.invokePostResponseAddPlugins(this);
-        return;
-      }
-    }
-
-
-    // Notify any change notification listeners that might be registered with
-    // the server.
-    if ((getResultCode() == ResultCode.SUCCESS) && (entry != null))
-    {
-      for (ChangeNotificationListener changeListener :
-           DirectoryServer.getChangeNotificationListeners())
-      {
-        try
-        {
-          changeListener.handleAddOperation(this, entry);
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          int    msgID   = MSGID_ADD_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 add response to the client.
-    getClientConnection().sendResponse(this);
-
-
-    // Log the add response.
-    logAddResponse(this);
-
-
-    // Notify any persistent searches that might be registered with the server.
-    if ((getResultCode() == ResultCode.SUCCESS) && (entry != null))
-    {
-      for (PersistentSearch persistentSearch :
-           DirectoryServer.getPersistentSearches())
-      {
-        try
-        {
-          persistentSearch.processAdd(this, entry);
-        }
-        catch (Exception e)
-        {
-          if (debugEnabled())
-          {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-
-          int    msgID   = MSGID_ADD_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 add plugins.
-    pluginConfigManager.invokePostResponseAddPlugins(this);
-  }
-
-
-
-  /**
-   * Adds the provided objectClass to the entry, along with its superior classes
-   * if appropriate.
+   * Set the proxied authorization DN for this operation if proxied
+   * authorization has been requested.
    *
-   * @param  objectClass  The objectclass to add to the entry.
+   * @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.
    */
-  private final void addObjectClassChain(ObjectClass objectClass)
-  {
-    if (! objectClasses.containsKey(objectClass))
-    {
-      objectClasses.put(objectClass, objectClass.getNameOrOID());
-    }
+  public abstract void setProxiedAuthorizationDN(DN proxiedAuthorizationDN);
 
-    ObjectClass superiorClass = objectClass.getSuperiorClass();
-    if ((superiorClass != null) &&
-        (! objectClasses.containsKey(superiorClass)))
-    {
-      addObjectClassChain(superiorClass);
-    }
-  }
-
-
-
-  /**
-   * Performs all password policy processing necessary for the provided add
-   * operation.
-   *
-   * @param  passwordPolicy  The password policy associated with the entry to be
-   *                         added.
-   * @param  userEntry       The user entry being added.
-   *
-   * @throws  DirectoryException  If a problem occurs while performing password
-   *                              policy processing for the add operation.
-   */
-  private final void handlePasswordPolicy(PasswordPolicy passwordPolicy,
-                                          Entry userEntry)
-         throws DirectoryException
-  {
-    // See if a password was specified.
-    AttributeType passwordAttribute = passwordPolicy.getPasswordAttribute();
-    List<Attribute> attrList = userEntry.getAttribute(passwordAttribute);
-    if ((attrList == null) || attrList.isEmpty())
-    {
-      // The entry doesn't have a password, so no action is required.
-      return;
-    }
-    else if (attrList.size() > 1)
-    {
-      // This must mean there are attribute options, which we won't allow for
-      // passwords.
-      int msgID = MSGID_PWPOLICY_ATTRIBUTE_OPTIONS_NOT_ALLOWED;
-      String message = getMessage(msgID, passwordAttribute.getNameOrOID());
-      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
-                                   msgID);
-    }
-
-    Attribute passwordAttr = attrList.get(0);
-    if (passwordAttr.hasOptions())
-    {
-      int msgID = MSGID_PWPOLICY_ATTRIBUTE_OPTIONS_NOT_ALLOWED;
-      String message = getMessage(msgID, passwordAttribute.getNameOrOID());
-      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
-                                   msgID);
-    }
-
-    LinkedHashSet<AttributeValue> values = passwordAttr.getValues();
-    if (values.isEmpty())
-    {
-      // This will be treated the same as not having a password.
-      return;
-    }
-
-    if ((! passwordPolicy.allowMultiplePasswordValues()) && (values.size() > 1))
-    {
-      // FIXME -- What if they're pre-encoded and might all be the same?
-      int    msgID   = MSGID_PWPOLICY_MULTIPLE_PW_VALUES_NOT_ALLOWED;
-      String message = getMessage(msgID, passwordAttribute.getNameOrOID());
-      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message,
-                                   msgID);
-    }
-
-    CopyOnWriteArrayList<PasswordStorageScheme> defaultStorageSchemes =
-         passwordPolicy.getDefaultStorageSchemes();
-    LinkedHashSet<AttributeValue> newValues =
-         new LinkedHashSet<AttributeValue>(defaultStorageSchemes.size());
-    for (AttributeValue v : values)
-    {
-      ByteString value = v.getValue();
-
-      // See if the password is pre-encoded.
-      if (passwordPolicy.usesAuthPasswordSyntax())
-      {
-        if (AuthPasswordSyntax.isEncoded(value))
-        {
-          if (passwordPolicy.allowPreEncodedPasswords())
-          {
-            newValues.add(v);
-            continue;
-          }
-          else
-          {
-            int    msgID   = MSGID_PWPOLICY_PREENCODED_NOT_ALLOWED;
-            String message = getMessage(msgID,
-                                        passwordAttribute.getNameOrOID());
-            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                                         message, msgID);
-          }
-        }
-      }
-      else
-      {
-        if (UserPasswordSyntax.isEncoded(value))
-        {
-          if (passwordPolicy.allowPreEncodedPasswords())
-          {
-            newValues.add(v);
-            continue;
-          }
-          else
-          {
-            int    msgID   = MSGID_PWPOLICY_PREENCODED_NOT_ALLOWED;
-            String message = getMessage(msgID,
-                                        passwordAttribute.getNameOrOID());
-            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                                         message, msgID);
-          }
-        }
-      }
-
-
-      // See if the password passes validation.  We should only do this if
-      // validation should be performed for administrators.
-      if (! passwordPolicy.skipValidationForAdministrators())
-      {
-        // There are never any current passwords for an add operation.
-        HashSet<ByteString> currentPasswords = new HashSet<ByteString>(0);
-        StringBuilder invalidReason = new StringBuilder();
-        for (PasswordValidator<?> validator :
-             passwordPolicy.getPasswordValidators().values())
-        {
-          if (! validator.passwordIsAcceptable(value, currentPasswords, this,
-                                               userEntry, invalidReason))
-          {
-            int    msgID   = MSGID_PWPOLICY_VALIDATION_FAILED;
-            String message = getMessage(msgID, passwordAttribute.getNameOrOID(),
-                                        String.valueOf(invalidReason));
-            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
-                                         message, msgID);
-          }
-        }
-      }
-
-
-      // Encode the password.
-      if (passwordPolicy.usesAuthPasswordSyntax())
-      {
-        for (PasswordStorageScheme s : defaultStorageSchemes)
-        {
-          ByteString encodedValue = s.encodeAuthPassword(value);
-          newValues.add(new AttributeValue(passwordAttribute, encodedValue));
-        }
-      }
-      else
-      {
-        for (PasswordStorageScheme s : defaultStorageSchemes)
-        {
-          ByteString encodedValue = s.encodePasswordWithScheme(value);
-          newValues.add(new AttributeValue(passwordAttribute, encodedValue));
-        }
-      }
-    }
-
-
-    // Put the new encoded values in the entry.
-    passwordAttr.setValues(newValues);
-
-
-    // Set the password changed time attribute.
-    ByteString timeString =
-         new ASN1OctetString(TimeThread.getGeneralizedTime());
-    AttributeType changedTimeType =
-         DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_CHANGED_TIME_LC);
-    if (changedTimeType == null)
-    {
-      changedTimeType = DirectoryServer.getDefaultAttributeType(
-                                             OP_ATTR_PWPOLICY_CHANGED_TIME);
-    }
-
-    LinkedHashSet<AttributeValue> changedTimeValues =
-         new LinkedHashSet<AttributeValue>(1);
-    changedTimeValues.add(new AttributeValue(changedTimeType, timeString));
-
-    ArrayList<Attribute> changedTimeList = new ArrayList<Attribute>(1);
-    changedTimeList.add(new Attribute(changedTimeType,
-                                      OP_ATTR_PWPOLICY_CHANGED_TIME,
-                                      changedTimeValues));
-
-    userEntry.putAttribute(changedTimeType, changedTimeList);
-
-
-    // If we should force change on add, then set the appropriate flag.
-    if (passwordPolicy.forceChangeOnAdd())
-    {
-      AttributeType resetType =
-           DirectoryServer.getAttributeType(OP_ATTR_PWPOLICY_RESET_REQUIRED_LC);
-      if (resetType == null)
-      {
-        resetType = DirectoryServer.getDefaultAttributeType(
-                                         OP_ATTR_PWPOLICY_RESET_REQUIRED);
-      }
-
-      LinkedHashSet<AttributeValue> resetValues = new
-           LinkedHashSet<AttributeValue>(1);
-      resetValues.add(BooleanSyntax.createBooleanValue(true));
-
-      ArrayList<Attribute> resetList = new ArrayList<Attribute>(1);
-      resetList.add(new Attribute(resetType, OP_ATTR_PWPOLICY_RESET_REQUIRED,
-                                  resetValues));
-      userEntry.putAttribute(resetType, resetList);
-    }
-  }
-
-
-
-  /**
-   * {@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("AddOperation(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