mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jarnou
17.14.2007 ff9755c40feeaf5a3208229d48b80b608ab7a68c
opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -225,7 +225,7 @@
   * @return  {@code true} if the operation should be allowed by the
   *          access control configuration, or {@code false} if not.
   */
  public abstract boolean isAllowed(ModifyDNOperation
  public abstract boolean isAllowed(LocalBackendModifyDNOperation
                                         modifyDNOperation);
opends/src/server/org/opends/server/api/AccessLogPublisher.java
@@ -341,7 +341,7 @@
   *                            DN request.
   */
  public abstract void logModifyDNRequest(
                            ModifyDNOperation modifyDNOperation);
                            ModifyDNOperationBasis modifyDNOperation);
@@ -355,7 +355,7 @@
   *                            DN response.
   */
  public abstract void logModifyDNResponse(
                            ModifyDNOperation modifyDNOperation);
                            ModifyDNOperationBasis modifyDNOperation);
opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -1025,7 +1025,8 @@
   * @param newRDN      The new RDN component.
   * @return True if access is allowed.
   */
  private boolean aciCheckRDNs(ModifyDNOperation operation, RDN oldRDN,
  private boolean aciCheckRDNs(LocalBackendModifyDNOperation operation,
                               RDN oldRDN,
                               RDN newRDN) {
      boolean ret;
@@ -1078,7 +1079,8 @@
   * @throws DirectoryException  If a problem occurs while trying to
   *                             retrieve the new superior entry.
   */
  private boolean aciCheckSuperiorEntry(DN superiorDN, ModifyDNOperation op)
  private boolean aciCheckSuperiorEntry(DN superiorDN,
      LocalBackendModifyDNOperation op)
  throws DirectoryException {
    boolean ret=false;
    Lock entryLock = null;
@@ -1115,7 +1117,7 @@
   * @return True if access is allowed.
   *
   */
  public boolean isAllowed(ModifyDNOperation operation) {
  public boolean isAllowed(LocalBackendModifyDNOperation operation) {
      boolean ret=true;
      DN newSuperiorDN;
      RDN oldRDN=operation.getOriginalEntry().getDN().getRDN();
opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -104,7 +104,8 @@
     * @param rights  The rights of the modify DN operation.
     * @param entry  The entry to evalauted for this modify DN.
     */
    public AciLDAPOperationContainer(ModifyDNOperation operation,  int rights,
    public AciLDAPOperationContainer(LocalBackendModifyDNOperation operation,
                                     int rights,
                                     Entry entry) {
        super(operation, rights,  entry);
    }
opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -160,7 +160,7 @@
   * {@inheritDoc}
   */
  @Override
  public boolean isAllowed(ModifyDNOperation modifyDNOperation)
  public boolean isAllowed(LocalBackendModifyDNOperation modifyDNOperation)
  {
    return true;
  }
opends/src/server/org/opends/server/core/ModifyDNOperation.java
@@ -26,231 +26,20 @@
 */
package org.opends.server.core;
import java.util.ArrayList;
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.Backend;
import org.opends.server.api.ChangeNotificationListener;
import org.opends.server.api.ClientConnection;
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.types.AbstractOperation;
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.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.OperationType;
import org.opends.server.types.Privilege;
import org.opends.server.types.Operation;
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.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
import org.opends.server.types.operation.PreParseModifyDNOperation;
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.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 alter the DN of an entry
 * in the Directory Server.
 * This interface defines an operation used to move an entry in
 * the Directory Server.
 */
public class ModifyDNOperation
       extends AbstractOperation
       implements PreParseModifyDNOperation, PreOperationModifyDNOperation,
                  PostOperationModifyDNOperation, PostResponseModifyDNOperation
public interface ModifyDNOperation extends Operation
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = DebugLogger.getTracer();
  // Indicates whether to delete the old RDN value from the entry.
  private boolean deleteOldRDN;
  // The raw, unprocessed current DN of the entry as included in the request
  // from the client.
  private ByteString rawEntryDN;
  // The raw, unprocessed newRDN as included in the request from the client.
  private ByteString rawNewRDN;
  // The raw, unprocessed newSuperior as included in the request from the
  // client.
  private ByteString rawNewSuperior;
  // The cancel request issued for this modify DN operation.
  private CancelRequest cancelRequest;
  // The current DN of the entry.
  private DN entryDN;
  // The new parent for the entry.
  private DN newSuperior;
  // The proxied authorization target DN for this operation.
  private DN proxiedAuthorizationDN;
  // The current entry, before it is renamed.
  private Entry currentEntry;
  // The new entry, as it will appear after it has been renamed.
  private Entry newEntry;
  // The set of response controls for this modify DN operation.
  private List<Control> responseControls;
  // The set of modifications applied to attributes in the entry in the course
  // of processing the modify DN.
  private List<Modification> modifications;
  // The change number that has been assigned to this operation.
  private long changeNumber;
  // The new RDN for the entry.
  private RDN newRDN;
  /**
   * Creates a new modify DN 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 entry DN as included in the
   *                           client request.
   * @param  rawNewRDN         The raw, unprocessed newRDN as included in the
   *                           client request.
   * @param  deleteOldRDN      Indicates whether to delete the old RDN value
   *                           from the entry.
   * @param  rawNewSuperior    The raw, unprocessed newSuperior as included in
   *                           the client request.
   */
  public ModifyDNOperation(ClientConnection clientConnection, long operationID,
                           int messageID, List<Control> requestControls,
                           ByteString rawEntryDN, ByteString rawNewRDN,
                           boolean deleteOldRDN, ByteString rawNewSuperior)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.rawEntryDN      = rawEntryDN;
    this.rawNewRDN       = rawNewRDN;
    this.deleteOldRDN    = deleteOldRDN;
    this.rawNewSuperior  = rawNewSuperior;
    entryDN          = null;
    newRDN           = null;
    newSuperior      = null;
    responseControls = new ArrayList<Control>();
    cancelRequest    = null;
    modifications    = null;
    changeNumber     = -1;
    currentEntry     = null;
    newEntry         = null;
  }
  /**
   * Creates a new modify DN 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 current entry DN for this modify DN
   *                           operation.
   * @param  newRDN            The new RDN for this modify DN operation.
   * @param  deleteOldRDN      Indicates whether to delete the old RDN value
   *                           from the entry.
   * @param  newSuperior       The newSuperior DN for this modify DN operation.
   */
  public ModifyDNOperation(ClientConnection clientConnection, long operationID,
                           int messageID, List<Control> requestControls,
                           DN entryDN, RDN newRDN, boolean deleteOldRDN,
                           DN newSuperior)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.entryDN      = entryDN;
    this.newRDN       = newRDN;
    this.deleteOldRDN = deleteOldRDN;
    this.newSuperior  = newSuperior;
    rawEntryDN = new ASN1OctetString(entryDN.toString());
    rawNewRDN  = new ASN1OctetString(newRDN.toString());
    if (newSuperior == null)
    {
      rawNewSuperior = null;
    }
    else
    {
      rawNewSuperior = new ASN1OctetString(newSuperior.toString());
    }
    responseControls = new ArrayList<Control>();
    cancelRequest    = null;
    modifications    = null;
    changeNumber     = -1;
    currentEntry     = null;
    newEntry         = null;
  }
  /**
   * Retrieves the raw, unprocessed entry DN as included in the client request.
@@ -259,12 +48,7 @@
   *
   * @return  The raw, unprocessed entry DN as included in the client request.
   */
  public final ByteString getRawEntryDN()
  {
    return rawEntryDN;
  }
  public ByteString getRawEntryDN();
  /**
   * Specifies the raw, unprocessed entry DN as included in the client request.
@@ -273,13 +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 void setRawEntryDN(ByteString rawEntryDN);
  /**
@@ -290,12 +68,7 @@
   * @return  The DN of the entry to rename, or <CODE>null</CODE> if the raw
   *          entry DN has not yet been processed.
   */
  public final DN getEntryDN()
  {
    return entryDN;
  }
  public DN getEntryDN();
  /**
   * Retrieves the raw, unprocessed newRDN as included in the request from the
@@ -305,12 +78,7 @@
   * @return  The raw, unprocessed newRDN as included in the request from the
   *          client.
   */
  public final ByteString getRawNewRDN()
  {
    return rawNewRDN;
  }
  public ByteString getRawNewRDN();
  /**
   * Specifies the raw, unprocessed newRDN as included in the request from the
@@ -320,14 +88,7 @@
   * @param  rawNewRDN  The raw, unprocessed newRDN as included in the request
   *                    from the client.
   */
  public final void setRawNewRDN(ByteString rawNewRDN)
  {
    this.rawNewRDN = rawNewRDN;
    newRDN = null;
  }
  public void setRawNewRDN(ByteString rawNewRDN);
  /**
   * Retrieves the new RDN to use for the entry.  This should not be called by
@@ -337,11 +98,7 @@
   * @return  The new RDN to use for the entry, or <CODE>null</CODE> if the raw
   *          newRDN has not yet been processed.
   */
  public final RDN getNewRDN()
  {
    return newRDN;
  }
  public RDN getNewRDN();
  /**
@@ -350,12 +107,7 @@
   * @return  <CODE>true</CODE> if the current RDN value should be removed from
   *          the entry, or <CODE>false</CODE> if not.
   */
  public final boolean deleteOldRDN()
  {
    return deleteOldRDN;
  }
  public boolean deleteOldRDN();
  /**
   * Specifies whether the current RDN value should be removed from the entry.
@@ -363,12 +115,7 @@
   * @param  deleteOldRDN  Specifies whether the current RDN value should be
   *                       removed from the entry.
   */
  public final void setDeleteOldRDN(boolean deleteOldRDN)
  {
    this.deleteOldRDN = deleteOldRDN;
  }
  public void setDeleteOldRDN(boolean deleteOldRDN);
  /**
   * Retrieves the raw, unprocessed newSuperior from the client request.  This
@@ -378,12 +125,7 @@
   * @return  The raw, unprocessed newSuperior from the client request, or
   *          <CODE>null</CODE> if there is none.
   */
  public final ByteString getRawNewSuperior()
  {
    return rawNewSuperior;
  }
  public ByteString getRawNewSuperior();
  /**
   * Specifies the raw, unprocessed newSuperior for this modify DN operation, as
@@ -393,14 +135,7 @@
   * @param  rawNewSuperior  The raw, unprocessed newSuperior as provided in the
   *                         request from the client.
   */
  public final void setRawNewSuperior(ByteString rawNewSuperior)
  {
    this.rawNewSuperior = rawNewSuperior;
    newSuperior = null;
  }
  public void setRawNewSuperior(ByteString rawNewSuperior);
  /**
   * Retrieves the newSuperior DN for the entry.  This should not be called by
@@ -412,12 +147,15 @@
   *          no newSuperior DN for this request or if the raw newSuperior has
   *          not yet been processed.
   */
  public final DN getNewSuperior()
  {
    return newSuperior;
  }
  public DN getNewSuperior();
  /**
   * Retrieves the new DN for the entry.
   *
   * @return The new DN for the entry, or <CODE>null</CODE> if there is
   *          neither newRDN, nor entryDN for this request.
   */
  public DN getNewDN();
  /**
   * Retrieves the set of modifications applied to attributes of the target
@@ -436,12 +174,7 @@
   *          of the modify DN processing, or <CODE>null</CODE> if that
   *          information is not yet available (e.g., during pre-parse plugins).
   */
  public final List<Modification> getModifications()
  {
    return modifications;
  }
  public List<Modification> getModifications();
  /**
   * Adds the provided modification to the set of modifications to be applied
@@ -451,12 +184,7 @@
   * @param  modification  The modification to add to the set of modifications
   *                       to apply to the entry.
   */
  public final void addModification(Modification modification)
  {
    modifications.add(modification);
  }
  public void addModification(Modification modification);
  /**
   * Retrieves the current entry, before it is renamed.  This will not be
@@ -466,11 +194,7 @@
   * @return  The current entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final Entry getOriginalEntry()
  {
    return currentEntry;
  }
  public Entry getOriginalEntry();
  /**
@@ -481,10 +205,7 @@
   * @return  The updated entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final Entry getUpdatedEntry()
  {
    return newEntry;
  }
  public Entry getUpdatedEntry();
  /**
   * Retrieves the change number that has been assigned to this operation.
@@ -493,11 +214,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 long getChangeNumber();
  /**
@@ -507,143 +224,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 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_DN;
  }
  /**
   * {@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 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.
    String newSuperiorStr;
    if (rawNewSuperior == null)
    {
      newSuperiorStr = null;
    }
    else
    {
      newSuperiorStr = rawNewSuperior.stringValue();
    }
    return new String[][]
    {
      new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) },
      new String[] { LOG_ELEMENT_NEW_RDN, String.valueOf(newRDN) },
      new String[] { LOG_ELEMENT_DELETE_OLD_RDN, String.valueOf(deleteOldRDN) },
      new String[] { LOG_ELEMENT_NEW_SUPERIOR, newSuperiorStr }
    };
  }
  /**
   * {@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(getProcessingTime());
    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 void setChangeNumber(long changeNumber);
  /**
@@ -654,1572 +235,17 @@
   *          authorization has been requested, or {@code null} if proxied
   *          authorization has not been requested.
   */
  public DN getProxiedAuthorizationDN()
  {
    return proxiedAuthorizationDN;
  }
  public DN getProxiedAuthorizationDN();
  /**
   * {@inheritDoc}
   * Sets the proxied authorization DN for this operation if proxied
   * authorization has been requested.
   *
   * @param dn  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;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void addResponseControl(Control control)
  {
    responseControls.add(control);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void removeResponseControl(Control control)
  {
    responseControls.remove(control);
  }
  /**
   * Performs the work of actually processing this operation.  This
   * should include all processing for the operation, including
   * invoking plugins, logging messages, performing access control,
   * managing synchronization, and any other work that might need to
   * be done in the course of processing.
   */
  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.
    setProcessingStartTime();
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      return;
    }
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
modifyDNProcessing:
    {
      // Invoke the pre-parse modify DN plugins.
      PreParsePluginResult preParseResult =
           pluginConfigManager.invokePreParseModifyDNPlugins(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));
        setProcessingStopTime();
        logModifyDNRequest(this);
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(this);
        return;
      }
      else if (preParseResult.sendResponseImmediately())
      {
        skipPostOperation = true;
        logModifyDNRequest(this);
        break modifyDNProcessing;
      }
      else if (preParseResult.skipCoreProcessing())
      {
        skipPostOperation = false;
        break modifyDNProcessing;
      }
      // Log the modify DN request message.
      logModifyDNRequest(this);
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(this);
        return;
      }
      // Process the entry DN, newRDN, and newSuperior elements from their raw
      // forms as provided by the client to the forms required for the rest of
      // the modify DN 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 modifyDNProcessing;
      }
      try
      {
        if (newRDN == null)
        {
          newRDN = RDN.decode(rawNewRDN.stringValue());
        }
      }
      catch (DirectoryException de)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, de);
        }
        setResultCode(de.getResultCode());
        appendErrorMessage(de.getErrorMessage());
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      if (rawNewSuperior == null)
      {
        newSuperior = null;
      }
      else
      {
        try
        {
          if (newSuperior == null)
          {
            newSuperior = DN.decode(rawNewSuperior);
          }
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResultCode(de.getResultCode());
          appendErrorMessage(de.getErrorMessage());
          skipPostOperation = true;
          break modifyDNProcessing;
        }
      }
      // Construct the new DN to use for the entry.
      DN parentDN;
      if (newSuperior == null)
      {
        parentDN = entryDN.getParentDNInSuffix();
      }
      else
      {
        parentDN = newSuperior;
      }
      if ((parentDN == null) || parentDN.isNullDN())
      {
        setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        appendErrorMessage(getMessage(MSGID_MODDN_NO_PARENT,
                                      String.valueOf(entryDN)));
        break modifyDNProcessing;
      }
      DN newDN = parentDN.concat(newRDN);
      // Get the backend for the current entry, and the backend for the new
      // entry.  If either is null, or if they are different, then fail.
      Backend currentBackend = DirectoryServer.getBackend(entryDN);
      if (currentBackend == null)
      {
        setResultCode(ResultCode.NO_SUCH_OBJECT);
        appendErrorMessage(getMessage(MSGID_MODDN_NO_BACKEND_FOR_CURRENT_ENTRY,
                                      String.valueOf(entryDN)));
        break modifyDNProcessing;
      }
      Backend newBackend = DirectoryServer.getBackend(newDN);
      if (newBackend == null)
      {
        setResultCode(ResultCode.NO_SUCH_OBJECT);
        appendErrorMessage(getMessage(MSGID_MODDN_NO_BACKEND_FOR_NEW_ENTRY,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        break modifyDNProcessing;
      }
      else if (! currentBackend.equals(newBackend))
      {
        setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        appendErrorMessage(getMessage(MSGID_MODDN_DIFFERENT_BACKENDS,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        break modifyDNProcessing;
      }
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(this);
        return;
      }
      // Acquire write locks for the current and new DN.
      Lock currentLock = null;
      for (int i=0; i < 3; i++)
      {
        currentLock = LockManager.lockWrite(entryDN);
        if (currentLock != null)
        {
          break;
        }
      }
      if (currentLock == null)
      {
        setResultCode(DirectoryServer.getServerErrorResultCode());
        appendErrorMessage(getMessage(MSGID_MODDN_CANNOT_LOCK_CURRENT_DN,
                                      String.valueOf(entryDN)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      Lock newLock = null;
      try
      {
        for (int i=0; i < 3; i++)
        {
          newLock = LockManager.lockWrite(newDN);
          if (newLock != null)
          {
            break;
          }
        }
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        LockManager.unlock(entryDN, currentLock);
        if (newLock != null)
        {
          LockManager.unlock(newDN, newLock);
        }
        setResultCode(DirectoryServer.getServerErrorResultCode());
        appendErrorMessage(getMessage(MSGID_MODDN_EXCEPTION_LOCKING_NEW_DN,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN),
                                      getExceptionMessage(e)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      if (newLock == null)
      {
        LockManager.unlock(entryDN, currentLock);
        setResultCode(DirectoryServer.getServerErrorResultCode());
        appendErrorMessage(getMessage(MSGID_MODDN_CANNOT_LOCK_NEW_DN,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      try
      {
        // Check for and handle a request to cancel this operation.
        if (cancelRequest != null)
        {
          indicateCancelled(cancelRequest);
          setProcessingStopTime();
          logModifyDNResponse(this);
          pluginConfigManager.invokePostResponseModifyDNPlugins(this);
          return;
        }
        // Get the current entry from the appropriate backend.  If it doesn't
        // exist, then fail.
        try
        {
          currentEntry = currentBackend.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 modifyDNProcessing;
        }
        if (currentEntry == null)
        {
          // See if one of the entry's ancestors exists.
          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();
          }
          setResultCode(ResultCode.NO_SUCH_OBJECT);
          appendErrorMessage(getMessage(MSGID_MODDN_NO_CURRENT_ENTRY,
                                        String.valueOf(entryDN)));
          break modifyDNProcessing;
        }
        // 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 modifyDNProcessing;
            }
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            logError(ErrorLogCategory.SYNCHRONIZATION,
                     ErrorLogSeverity.SEVERE_ERROR,
                     MSGID_MODDN_SYNCH_CONFLICT_RESOLUTION_FAILED,
                     getConnectionID(), getOperationID(),
                     getExceptionMessage(de));
            setResponseData(de);
            break modifyDNProcessing;
          }
        }
        // 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 modifyDNProcessing;
                }
              }
              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_MODDN_ASSERTION_FAILED,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(ResultCode.PROTOCOL_ERROR);
                int msgID = MSGID_MODDN_CANNOT_PROCESS_ASSERTION_FILTER;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              de.getErrorMessage()));
                break modifyDNProcessing;
              }
            }
            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 modifyDNProcessing;
                }
              }
            }
            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 modifyDNProcessing;
                }
              }
            }
            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 modifyDNProcessing;
              }
              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 modifyDNProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(this,
                      authorizationEntry) == false) {
                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              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 modifyDNProcessing;
              }
              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 modifyDNProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(this,
                                                authorizationEntry) == false) {
                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              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_MODDN_UNSUPPORTED_CRITICAL_CONTROL;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              oid));
                break modifyDNProcessing;
              }
            }
          }
        }
        // Check to see if the client has permission to perform the
        // modify DN.
        // 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 or new superior
        // already exists may have already exposed sensitive information
        // to the client.
        if (AccessControlConfigManager.getInstance()
            .getAccessControlHandler().isAllowed(this) == false) {
          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
          int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
          appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
          skipPostOperation = true;
          break modifyDNProcessing;
        }
        // Duplicate the entry and set its new DN.  Also, create an empty list
        // to hold the attribute-level modifications.
        newEntry = currentEntry.duplicate(false);
        newEntry.setDN(newDN);
        modifications = new ArrayList<Modification>();
        // If we should delete the old RDN values from the entry, then do so.
        if (deleteOldRDN)
        {
          RDN currentRDN = entryDN.getRDN();
          int numValues  = currentRDN.getNumValues();
          for (int i=0; i < numValues; i++)
          {
            LinkedHashSet<AttributeValue> valueSet =
                 new LinkedHashSet<AttributeValue>(1);
            valueSet.add(currentRDN.getAttributeValue(i));
            Attribute a = new Attribute(currentRDN.getAttributeType(i),
                                        currentRDN.getAttributeName(i),
                                        valueSet);
            // If the associated attribute type is marked NO-USER-MODIFICATION,
            // then refuse the update.
            if (a.getAttributeType().isNoUserModification())
            {
              if (! (isInternalOperation() || isSynchronizationOperation()))
              {
                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                int msgID = MSGID_MODDN_OLD_RDN_ATTR_IS_NO_USER_MOD;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              a.getName()));
                break modifyDNProcessing;
              }
            }
            LinkedList<AttributeValue> missingValues =
                 new LinkedList<AttributeValue>();
            newEntry.removeAttribute(a, missingValues);
            if (missingValues.isEmpty())
            {
              modifications.add(new Modification(ModificationType.DELETE, a));
            }
          }
        }
        // Add the new RDN values to the entry.
        int newRDNValues = newRDN.getNumValues();
        for (int i=0; i < newRDNValues; i++)
        {
          LinkedHashSet<AttributeValue> valueSet =
               new LinkedHashSet<AttributeValue>(1);
          valueSet.add(newRDN.getAttributeValue(i));
          Attribute a = new Attribute(newRDN.getAttributeType(i),
                                      newRDN.getAttributeName(i),
                                      valueSet);
          LinkedList<AttributeValue> duplicateValues =
               new LinkedList<AttributeValue>();
          newEntry.addAttribute(a, duplicateValues);
          if (duplicateValues.isEmpty())
          {
            // If the associated attribute type is marked NO-USER-MODIFICATION,
            // then refuse the update.
            if (a.getAttributeType().isNoUserModification())
            {
              if (! (isInternalOperation() || isSynchronizationOperation()))
              {
                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                int msgID = MSGID_MODDN_NEW_RDN_ATTR_IS_NO_USER_MOD;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              a.getName()));
                break modifyDNProcessing;
              }
            }
            else
            {
              modifications.add(new Modification(ModificationType.ADD, a));
            }
          }
        }
        // If the server is configured to check the schema and the
        // operation is not a synchronization operation,
        // make sure that the resulting entry is valid as per the server schema.
        if ((DirectoryServer.checkSchema()) &&
            (!isSynchronizationOperation()) )
        {
          StringBuilder invalidReason = new StringBuilder();
          if (! newEntry.conformsToSchema(null, false, true, true,
                                          invalidReason))
          {
            setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
            appendErrorMessage(getMessage(MSGID_MODDN_VIOLATES_SCHEMA,
                                          String.valueOf(entryDN),
                                          String.valueOf(invalidReason)));
            break modifyDNProcessing;
          }
          for (int i=0; i < newRDNValues; i++)
          {
            AttributeType at = newRDN.getAttributeType(i);
            if (at.isObsolete())
            {
              setResultCode(ResultCode.CONSTRAINT_VIOLATION);
              appendErrorMessage(getMessage(MSGID_MODDN_NEWRDN_ATTR_IS_OBSOLETE,
                                            String.valueOf(entryDN),
                                            at.getNameOrOID()));
              break modifyDNProcessing;
            }
          }
        }
        // Check for and handle a request to cancel this operation.
        if (cancelRequest != null)
        {
          indicateCancelled(cancelRequest);
          setProcessingStopTime();
          logModifyDNResponse(this);
          pluginConfigManager.invokePostResponseModifyDNPlugins(this);
          return;
        }
        // Get a count of the current number of modifications.  The
        // pre-operation plugins may alter this list, and we need to be able to
        // identify which changes were made after they're done.
        int modCount = modifications.size();
        // If the operation is not a synchronization operation,
        // Invoke the pre-operation modify DN plugins.
        if (!isSynchronizationOperation())
        {
          PreOperationPluginResult preOpResult =
            pluginConfigManager.invokePreOperationModifyDNPlugins(this);
          if (preOpResult.connectionTerminated())
          {
            // There's no point in continuing with anything.  Log the request
            // and result and return.
            setResultCode(ResultCode.CANCELED);
            int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
            appendErrorMessage(getMessage(msgID));
            setProcessingStopTime();
            logModifyDNResponse(this);
            pluginConfigManager.invokePostResponseModifyDNPlugins(this);
            return;
          }
          else if (preOpResult.sendResponseImmediately())
          {
            skipPostOperation = true;
            break modifyDNProcessing;
          }
          else if (preOpResult.skipCoreProcessing())
          {
            skipPostOperation = false;
            break modifyDNProcessing;
          }
        }
        // Check to see if any of the pre-operation plugins made any changes to
        // the entry.  If so, then apply them.
        if (modifications.size() > modCount)
        {
          for (int i=modCount; i < modifications.size(); i++)
          {
            Modification m = modifications.get(i);
            Attribute    a = m.getAttribute();
            switch (m.getModificationType())
            {
              case ADD:
                LinkedList<AttributeValue> duplicateValues =
                     new LinkedList<AttributeValue>();
                newEntry.addAttribute(a, duplicateValues);
                break;
              case DELETE:
                LinkedList<AttributeValue> missingValues =
                     new LinkedList<AttributeValue>();
                newEntry.removeAttribute(a, missingValues);
                break;
              case REPLACE:
                duplicateValues = new LinkedList<AttributeValue>();
                newEntry.removeAttribute(a.getAttributeType(), a.getOptions());
                newEntry.addAttribute(a, duplicateValues);
                break;
              case INCREMENT:
                List<Attribute> attrList =
                     newEntry.getAttribute(a.getAttributeType(),
                                           a.getOptions());
                if ((attrList == null) || attrList.isEmpty())
                {
                  setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_ATTR;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (attrList.size() > 1)
                {
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_VALUES;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                LinkedHashSet<AttributeValue> values =
                     attrList.get(0).getValues();
                if ((values == null) || values.isEmpty())
                {
                  setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_ATTR;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (values.size() > 1)
                {
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_VALUES;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long currentLongValue;
                try
                {
                  AttributeValue v = values.iterator().next();
                  currentLongValue = Long.parseLong(v.getStringValue());
                }
                catch (Exception e)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
                  }
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_VALUE_NOT_INTEGER;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                LinkedHashSet<AttributeValue> newValues = a.getValues();
                if ((newValues == null) || newValues.isEmpty())
                {
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_AMOUNT;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (newValues.size() > 1)
                {
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_AMOUNTS;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long incrementAmount;
                try
                {
                  AttributeValue v = values.iterator().next();
                  incrementAmount = Long.parseLong(v.getStringValue());
                }
                catch (Exception e)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
                  }
                  setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_AMOUNT_NOT_INTEGER;
                  appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long newLongValue = currentLongValue + incrementAmount;
                ByteString newValueOS =
                     new ASN1OctetString(String.valueOf(newLongValue));
                newValues = new LinkedHashSet<AttributeValue>(1);
                newValues.add(new AttributeValue(a.getAttributeType(),
                                                 newValueOS));
                List<Attribute> newAttrList = new ArrayList<Attribute>(1);
                newAttrList.add(new Attribute(a.getAttributeType(),
                                              a.getName(), newValues));
                newEntry.putAttribute(a.getAttributeType(), newAttrList);
                break;
            }
          }
          // Make sure that the updated entry still conforms to the server
          // schema.
          if (DirectoryServer.checkSchema())
          {
            StringBuilder invalidReason = new StringBuilder();
            if (! newEntry.conformsToSchema(null, false, true, true,
                                            invalidReason))
            {
              setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
              appendErrorMessage(getMessage(MSGID_MODDN_PREOP_VIOLATES_SCHEMA,
                                            String.valueOf(entryDN),
                                            String.valueOf(invalidReason)));
              break modifyDNProcessing;
            }
          }
        }
        // Check for and handle a request to cancel this operation.
        if (cancelRequest != null)
        {
          indicateCancelled(cancelRequest);
          setProcessingStopTime();
          logModifyDNResponse(this);
          pluginConfigManager.invokePostResponseModifyDNPlugins(this);
          return;
        }
        // Actually perform the modify DN operation.  This should include taking
        // care of any synchronization that might be needed.
        try
        {
          // If it is not a private backend, then check to see if the server or
          // backend is operating in read-only mode.
          if (! currentBackend.isPrivateBackend())
          {
            switch (DirectoryServer.getWritabilityMode())
            {
              case DISABLED:
                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                appendErrorMessage(getMessage(MSGID_MODDN_SERVER_READONLY,
                                              String.valueOf(entryDN)));
                break modifyDNProcessing;
              case INTERNAL_ONLY:
                if (! (isInternalOperation() || isSynchronizationOperation()))
                {
                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                  appendErrorMessage(getMessage(MSGID_MODDN_SERVER_READONLY,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
            }
            switch (currentBackend.getWritabilityMode())
            {
              case DISABLED:
                setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                appendErrorMessage(getMessage(MSGID_MODDN_BACKEND_READONLY,
                                              String.valueOf(entryDN)));
                break modifyDNProcessing;
              case INTERNAL_ONLY:
                if (! (isInternalOperation() || isSynchronizationOperation()))
                {
                  setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                  appendErrorMessage(getMessage(MSGID_MODDN_BACKEND_READONLY,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
            }
          }
          if (noOp)
          {
            appendErrorMessage(getMessage(MSGID_MODDN_NOOP));
            setResultCode(ResultCode.NO_OPERATION);
          }
          else
          {
            for (SynchronizationProvider provider :
                 DirectoryServer.getSynchronizationProviders())
            {
              try
              {
                SynchronizationProviderResult result =
                     provider.doPreOperation(this);
                if (! result.continueOperationProcessing())
                {
                  break modifyDNProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                logError(ErrorLogCategory.SYNCHRONIZATION,
                         ErrorLogSeverity.SEVERE_ERROR,
                         MSGID_MODDN_SYNCH_PREOP_FAILED, getConnectionID(),
                         getOperationID(), getExceptionMessage(de));
                setResponseData(de);
                break modifyDNProcessing;
              }
            }
            currentBackend.renameEntry(entryDN, newEntry, this);
          }
          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 = newEntry.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);
          }
          if (! noOp)
          {
            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 modifyDNProcessing;
        }
        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 modifyDNProcessing;
        }
      }
      finally
      {
        LockManager.unlock(entryDN, currentLock);
        LockManager.unlock(newDN, newLock);
        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_MODDN_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 DN plugins.
    if (! skipPostOperation)
    {
      PostOperationPluginResult postOperationResult =
           pluginConfigManager.invokePostOperationModifyDNPlugins(this);
      if (postOperationResult.connectionTerminated())
      {
        setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_POSTOP_DISCONNECT;
        appendErrorMessage(getMessage(msgID));
        setProcessingStopTime();
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(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.handleModifyDNOperation(this, currentEntry, newEntry);
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          int    msgID   = MSGID_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER;
          String message = getMessage(msgID, getExceptionMessage(e));
          logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
                   message, msgID);
        }
      }
    }
    // Stop the processing timer.
    setProcessingStopTime();
    // Send the modify DN response to the client.
    clientConnection.sendResponse(this);
    // Log the modify DN response.
    logModifyDNResponse(this);
    // Notify any persistent searches that might be registered with the server.
    if (getResultCode() == ResultCode.SUCCESS)
    {
      for (PersistentSearch persistentSearch :
           DirectoryServer.getPersistentSearches())
      {
        try
        {
          persistentSearch.processModifyDN(this, currentEntry, newEntry);
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          int    msgID   = MSGID_MODDN_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 DN plugins.
    pluginConfigManager.invokePostResponseModifyDNPlugins(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()
  public boolean setCancelRequest(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    buffer.append("ModifyDNOperation(connID=");
    buffer.append(clientConnection.getConnectionID());
    buffer.append(", opID=");
    buffer.append(operationID);
    buffer.append(", dn=");
    buffer.append(rawEntryDN);
    buffer.append(", newRDN=");
    buffer.append(rawNewRDN);
    buffer.append(", deleteOldRDN=");
    buffer.append(deleteOldRDN);
    if (rawNewSuperior != null)
    {
      buffer.append(", newSuperior=");
      buffer.append(rawNewSuperior);
    }
    buffer.append(")");
  }
  public void setProxiedAuthorizationDN(DN dn);
}
opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
New file
@@ -0,0 +1,952 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PreParsePluginResult;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.types.AbstractOperation;
import org.opends.server.types.ByteString;
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.Modification;
import org.opends.server.types.Operation;
import org.opends.server.types.OperationType;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PreParseModifyDNOperation;
import static org.opends.server.core.CoreConstants.*;
import static org.opends.server.loggers.AccessLogger.*;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.workflowelement.localbackend.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import 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.StaticUtils.*;
/**
 * This class defines an operation that may be used to alter the DN of an entry
 * in the Directory Server.
 */
public class ModifyDNOperationBasis
       extends AbstractOperation
       implements ModifyDNOperation,
                  PreParseModifyDNOperation,
                  PostResponseModifyDNOperation
                  {
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = DebugLogger.getTracer();
  // Indicates whether to delete the old RDN value from the entry.
  private boolean deleteOldRDN;
  // The raw, unprocessed current DN of the entry as included in the request
  // from the client.
  private ByteString rawEntryDN;
  // The raw, unprocessed newRDN as included in the request from the client.
  private ByteString rawNewRDN;
  // The raw, unprocessed newSuperior as included in the request from the
  // client.
  private ByteString rawNewSuperior;
  // The cancel request issued for this modify DN operation.
  private CancelRequest cancelRequest;
  // The current DN of the entry.
  private DN entryDN;
  // The new parent for the entry.
  private DN newSuperior;
  // The proxied authorization target DN for this operation.
  private DN proxiedAuthorizationDN;
  // The set of response controls for this modify DN operation.
  private List<Control> responseControls;
  // The set of modifications applied to attributes in the entry in the course
  // of processing the modify DN.
  private List<Modification> modifications;
  // The change number that has been assigned to this operation.
  private long changeNumber;
  // The new RDN for the entry.
  private RDN newRDN;
  // The new entry DN
  private DN newDN = null;
  /**
   * Creates a new modify DN 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 entry DN as included in the
   *                           client request.
   * @param  rawNewRDN         The raw, unprocessed newRDN as included in the
   *                           client request.
   * @param  deleteOldRDN      Indicates whether to delete the old RDN value
   *                           from the entry.
   * @param  rawNewSuperior    The raw, unprocessed newSuperior as included in
   *                           the client request.
   */
  public ModifyDNOperationBasis(ClientConnection clientConnection,
      long operationID,
      int messageID, List<Control> requestControls,
      ByteString rawEntryDN, ByteString rawNewRDN,
      boolean deleteOldRDN, ByteString rawNewSuperior)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.rawEntryDN      = rawEntryDN;
    this.rawNewRDN       = rawNewRDN;
    this.deleteOldRDN    = deleteOldRDN;
    this.rawNewSuperior  = rawNewSuperior;
    entryDN          = null;
    newRDN           = null;
    newSuperior      = null;
    responseControls = new ArrayList<Control>();
    cancelRequest    = null;
    modifications    = null;
    changeNumber     = -1;
  }
  /**
   * Creates a new modify DN 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 current entry DN for this modify DN
   *                           operation.
   * @param  newRDN            The new RDN for this modify DN operation.
   * @param  deleteOldRDN      Indicates whether to delete the old RDN value
   *                           from the entry.
   * @param  newSuperior       The newSuperior DN for this modify DN operation.
   */
  public ModifyDNOperationBasis(ClientConnection clientConnection,
      long operationID,
      int messageID, List<Control> requestControls,
      DN entryDN, RDN newRDN, boolean deleteOldRDN,
      DN newSuperior)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.entryDN      = entryDN;
    this.newRDN       = newRDN;
    this.deleteOldRDN = deleteOldRDN;
    this.newSuperior  = newSuperior;
    rawEntryDN = new ASN1OctetString(entryDN.toString());
    rawNewRDN  = new ASN1OctetString(newRDN.toString());
    if (newSuperior == null)
    {
      rawNewSuperior = null;
    }
    else
    {
      rawNewSuperior = new ASN1OctetString(newSuperior.toString());
    }
    responseControls = new ArrayList<Control>();
    cancelRequest    = null;
    modifications    = null;
    changeNumber     = -1;
  }
  /**
   * {@inheritDoc}
   */
  public final ByteString getRawEntryDN()
  {
    return rawEntryDN;
  }
  /**
   * {@inheritDoc}
   */
  public final void setRawEntryDN(ByteString rawEntryDN)
  {
    this.rawEntryDN = rawEntryDN;
    entryDN = null;
  }
  /**
   * {@inheritDoc}
   */
  public final DN getEntryDN()
  {
    try
    {
      if (entryDN == null)
      {
        entryDN = DN.decode(rawEntryDN);
      }
    }
    catch (DirectoryException de)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }
      setResultCode(de.getResultCode());
      appendErrorMessage(de.getErrorMessage());
    }
    return entryDN;
  }
  /**
   * {@inheritDoc}
   */
  public final ByteString getRawNewRDN()
  {
    return rawNewRDN;
  }
  /**
   * {@inheritDoc}
   */
  public final void setRawNewRDN(ByteString rawNewRDN)
  {
    this.rawNewRDN = rawNewRDN;
    newRDN = null;
    newDN = null;
  }
  /**
   * {@inheritDoc}
   */
  public final RDN getNewRDN()
  {
    try
    {
      if (newRDN == null)
      {
        newRDN = RDN.decode(rawNewRDN.stringValue());
      }
    }
    catch (DirectoryException de)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, de);
      }
      setResultCode(de.getResultCode());
      appendErrorMessage(de.getErrorMessage());
    }
    return newRDN;
  }
  /**
   * {@inheritDoc}
   */
  public final boolean deleteOldRDN()
  {
    return deleteOldRDN;
  }
  /**
   * {@inheritDoc}
   */
  public final void setDeleteOldRDN(boolean deleteOldRDN)
  {
    this.deleteOldRDN = deleteOldRDN;
  }
  /**
   * {@inheritDoc}
   */
  public final ByteString getRawNewSuperior()
  {
    return rawNewSuperior;
  }
  /**
   * {@inheritDoc}
   */
  public final void setRawNewSuperior(ByteString rawNewSuperior)
  {
    this.rawNewSuperior = rawNewSuperior;
    newSuperior = null;
    newDN = null;
  }
  /**
   * {@inheritDoc}
   */
  public final DN getNewSuperior()
  {
    if (rawNewSuperior == null)
    {
      newSuperior = null;
    }
    else
    {
      try
      {
        if (newSuperior == null)
        {
          newSuperior = DN.decode(rawNewSuperior);
        }
      }
      catch (DirectoryException de)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, de);
        }
        setResultCode(de.getResultCode());
        appendErrorMessage(de.getErrorMessage());
      }
    }
    return newSuperior;
  }
  /**
   * {@inheritDoc}
   */
  public final List<Modification> getModifications()
  {
    return modifications;
  }
  /**
   * {@inheritDoc}
   */
  public final void addModification(Modification modification)
  {
    if (modifications == null)
    {
      modifications = new ArrayList<Modification>();
    }
    if (modification != null)
    {
      modifications.add(modification);
    }
  }
  /**
   * {@inheritDoc}
   */
  public final Entry getOriginalEntry()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  public final Entry getUpdatedEntry()
  {
    return null;
  }
  /**
   * {@inheritDoc}
   */
  public final long getChangeNumber()
  {
    return changeNumber;
  }
  /**
   * {@inheritDoc}
   */
  public final void setChangeNumber(long changeNumber)
  {
    this.changeNumber = changeNumber;
  }
  /**
   * {@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_DN;
  }
  /**
   * {@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 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.
    String newSuperiorStr;
    if (rawNewSuperior == null)
    {
      newSuperiorStr = null;
    }
    else
    {
      newSuperiorStr = rawNewSuperior.stringValue();
    }
    return new String[][]
                        {
        new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) },
        new String[] { LOG_ELEMENT_NEW_RDN, String.valueOf(newRDN) },
        new String[] { LOG_ELEMENT_DELETE_OLD_RDN,
            String.valueOf(deleteOldRDN) },
        new String[] { LOG_ELEMENT_NEW_SUPERIOR, newSuperiorStr }
                        };
  }
  /**
   * {@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(getProcessingTime());
    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 }
                        };
  }
  /**
   * {@inheritDoc}
   */
  public DN getProxiedAuthorizationDN()
  {
    return proxiedAuthorizationDN;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final List<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);
  }
  /**
   * Performs the work of actually processing this operation.  This
   * should include all processing for the operation, including
   * invoking plugins, logging messages, performing access control,
   * managing synchronization, and any other work that might need to
   * be done in the course of processing.
   */
  public final void run()
  {
    setResultCode(ResultCode.UNDEFINED);
    boolean workflowExecuted = false;
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
      DirectoryServer.getPluginConfigManager();
    // Start the processing timer.
    setProcessingStartTime();
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      return;
    }
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
    modifyDNProcessing:
    {
      // Invoke the pre-parse modify DN plugins.
      PreParsePluginResult preParseResult =
        pluginConfigManager.invokePreParseModifyDNPlugins(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));
        setProcessingStopTime();
        logModifyDNRequest(this);
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(this);
        return;
      }
      else if (preParseResult.sendResponseImmediately())
      {
        logModifyDNRequest(this);
        break modifyDNProcessing;
      }
      else if (preParseResult.skipCoreProcessing())
      {
        break modifyDNProcessing;
      }
      // Log the modify DN request message.
      logModifyDNRequest(this);
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logModifyDNResponse(this);
        pluginConfigManager.invokePostResponseModifyDNPlugins(this);
        return;
      }
      // Process the entry DN, newRDN, and newSuperior elements from their raw
      // forms as provided by the client to the forms required for the rest of
      // the modify DN processing.
      DN entryDN = getEntryDN();
      if (entryDN == null)
      {
        break modifyDNProcessing;
      }
      // Retrieve the network group attached to the client connection
      // and get a workflow to process the operation.
      NetworkGroup ng = getClientConnection().getNetworkGroup();
      Workflow workflow = ng.getWorkflowCandidate(entryDN);
      if (workflow == null)
      {
        // We have found no workflow for the requested base DN, just return
        // a no such entry result code and stop the processing.
        updateOperationErrMsgAndResCode();
        break modifyDNProcessing;
      }
      workflow.execute(this);
      workflowExecuted = true;
    }
    // Check for and handle a request to cancel this operation.
    if ((getCancelRequest() != null) ||
        (getCancelResult() == CancelResult.CANCELED))
    {
      if (getCancelRequest() != null){
        indicateCancelled(getCancelRequest());
      }
      setProcessingStopTime();
      logModifyDNResponse(this);
      invokePostResponsePlugins();
      return;
    }
    // Stop the processing timer.
    setProcessingStopTime();
    // Send the modify DN response to the client.
    clientConnection.sendResponse(this);
    // Log the modify DN response.
    logModifyDNResponse(this);
    // If a workflow has been executed to process the operation, then
    // call the post response plugins against the operations attached
    // to this operation.
    if (workflowExecuted)
    {
      // Check wether there are local operations in attachments
      List localOperations =
        (List)getAttachment(Operation.LOCALBACKENDOPERATIONS);
      if (localOperations != null && (! localOperations.isEmpty())){
        for (Object localOperation : localOperations)
        {
          LocalBackendModifyDNOperation localOp =
            (LocalBackendModifyDNOperation)localOperation;
          // Notify any persistent searches that might be registered with
          // the server.
          if (getResultCode() == ResultCode.SUCCESS)
          {
            for (PersistentSearch persistentSearch :
              DirectoryServer.getPersistentSearches())
            {
              try
              {
                persistentSearch.processModifyDN(
                    localOp,
                    localOp.getOriginalEntry(),
                    localOp.getUpdatedEntry());
              }
              catch (Exception e)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
                }
                int    msgID   = MSGID_MODDN_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 DN plugins.
          pluginConfigManager.invokePostResponseModifyDNPlugins(localOp);
        }
      }
    }
    else {
      // Invoke the post-response modify DN plugins.
      pluginConfigManager.invokePostResponseModifyDNPlugins(this);
    }
  }
  /**
   * Updates the error message and the result code of the operation.
   *
   * This method is called because no workflows were found to process
   * the operation.
   */
  private void updateOperationErrMsgAndResCode()
  {
    setResultCode(ResultCode.NO_SUCH_OBJECT);
    appendErrorMessage(getMessage(MSGID_MODDN_NO_BACKEND_FOR_CURRENT_ENTRY,
        String.valueOf(entryDN)));
  }
  /**
   * {@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()
  public boolean setCancelRequest(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    buffer.append("ModifyDNOperation(connID=");
    buffer.append(clientConnection.getConnectionID());
    buffer.append(", opID=");
    buffer.append(operationID);
    buffer.append(", dn=");
    buffer.append(rawEntryDN);
    buffer.append(", newRDN=");
    buffer.append(rawNewRDN);
    buffer.append(", deleteOldRDN=");
    buffer.append(deleteOldRDN);
    if (rawNewSuperior != null)
    {
      buffer.append(", newSuperior=");
      buffer.append(rawNewSuperior);
    }
    buffer.append(")");
  }
  /**
   * {@inheritDoc}
   */
  public void setProxiedAuthorizationDN(DN dn)
  {
    proxiedAuthorizationDN = dn;
  }
  /**
   * Execute the postResponseModifyPlugins.
   */
  private void invokePostResponsePlugins()
  {
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
      DirectoryServer.getPluginConfigManager();
    // Check wether there are local operations in attachments
    List localOperations =
      (List)getAttachment(Operation.LOCALBACKENDOPERATIONS);
    if (localOperations != null && (! localOperations.isEmpty())){
      for (Object localOp : localOperations)
      {
        LocalBackendModifyDNOperation localOperation =
          (LocalBackendModifyDNOperation)localOp;
        // Invoke the post-response add plugins.
        pluginConfigManager.invokePostResponseModifyDNPlugins(localOperation);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public DN getNewDN()
  {
    if (newDN == null)
    {
      // Construct the new DN to use for the entry.
      DN parentDN = null;
      if (newSuperior == null)
      {
        if (getEntryDN() != null)
        {
          parentDN = entryDN.getParentDNInSuffix();
        }
      }
      else
      {
        parentDN = newSuperior;
      }
      if ((parentDN == null) || parentDN.isNullDN())
      {
        setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        appendErrorMessage(getMessage(MSGID_MODDN_NO_PARENT,
            String.valueOf(entryDN)));
      }
      newDN = parentDN.concat(newRDN);
    }
    return newDN;
  }
}
opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
New file
@@ -0,0 +1,199 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import java.util.List;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.RDN;
/**
 * This abstract class wraps/decorates a given moddn operation.
 * This class will be extended by sub-classes to enhance the
 * functionnality of the ModifyDNOperationBasis.
 */
public abstract class ModifyDNOperationWrapper
  extends OperationWrapper
  implements ModifyDNOperation
{
  ModifyDNOperation modifyDN;
  /**
   * Creates a new moddn operation based on the provided moddn operation.
   *
   * @param modifyDN The moddn operation to wrap
   */
  public ModifyDNOperationWrapper(ModifyDNOperation modifyDN)
  {
    super(modifyDN);
    this.modifyDN = modifyDN;
  }
  /**
   * {@inheritDoc}
   */
  public void addModification(Modification modification) {
    modifyDN.addModification(modification);
  }
  /**
   * {@inheritDoc}
   */
  public boolean deleteOldRDN() {
    return modifyDN.deleteOldRDN();
  }
  /**
   * {@inheritDoc}
   */
  public long getChangeNumber() {
    return modifyDN.getChangeNumber();
  }
  /**
   * {@inheritDoc}
   */
  public DN getEntryDN() {
    return modifyDN.getEntryDN();
  }
  /**
   * {@inheritDoc}
   */
  public List<Modification> getModifications() {
    return modifyDN.getModifications();
  }
  /**
   * {@inheritDoc}
   */
  public RDN getNewRDN() {
    return modifyDN.getNewRDN();
  }
  /**
   * {@inheritDoc}
   */
  public DN getNewSuperior() {
    return modifyDN.getNewSuperior();
  }
  /**
   * {@inheritDoc}
   */
  public Entry getOriginalEntry() {
    return modifyDN.getOriginalEntry();
  }
  /**
   * {@inheritDoc}
   */
  public DN getProxiedAuthorizationDN() {
    return modifyDN.getProxiedAuthorizationDN();
  }
  /**
   * {@inheritDoc}
   */
  public ByteString getRawEntryDN() {
    return modifyDN.getRawEntryDN();
  }
  /**
   * {@inheritDoc}
   */
  public ByteString getRawNewRDN() {
    return modifyDN.getRawNewRDN();
  }
  /**
   * {@inheritDoc}
   */
  public ByteString getRawNewSuperior() {
    return modifyDN.getRawNewSuperior();
  }
  /**
   * {@inheritDoc}
   */
  public Entry getUpdatedEntry() {
    return modifyDN.getUpdatedEntry();
  }
  /**
   * {@inheritDoc}
   */
  public void setChangeNumber(long changeNumber) {
    modifyDN.setChangeNumber(changeNumber);
  }
  /**
   * {@inheritDoc}
   */
  public void setDeleteOldRDN(boolean deleteOldRDN) {
    modifyDN.setDeleteOldRDN(deleteOldRDN);
  }
  /**
   * {@inheritDoc}
   */
  public void setRawEntryDN(ByteString rawEntryDN) {
    modifyDN.setRawEntryDN(rawEntryDN);
  }
  /**
   * {@inheritDoc}
   */
  public void setRawNewRDN(ByteString rawNewRDN) {
    modifyDN.setRawNewRDN(rawNewRDN);
  }
  /**
   * {@inheritDoc}
   */
  public void setRawNewSuperior(ByteString rawNewSuperior) {
    modifyDN.setRawNewSuperior(rawNewSuperior);
  }
  /**
   * {@inheritDoc}
   */
  public void setProxiedAuthorizationDN(DN dn)
  {
    modifyDN.setProxiedAuthorizationDN(dn);
  }
  /**
   * {@inheritDoc}
   */
  public DN getNewDN()
  {
    return modifyDN.getNewDN();
  }
}
opends/src/server/org/opends/server/core/PersistentSearch.java
@@ -532,7 +532,7 @@
   * @param  oldEntry           The entry before the modify DN.
   * @param  newEntry           The entry after the modify DN.
   */
  public void processModifyDN(ModifyDNOperation modifyDNOperation,
  public void processModifyDN(LocalBackendModifyDNOperation modifyDNOperation,
                              Entry oldEntry, Entry newEntry)
  {
    // See if we care about modify DN operations.
opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -84,18 +84,21 @@
import org.opends.server.types.operation.PostOperationBindOperation;
import org.opends.server.types.operation.PostOperationCompareOperation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostOperationSearchOperation;
import org.opends.server.types.operation.PostResponseAddOperation;
import org.opends.server.types.operation.PostResponseBindOperation;
import org.opends.server.types.operation.PostResponseCompareOperation;
import org.opends.server.types.operation.PostResponseDeleteOperation;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PostResponseModifyOperation;
import org.opends.server.types.operation.PostResponseSearchOperation;
import org.opends.server.types.operation.PreOperationAddOperation;
import org.opends.server.types.operation.PreOperationBindOperation;
import org.opends.server.types.operation.PreOperationCompareOperation;
import org.opends.server.types.operation.PreOperationDeleteOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyOperation;
import org.opends.server.types.operation.PreOperationSearchOperation;
import org.opends.server.types.operation.PreParseAddOperation;
@@ -2303,7 +2306,7 @@
   * @return  The result of processing the pre-parse modify DN plugins.
   */
  public PreParsePluginResult invokePreParseModifyDNPlugins(
                                   ModifyDNOperation modifyDNOperation)
                                   ModifyDNOperationBasis modifyDNOperation)
  {
    PreParsePluginResult result = null;
@@ -3037,7 +3040,7 @@
   * @return  The result of processing the pre-operation modify DN plugins.
   */
  public PreOperationPluginResult invokePreOperationModifyDNPlugins(
                                       ModifyDNOperation modifyDNOperation)
                              PreOperationModifyDNOperation modifyDNOperation)
  {
    PreOperationPluginResult result = null;
@@ -3771,7 +3774,7 @@
   * @return  The result of processing the post-operation modify DN plugins.
   */
  public PostOperationPluginResult invokePostOperationModifyDNPlugins(
                                        ModifyDNOperation modifyDNOperation)
                             PostOperationModifyDNOperation modifyDNOperation)
  {
    PostOperationPluginResult result = null;
@@ -4461,7 +4464,7 @@
   * @return  The result of processing the post-response modify DN plugins.
   */
  public PostResponsePluginResult invokePostResponseModifyDNPlugins(
                                       ModifyDNOperation modifyDNOperation)
                               PostResponseModifyDNOperation modifyDNOperation)
  {
    PostResponsePluginResult result = null;
opends/src/server/org/opends/server/loggers/AccessLogger.java
@@ -710,7 +710,8 @@
   * @param  modifyDNOperation  The modify DN operation containing the
   *                            information to use to log the modify DN request.
   */
  public static void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
  public static void logModifyDNRequest(ModifyDNOperationBasis
      modifyDNOperation)
  {
    for (AccessLogPublisher publisher : accessPublishers)
    {
@@ -728,7 +729,8 @@
   *                            information to use to log the modify DN
   *                            response.
   */
  public static void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
  public static void logModifyDNResponse(ModifyDNOperationBasis
      modifyDNOperation)
  {
    for (AccessLogPublisher publisher : accessPublishers)
    {
opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -44,7 +44,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.SearchOperation;
import org.opends.server.core.UnbindOperation;
import org.opends.server.types.*;
@@ -1369,7 +1369,7 @@
   * @param  modifyDNOperation  The modify DN operation containing the
   *                            info to use to log the modify DN request.
   */
  public void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
  public void logModifyDNRequest(ModifyDNOperationBasis modifyDNOperation)
  {
    long connectionID = modifyDNOperation.getConnectionID();
    if (connectionID < 0)
@@ -1430,7 +1430,7 @@
   *                            information to use to log the modify DN
   *                            response.
   */
  public void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
  public void logModifyDNResponse(ModifyDNOperationBasis modifyDNOperation)
  {
    long connectionID = modifyDNOperation.getConnectionID();
    if (connectionID < 0)
opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
@@ -43,7 +43,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.SearchOperation;
import org.opends.server.core.UnbindOperation;
import org.opends.server.types.*;
@@ -738,7 +738,7 @@
   * {@inheritDoc}
   */
  @Override()
  public void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
  public void logModifyDNRequest(ModifyDNOperationBasis modifyDNOperation)
  {
  }
@@ -748,7 +748,7 @@
   * {@inheritDoc}
   */
  @Override()
  public void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
  public void logModifyDNResponse(ModifyDNOperationBasis modifyDNOperation)
  {
    long connectionID = modifyDNOperation.getConnectionID();
    if (connectionID < 0)
opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -1183,7 +1183,7 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(String rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(String rawEntryDN,
                                           String rawNewRDN,
                                           boolean deleteOldRDN)
  {
@@ -1207,7 +1207,7 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(ByteString rawEntryDN,
                                           ByteString rawNewRDN,
                                           boolean deleteOldRDN)
  {
@@ -1232,7 +1232,7 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(String rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(String rawEntryDN,
                                           String rawNewRDN,
                                           boolean deleteOldRDN,
                                           String rawNewSuperior)
@@ -1261,13 +1261,13 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(ByteString rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(ByteString rawEntryDN,
                                           ByteString rawNewRDN,
                                           boolean deleteOldRDN,
                                           ByteString rawNewSuperior)
  {
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(this, nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(),
                               nextMessageID(),
                               new ArrayList<Control>(0), rawEntryDN,
                               rawNewRDN, deleteOldRDN,
@@ -1293,7 +1293,8 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(DN entryDN, RDN newRDN,
  public ModifyDNOperationBasis processModifyDN(DN entryDN,
                                           RDN newRDN,
                                           boolean deleteOldRDN)
  {
    return processModifyDN(entryDN, newRDN, deleteOldRDN, null);
@@ -1317,12 +1318,13 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(DN entryDN, RDN newRDN,
  public ModifyDNOperationBasis processModifyDN(DN entryDN,
                                           RDN newRDN,
                                           boolean deleteOldRDN,
                                           DN newSuperior)
  {
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(this, nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(),
                               nextMessageID(),
                               new ArrayList<Control>(0), entryDN,
                               newRDN, deleteOldRDN, newSuperior);
opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -744,7 +744,7 @@
   * @return  A reference to the modify DN operation that was processed and
   *          contains information about the result of the processing.
   */
  public ModifyDNOperation processModifyDN(ASN1OctetString rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(ASN1OctetString rawEntryDN,
                                           ASN1OctetString rawNewRDN,
                                           boolean deleteOldRDN)
  {
@@ -767,13 +767,13 @@
   * @return  A reference to the modify DN operation that was processed and
   *          contains information about the result of the processing.
   */
  public ModifyDNOperation processModifyDN(ASN1OctetString rawEntryDN,
  public ModifyDNOperationBasis processModifyDN(ASN1OctetString rawEntryDN,
                                           ASN1OctetString rawNewRDN,
                                           boolean deleteOldRDN,
                                           ASN1OctetString rawNewSuperior)
  {
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(this, nextOperationID(), nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(), nextMessageID(),
                               new ArrayList<Control>(0), rawEntryDN, rawNewRDN,
                               deleteOldRDN, rawNewSuperior);
@@ -807,12 +807,12 @@
   *          processed and contains information about the result of
   *          the processing.
   */
  public ModifyDNOperation processModifyDN(DN entryDN, RDN newRDN,
  public ModifyDNOperationBasis processModifyDN(DN entryDN, RDN newRDN,
                                           boolean deleteOldRDN,
                                           DN newSuperior)
  {
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(this, nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(this, nextOperationID(),
                               nextMessageID(),
                               new ArrayList<Control>(0), entryDN,
                               newRDN, deleteOldRDN, newSuperior);
opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -60,7 +60,7 @@
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.core.PersistentSearch;
import org.opends.server.core.PluginConfigManager;
@@ -2319,8 +2319,8 @@
    ModifyDNRequestProtocolOp protocolOp =
         message.getModifyDNRequestProtocolOp();
    ModifyDNOperation modifyDNOp =
         new ModifyDNOperation(this, nextOperationID.getAndIncrement(),
    ModifyDNOperationBasis modifyDNOp =
         new ModifyDNOperationBasis(this, nextOperationID.getAndIncrement(),
                               message.getMessageID(), controls,
                               protocolOp.getEntryDN(), protocolOp.getNewRDN(),
                               protocolOp.deleteOldRDN(),
opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java
@@ -66,7 +66,7 @@
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.LockFileManager;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.asn1.ASN1Exception;
@@ -1243,13 +1243,13 @@
              done = solveNamingConflict(newOp, addMsg);
            }
          }
          else if (op instanceof ModifyDNOperation)
          else if (op instanceof ModifyDNOperationBasis)
          {
            ModifyDNMsg newMsg = (ModifyDNMsg) msg;
            dependency = remotePendingChanges.checkDependencies(newMsg);
            if (!dependency)
            {
              ModifyDNOperation newOp = (ModifyDNOperation) op;
              ModifyDNOperationBasis newOp = (ModifyDNOperationBasis) op;
              done = solveNamingConflict(newOp, msg);
            }
          }
@@ -1570,7 +1570,7 @@
 * @return true if the process is completed, false if it must continue.
 * @throws Exception When the operation is not valid.
 */
private boolean solveNamingConflict(ModifyDNOperation op,
private boolean solveNamingConflict(ModifyDNOperationBasis op,
    UpdateMessage msg) throws Exception
{
  ResultCode result = op.getResultCode();
@@ -1843,7 +1843,7 @@
    InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
    ModifyDNOperation newOp = conn.processModifyDN(
    ModifyDNOperationBasis newOp = conn.processModifyDN(
        dn, generateDeleteConflictDn(uid, dn),false, baseDN);
    if (newOp.getResultCode() != ResultCode.SUCCESS)
opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
@@ -31,7 +31,7 @@
import java.io.UnsupportedEncodingException;
import java.util.zip.DataFormatException;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.common.ChangeNumber;
@@ -153,7 +153,7 @@
  public AbstractOperation createOperation(
         InternalClientConnection connection, String newDn)
  {
    ModifyDNOperation moddn =  new ModifyDNOperation(connection,
    ModifyDNOperationBasis moddn =  new ModifyDNOperationBasis(connection,
               InternalClientConnection.nextOperationID(),
               InternalClientConnection.nextMessageID(), null,
               new ASN1OctetString(newDn), new ASN1OctetString(newRDN),
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
New file
@@ -0,0 +1,117 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.workflowelement.localbackend;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationWrapper;
import org.opends.server.types.Entry;
import org.opends.server.types.operation.PostOperationModifyDNOperation;
import org.opends.server.types.operation.PostResponseModifyDNOperation;
import org.opends.server.types.operation.PreOperationModifyDNOperation;
/**
 * This class defines an operation used to move an entry in a local backend
 * of the Directory Server.
 */
public class LocalBackendModifyDNOperation
  extends ModifyDNOperationWrapper
  implements PreOperationModifyDNOperation,
             PostOperationModifyDNOperation,
             PostResponseModifyDNOperation
{
  // The current entry, before it is renamed.
  private Entry currentEntry;
  // The new entry, as it will appear after it has been renamed.
  private Entry newEntry;
  /**
   * Creates a new operation that may be used to move an entry in a
   * local backend of the Directory Server.
   *
   * @param operation The operation to enhance.
   */
  public LocalBackendModifyDNOperation (ModifyDNOperation operation)
  {
    super(operation);
    LocalBackendWorkflowElement.attachLocalOperation (operation, this);
  }
  /**
   * Retrieves the current entry, before it is renamed.  This will not be
   * available to pre-parse plugins or during the conflict resolution portion of
   * the synchronization processing.
   *
   * @return  The current entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final Entry getOriginalEntry()
  {
    return currentEntry;
  }
  /**
   * Retrieves the new entry, as it will appear after it is renamed.  This will
   * not be  available to pre-parse plugins or during the conflict resolution
   * portion of the synchronization processing.
   *
   * @return  The updated entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final Entry getUpdatedEntry()
  {
    return newEntry;
  }
  /**
   * Sets the current entry, before it is renamed.  This will not be
   * available to pre-parse plugins or during the conflict resolution portion of
   * the synchronization processing.
   *
   * @param entry  The current entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final void setOriginalEntry(Entry entry)
  {
    this.currentEntry = entry;
  }
  /**
   * Sets the new entry, as it will appear after it is renamed.  This will
   * not be  available to pre-parse plugins or during the conflict resolution
   * portion of the synchronization processing.
   *
   * @param entry  The updated entry, or <CODE>null</CODE> if it is not yet
   *           available.
   */
  public final void setUpdatedEntry(Entry entry)
  {
    this.newEntry = entry;
  }
}
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -77,6 +77,7 @@
import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.PasswordPolicy;
import org.opends.server.core.PasswordPolicyState;
@@ -179,6 +180,9 @@
    case MODIFY:
      processModify((ModifyOperation) operation);
      break;
    case MODIFY_DN:
      processModifyDN((ModifyDNOperation) operation);
      break;
    case COMPARE:
      processCompare((CompareOperation) operation);
      break;
@@ -6679,6 +6683,7 @@
  }
  /**
   * Perform a compare operation against a local backend.
   *
@@ -7248,6 +7253,1301 @@
    }
  }
  /**
   * Perform a moddn operation against a local backend.
   *
   * @param op The operation to perform
   */
  public void processModifyDN(ModifyDNOperation op)
  {
    LocalBackendModifyDNOperation localOp =
      new LocalBackendModifyDNOperation(op);
    processLocalModifyDN(localOp);
  }
  /**
   * Perform a local moddn operation against the local backend.
   *
   * @param operation - The operation to perform
   */
  private void processLocalModifyDN(LocalBackendModifyDNOperation op)
  {
    ClientConnection clientConnection = op.getClientConnection();
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
         DirectoryServer.getPluginConfigManager();
    boolean skipPostOperation = false;
    // Check for and handle a request to cancel this operation.
    if (op.getCancelRequest() != null)
    {
      op.indicateCancelled(op.getCancelRequest());
      return;
    }
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
modifyDNProcessing:
    {
      // Process the entry DN, newRDN, and newSuperior elements from their raw
      // forms as provided by the client to the forms required for the rest of
      // the modify DN processing.
      DN entryDN = op.getEntryDN();
      RDN newRDN = op.getNewRDN();
      if (newRDN == null)
      {
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      DN newSuperior = op.getNewSuperior();
      if ((newSuperior == null) &&
          (op.getRawNewSuperior() != null))
      {
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      // Construct the new DN to use for the entry.
      DN parentDN;
      if (newSuperior == null)
      {
        parentDN = entryDN.getParentDNInSuffix();
      }
      else
      {
        parentDN = newSuperior;
      }
      if ((parentDN == null) || parentDN.isNullDN())
      {
        op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        op.appendErrorMessage(getMessage(MSGID_MODDN_NO_PARENT,
                                      String.valueOf(entryDN)));
        break modifyDNProcessing;
      }
      DN newDN = parentDN.concat(newRDN);
      // Get the backend for the current entry, and the backend for the new
      // entry.  If either is null, or if they are different, then fail.
      Backend currentBackend = backend;
      if (currentBackend == null)
      {
        op.setResultCode(ResultCode.NO_SUCH_OBJECT);
        op.appendErrorMessage(getMessage(
                                      MSGID_MODDN_NO_BACKEND_FOR_CURRENT_ENTRY,
                                      String.valueOf(entryDN)));
        break modifyDNProcessing;
      }
      Backend newBackend = DirectoryServer.getBackend(newDN);
      if (newBackend == null)
      {
        op.setResultCode(ResultCode.NO_SUCH_OBJECT);
        op.appendErrorMessage(getMessage(MSGID_MODDN_NO_BACKEND_FOR_NEW_ENTRY,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        break modifyDNProcessing;
      }
      else if (! currentBackend.equals(newBackend))
      {
        op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
        op.appendErrorMessage(getMessage(MSGID_MODDN_DIFFERENT_BACKENDS,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        break modifyDNProcessing;
      }
      // Check for and handle a request to cancel this operation.
      if (op.getCancelRequest() != null)
      {
        op.indicateCancelled(op.getCancelRequest());
        return;
      }
      // Acquire write locks for the current and new DN.
      Lock currentLock = null;
      for (int i=0; i < 3; i++)
      {
        currentLock = LockManager.lockWrite(entryDN);
        if (currentLock != null)
        {
          break;
        }
      }
      if (currentLock == null)
      {
        op.setResultCode(DirectoryServer.getServerErrorResultCode());
        op.appendErrorMessage(getMessage(MSGID_MODDN_CANNOT_LOCK_CURRENT_DN,
                                      String.valueOf(entryDN)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      Lock newLock = null;
      try
      {
        for (int i=0; i < 3; i++)
        {
          newLock = LockManager.lockWrite(newDN);
          if (newLock != null)
          {
            break;
          }
        }
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        LockManager.unlock(entryDN, currentLock);
        if (newLock != null)
        {
          LockManager.unlock(newDN, newLock);
        }
        op.setResultCode(DirectoryServer.getServerErrorResultCode());
        op.appendErrorMessage(getMessage(MSGID_MODDN_EXCEPTION_LOCKING_NEW_DN,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN),
                                      getExceptionMessage(e)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      if (newLock == null)
      {
        LockManager.unlock(entryDN, currentLock);
        op.setResultCode(DirectoryServer.getServerErrorResultCode());
        op.appendErrorMessage(getMessage(MSGID_MODDN_CANNOT_LOCK_NEW_DN,
                                      String.valueOf(entryDN),
                                      String.valueOf(newDN)));
        skipPostOperation = true;
        break modifyDNProcessing;
      }
      Entry currentEntry = null;
      try
      {
        // Check for and handle a request to cancel this operation.
        if (op.getCancelRequest() != null)
        {
          op.indicateCancelled(op.getCancelRequest());
          return;
        }
        // Get the current entry from the appropriate backend.  If it doesn't
        // exist, then fail.
        try
        {
          currentEntry = currentBackend.getEntry(entryDN);
          op.setOriginalEntry(currentEntry);
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          op.setResultCode(de.getResultCode());
          op.appendErrorMessage(de.getErrorMessage());
          op.setMatchedDN(de.getMatchedDN());
          op.setReferralURLs(de.getReferralURLs());
          break modifyDNProcessing;
        }
        if (op.getOriginalEntry() == null)
        {
          // See if one of the entry's ancestors exists.
          parentDN = entryDN.getParentDNInSuffix();
          while (parentDN != null)
          {
            try
            {
              if (DirectoryServer.entryExists(parentDN))
              {
                op.setMatchedDN(parentDN);
                break;
              }
            }
            catch (Exception e)
            {
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
              break;
            }
            parentDN = parentDN.getParentDNInSuffix();
          }
          op.setResultCode(ResultCode.NO_SUCH_OBJECT);
          op.appendErrorMessage(getMessage(MSGID_MODDN_NO_CURRENT_ENTRY,
                                        String.valueOf(entryDN)));
          break modifyDNProcessing;
        }
        // Invoke any conflict resolution processing that might be needed by the
        // synchronization provider.
        for (SynchronizationProvider provider :
             DirectoryServer.getSynchronizationProviders())
        {
          try
          {
            SynchronizationProviderResult result =
                 provider.handleConflictResolution(op);
            if (! result.continueOperationProcessing())
            {
              break modifyDNProcessing;
            }
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            logError(ErrorLogCategory.SYNCHRONIZATION,
                     ErrorLogSeverity.SEVERE_ERROR,
                     MSGID_MODDN_SYNCH_CONFLICT_RESOLUTION_FAILED,
                     op.getConnectionID(), op.getOperationID(),
                     getExceptionMessage(de));
            op.setResponseData(de);
            break modifyDNProcessing;
          }
        }
        // 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 = op.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);
                  }
                  op.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  op.appendErrorMessage(le.getMessage());
                  break modifyDNProcessing;
                }
              }
              try
              {
                // FIXME -- We need to determine whether the current user has
                //          permission to make this determination.
                SearchFilter filter = assertControl.getSearchFilter();
                if (! filter.matchesEntry(currentEntry))
                {
                  op.setResultCode(ResultCode.ASSERTION_FAILED);
                  op.appendErrorMessage(getMessage(MSGID_MODDN_ASSERTION_FAILED,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                op.setResultCode(ResultCode.PROTOCOL_ERROR);
                int msgID = MSGID_MODDN_CANNOT_PROCESS_ASSERTION_FILTER;
                op.appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              de.getErrorMessage()));
                break modifyDNProcessing;
              }
            }
            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);
                  }
                  op.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  op.appendErrorMessage(le.getMessage());
                  break modifyDNProcessing;
                }
              }
            }
            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);
                  }
                  op.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  op.appendErrorMessage(le.getMessage());
                  break modifyDNProcessing;
                }
              }
            }
            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, op))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                op.appendErrorMessage(getMessage(msgID));
                op.setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyDNProcessing;
              }
              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);
                  }
                  op.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  op.appendErrorMessage(le.getMessage());
                  break modifyDNProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                op.setResultCode(de.getResultCode());
                op.appendErrorMessage(de.getErrorMessage());
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(op,
                      authorizationEntry) == false) {
                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                op.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              op.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                op.setProxiedAuthorizationDN(DN.nullDN());
              }
              else
              {
                op.setProxiedAuthorizationDN(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, op))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                op.appendErrorMessage(getMessage(msgID));
                op.setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break modifyDNProcessing;
              }
              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);
                  }
                  op.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  op.appendErrorMessage(le.getMessage());
                  break modifyDNProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                op.setResultCode(de.getResultCode());
                op.appendErrorMessage(de.getErrorMessage());
                break modifyDNProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                  .getAccessControlHandler().isProxiedAuthAllowed(op,
                                                authorizationEntry) == false) {
                op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                op.appendErrorMessage(getMessage(msgID,
                    String.valueOf(entryDN)));
                skipPostOperation = true;
                break modifyDNProcessing;
              }
              op.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                op.setProxiedAuthorizationDN(DN.nullDN());
              }
              else
              {
                op.setProxiedAuthorizationDN(authorizationEntry.getDN());
              }
            }
            // NYI -- Add support for additional controls.
            else if (c.isCritical())
            {
              Backend backend = DirectoryServer.getBackend(entryDN);
              if ((backend == null) || (! backend.supportsControl(oid)))
              {
                op.setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
                int msgID = MSGID_MODDN_UNSUPPORTED_CRITICAL_CONTROL;
                op.appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              oid));
                break modifyDNProcessing;
              }
            }
          }
        }
        // Check to see if the client has permission to perform the
        // modify DN.
        // 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 or new superior
        // already exists may have already exposed sensitive information
        // to the client.
        if (AccessControlConfigManager.getInstance()
            .getAccessControlHandler().isAllowed(op) == false) {
          op.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
          int msgID = MSGID_MODDN_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
          op.appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
          skipPostOperation = true;
          break modifyDNProcessing;
        }
        // Duplicate the entry and set its new DN.  Also, create an empty list
        // to hold the attribute-level modifications.
        Entry newEntry = currentEntry.duplicate(false);
        newEntry.setDN(newDN);
        op.setUpdatedEntry(newEntry);
        // init the modifications
        op.addModification(null);
        List<Modification> modifications = op.getModifications();
        // If we should delete the old RDN values from the entry, then do so.
        if (op.deleteOldRDN())
        {
          RDN currentRDN = entryDN.getRDN();
          int numValues  = currentRDN.getNumValues();
          for (int i=0; i < numValues; i++)
          {
            LinkedHashSet<AttributeValue> valueSet =
                 new LinkedHashSet<AttributeValue>(1);
            valueSet.add(currentRDN.getAttributeValue(i));
            Attribute a = new Attribute(currentRDN.getAttributeType(i),
                                        currentRDN.getAttributeName(i),
                                        valueSet);
            // If the associated attribute type is marked NO-USER-MODIFICATION,
            // then refuse the update.
            if (a.getAttributeType().isNoUserModification())
            {
              if (! (op.isInternalOperation() ||
                  op.isSynchronizationOperation()))
              {
                op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                int msgID = MSGID_MODDN_OLD_RDN_ATTR_IS_NO_USER_MOD;
                op.appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              a.getName()));
                break modifyDNProcessing;
              }
            }
            LinkedList<AttributeValue> missingValues =
                 new LinkedList<AttributeValue>();
            newEntry.removeAttribute(a, missingValues);
            if (missingValues.isEmpty())
            {
              modifications.add(new Modification(ModificationType.DELETE, a));
            }
          }
        }
        // Add the new RDN values to the entry.
        int newRDNValues = newRDN.getNumValues();
        for (int i=0; i < newRDNValues; i++)
        {
          LinkedHashSet<AttributeValue> valueSet =
               new LinkedHashSet<AttributeValue>(1);
          valueSet.add(newRDN.getAttributeValue(i));
          Attribute a = new Attribute(newRDN.getAttributeType(i),
                                      newRDN.getAttributeName(i),
                                      valueSet);
          LinkedList<AttributeValue> duplicateValues =
               new LinkedList<AttributeValue>();
          newEntry.addAttribute(a, duplicateValues);
          if (duplicateValues.isEmpty())
          {
            // If the associated attribute type is marked NO-USER-MODIFICATION,
            // then refuse the update.
            if (a.getAttributeType().isNoUserModification())
            {
              if (! (op.isInternalOperation() ||
                  op.isSynchronizationOperation()))
              {
                op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                int msgID = MSGID_MODDN_NEW_RDN_ATTR_IS_NO_USER_MOD;
                op.appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              a.getName()));
                break modifyDNProcessing;
              }
            }
            else
            {
              modifications.add(new Modification(ModificationType.ADD, a));
            }
          }
        }
        // If the server is configured to check the schema and the
        // operation is not a synchronization operation,
        // make sure that the resulting entry is valid as per the server schema.
        if ((DirectoryServer.checkSchema()) &&
            (!op.isSynchronizationOperation()) )
        {
          StringBuilder invalidReason = new StringBuilder();
          if (! newEntry.conformsToSchema(null, false, true, true,
                                          invalidReason))
          {
            op.setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
            op.appendErrorMessage(getMessage(MSGID_MODDN_VIOLATES_SCHEMA,
                                          String.valueOf(entryDN),
                                          String.valueOf(invalidReason)));
            break modifyDNProcessing;
          }
          for (int i=0; i < newRDNValues; i++)
          {
            AttributeType at = newRDN.getAttributeType(i);
            if (at.isObsolete())
            {
              op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
              op.appendErrorMessage(getMessage(
                                            MSGID_MODDN_NEWRDN_ATTR_IS_OBSOLETE,
                                            String.valueOf(entryDN),
                                            at.getNameOrOID()));
              break modifyDNProcessing;
            }
          }
        }
        // Check for and handle a request to cancel this operation.
        if (op.getCancelRequest() != null)
        {
          op.indicateCancelled(op.getCancelRequest());
          return;
        }
        // Get a count of the current number of modifications.  The
        // pre-operation plugins may alter this list, and we need to be able to
        // identify which changes were made after they're done.
        int modCount = op.getModifications().size();
        // If the operation is not a synchronization operation,
        // Invoke the pre-operation modify DN plugins.
        if (!op.isSynchronizationOperation())
        {
          PreOperationPluginResult preOpResult =
            pluginConfigManager.invokePreOperationModifyDNPlugins(op);
          if (preOpResult.connectionTerminated())
          {
            // There's no point in continuing with anything.  Log the request
            // and result and return.
            op.setResultCode(ResultCode.CANCELED);
            int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
            op.appendErrorMessage(getMessage(msgID));
            return;
          }
          else if (preOpResult.sendResponseImmediately())
          {
            skipPostOperation = true;
            break modifyDNProcessing;
          }
          else if (preOpResult.skipCoreProcessing())
          {
            skipPostOperation = false;
            break modifyDNProcessing;
          }
        }
        // Check to see if any of the pre-operation plugins made any changes to
        // the entry.  If so, then apply them.
        if (modifications.size() > modCount)
        {
          for (int i=modCount; i < modifications.size(); i++)
          {
            Modification m = modifications.get(i);
            Attribute    a = m.getAttribute();
            switch (m.getModificationType())
            {
              case ADD:
                LinkedList<AttributeValue> duplicateValues =
                     new LinkedList<AttributeValue>();
                newEntry.addAttribute(a, duplicateValues);
                break;
              case DELETE:
                LinkedList<AttributeValue> missingValues =
                     new LinkedList<AttributeValue>();
                newEntry.removeAttribute(a, missingValues);
                break;
              case REPLACE:
                duplicateValues = new LinkedList<AttributeValue>();
                newEntry.removeAttribute(a.getAttributeType(), a.getOptions());
                newEntry.addAttribute(a, duplicateValues);
                break;
              case INCREMENT:
                List<Attribute> attrList =
                     newEntry.getAttribute(a.getAttributeType(),
                                           a.getOptions());
                if ((attrList == null) || attrList.isEmpty())
                {
                  op.setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_ATTR;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (attrList.size() > 1)
                {
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_VALUES;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                LinkedHashSet<AttributeValue> values =
                     attrList.get(0).getValues();
                if ((values == null) || values.isEmpty())
                {
                  op.setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_ATTR;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (values.size() > 1)
                {
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_VALUES;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long currentLongValue;
                try
                {
                  AttributeValue v = values.iterator().next();
                  currentLongValue = Long.parseLong(v.getStringValue());
                }
                catch (Exception e)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
                  }
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_VALUE_NOT_INTEGER;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                LinkedHashSet<AttributeValue> newValues = a.getValues();
                if ((newValues == null) || newValues.isEmpty())
                {
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_NO_AMOUNT;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                else if (newValues.size() > 1)
                {
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_MULTIPLE_AMOUNTS;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long incrementAmount;
                try
                {
                  AttributeValue v = values.iterator().next();
                  incrementAmount = Long.parseLong(v.getStringValue());
                }
                catch (Exception e)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
                  }
                  op.setResultCode(ResultCode.CONSTRAINT_VIOLATION);
                  int msgID = MSGID_MODDN_PREOP_INCREMENT_AMOUNT_NOT_INTEGER;
                  op.appendErrorMessage(getMessage(msgID,
                                                String.valueOf(entryDN),
                                                a.getName()));
                  break modifyDNProcessing;
                }
                long newLongValue = currentLongValue + incrementAmount;
                ByteString newValueOS =
                     new ASN1OctetString(String.valueOf(newLongValue));
                newValues = new LinkedHashSet<AttributeValue>(1);
                newValues.add(new AttributeValue(a.getAttributeType(),
                                                 newValueOS));
                List<Attribute> newAttrList = new ArrayList<Attribute>(1);
                newAttrList.add(new Attribute(a.getAttributeType(),
                                              a.getName(), newValues));
                newEntry.putAttribute(a.getAttributeType(), newAttrList);
                break;
            }
          }
          // Make sure that the updated entry still conforms to the server
          // schema.
          if (DirectoryServer.checkSchema())
          {
            StringBuilder invalidReason = new StringBuilder();
            if (! newEntry.conformsToSchema(null, false, true, true,
                                            invalidReason))
            {
              op.setResultCode(ResultCode.OBJECTCLASS_VIOLATION);
              op.appendErrorMessage(getMessage(
                                            MSGID_MODDN_PREOP_VIOLATES_SCHEMA,
                                            String.valueOf(entryDN),
                                            String.valueOf(invalidReason)));
              break modifyDNProcessing;
            }
          }
        }
        // Check for and handle a request to cancel this operation.
        if (op.getCancelRequest() != null)
        {
          op.indicateCancelled(op.getCancelRequest());
          return;
        }
        // Actually perform the modify DN operation.
        // This should include taking
        // care of any synchronization that might be needed.
        try
        {
          // If it is not a private backend, then check to see if the server or
          // backend is operating in read-only mode.
          if (! currentBackend.isPrivateBackend())
          {
            switch (DirectoryServer.getWritabilityMode())
            {
              case DISABLED:
                op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                op.appendErrorMessage(getMessage(MSGID_MODDN_SERVER_READONLY,
                                              String.valueOf(entryDN)));
                break modifyDNProcessing;
              case INTERNAL_ONLY:
                if (! (op.isInternalOperation() ||
                    op.isSynchronizationOperation()))
                {
                  op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                  op.appendErrorMessage(getMessage(MSGID_MODDN_SERVER_READONLY,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
            }
            switch (currentBackend.getWritabilityMode())
            {
              case DISABLED:
                op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                op.appendErrorMessage(getMessage(MSGID_MODDN_BACKEND_READONLY,
                                              String.valueOf(entryDN)));
                break modifyDNProcessing;
              case INTERNAL_ONLY:
                if (! (op.isInternalOperation() ||
                    op.isSynchronizationOperation()))
                {
                  op.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
                  op.appendErrorMessage(getMessage(MSGID_MODDN_BACKEND_READONLY,
                                                String.valueOf(entryDN)));
                  break modifyDNProcessing;
                }
            }
          }
          if (noOp)
          {
            op.appendErrorMessage(getMessage(MSGID_MODDN_NOOP));
            op.setResultCode(ResultCode.NO_OPERATION);
          }
          else
          {
            for (SynchronizationProvider provider :
                 DirectoryServer.getSynchronizationProviders())
            {
              try
              {
                SynchronizationProviderResult result =
                     provider.doPreOperation(op);
                if (! result.continueOperationProcessing())
                {
                  break modifyDNProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                logError(ErrorLogCategory.SYNCHRONIZATION,
                         ErrorLogSeverity.SEVERE_ERROR,
                         MSGID_MODDN_SYNCH_PREOP_FAILED, op.getConnectionID(),
                         op.getOperationID(), getExceptionMessage(de));
                op.setResponseData(de);
                break modifyDNProcessing;
              }
            }
            currentBackend.renameEntry(entryDN, newEntry, op);
          }
          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);
            op.addResponseControl(responseControl);
          }
          if (postReadRequest != null)
          {
            Entry entry = newEntry.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);
            op.addResponseControl(responseControl);
          }
          if (! noOp)
          {
            op.setResultCode(ResultCode.SUCCESS);
          }
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          op.setResultCode(de.getResultCode());
          op.appendErrorMessage(de.getErrorMessage());
          op.setMatchedDN(de.getMatchedDN());
          op.setReferralURLs(de.getReferralURLs());
          break modifyDNProcessing;
        }
        catch (CancelledOperationException coe)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, coe);
          }
          CancelResult cancelResult = coe.getCancelResult();
          op.setCancelResult(cancelResult);
          op.setResultCode(cancelResult.getResultCode());
          String message = coe.getMessage();
          if ((message != null) && (message.length() > 0))
          {
            op.appendErrorMessage(message);
          }
          break modifyDNProcessing;
        }
      }
      finally
      {
        LockManager.unlock(entryDN, currentLock);
        LockManager.unlock(newDN, newLock);
        for (SynchronizationProvider provider :
             DirectoryServer.getSynchronizationProviders())
        {
          try
          {
            provider.doPostOperation(op);
          }
          catch (DirectoryException de)
          {
            if (debugEnabled())
            {
              TRACER.debugCaught(DebugLogLevel.ERROR, de);
            }
            logError(ErrorLogCategory.SYNCHRONIZATION,
                     ErrorLogSeverity.SEVERE_ERROR,
                     MSGID_MODDN_SYNCH_POSTOP_FAILED, op.getConnectionID(),
                     op.getOperationID(), getExceptionMessage(de));
            op.setResponseData(de);
            break;
          }
        }
      }
    }
    // Indicate that it is now too late to attempt to cancel the operation.
    op.setCancelResult(CancelResult.TOO_LATE);
    // Invoke the post-operation modify DN plugins.
    if (! skipPostOperation)
    {
      PostOperationPluginResult postOperationResult =
           pluginConfigManager.invokePostOperationModifyDNPlugins(op);
      if (postOperationResult.connectionTerminated())
      {
        op.setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_POSTOP_DISCONNECT;
        op.appendErrorMessage(getMessage(msgID));
        return;
      }
    }
    // Notify any change notification listeners that might be registered with
    // the server.
    if (op.getResultCode() == ResultCode.SUCCESS)
    {
      for (ChangeNotificationListener changeListener :
           DirectoryServer.getChangeNotificationListeners())
      {
        try
        {
          changeListener.handleModifyDNOperation(op,
              op.getOriginalEntry(),
              op.getUpdatedEntry());
        }
        catch (Exception e)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          int    msgID   = MSGID_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER;
          String message = getMessage(msgID, getExceptionMessage(e));
          logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
                   message, msgID);
        }
      }
    }
  }
  /**
   * Attaches the current local operation to the global operation so that
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
@@ -40,7 +40,7 @@
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ByteStringFactory;
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
@@ -40,7 +40,7 @@
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.SchemaConfigManager;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -309,8 +309,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), null,
                               currentSchemaDN, newSchemaDN.getRDN(),
                               true, null);
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -34,7 +34,7 @@
import org.opends.server.admin.std.meta.JEBackendCfgDefn;
import org.opends.server.admin.std.meta.JEIndexCfgDefn;
import org.opends.server.admin.server.AdminTestCaseUtils;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
@@ -1167,7 +1167,7 @@
      InternalClientConnection conn =
          InternalClientConnection.getRootConnection();
      ModifyDNOperation modifyDN = new ModifyDNOperation(conn,
      ModifyDNOperationBasis modifyDN = new ModifyDNOperationBasis(conn,
          conn.nextOperationID(),
          conn.nextMessageID(),
          noControls,
opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
@@ -40,7 +40,7 @@
import org.opends.server.api.Group;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.extensions.DynamicGroup;
import org.opends.server.extensions.StaticGroup;
import org.opends.server.extensions.VirtualStaticGroup;
@@ -689,7 +689,7 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(groupDN, newRDN, true);
    assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
@@ -165,7 +165,7 @@
   *
   * @param  modifyDNOperation  The operation to be tested.
   */
  private void examineCompletedOperation(ModifyDNOperation modifyDNOperation)
  private void examineCompletedOperation(ModifyDNOperationBasis modifyDNOperation)
  {
    assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
    assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
@@ -185,7 +185,7 @@
   *
   * @param  modifyDNOperation  The operation to be tested.
   */
  private void examineIncompleteOperation(ModifyDNOperation modifyDNOperation)
  private void examineIncompleteOperation(ModifyDNOperationBasis modifyDNOperation)
  {
    assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
    assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
@@ -206,7 +206,7 @@
   *
   * @param  modifyDNOperation  The operation to be tested.
   */
  private void examineUnparsedOperation(ModifyDNOperation modifyDNOperation)
  private void examineUnparsedOperation(ModifyDNOperationBasis modifyDNOperation)
  {
    assertTrue(modifyDNOperation.getProcessingStartTime() > 0);
    assertTrue(modifyDNOperation.getProcessingStopTime() > 0);
@@ -232,13 +232,13 @@
    InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
    ModifyDNOperation[] modifies = new ModifyDNOperation[]
    ModifyDNOperationBasis[] modifies = new ModifyDNOperationBasis[]
    {
      new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
      new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            noControls, new ASN1OctetString("cn=test,ou=test"),
                            new ASN1OctetString("cn=test2"), true,
                            new ASN1OctetString("dc=example,dc=com")),
      new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
      new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                            noControls, DN.decode("cn=test,ou=test"),
                            RDN.decode("cn=test2"), true,
                            DN.decode("dc=example,dc=com"))
@@ -256,8 +256,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), false,
@@ -282,7 +282,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.0"), true,
@@ -315,8 +315,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -341,7 +341,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
@@ -374,8 +374,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), true,
@@ -400,7 +400,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.0"), true,
@@ -433,8 +433,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), true,
@@ -459,7 +459,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
@@ -492,8 +492,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), true,
@@ -518,7 +518,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.test0,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.0"), true,
@@ -551,8 +551,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), true,
@@ -577,7 +577,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.test0,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
@@ -610,8 +610,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("cn=Aaccf Amar Test"), true,
@@ -637,7 +637,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("cn=Aaccf Amar Test,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), false,
@@ -673,8 +673,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.invalid,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), true,
@@ -696,8 +696,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("invalid=invalid"), true,
@@ -719,8 +719,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), true,
@@ -742,8 +742,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("invalid DN"),
                               new ASN1OctetString("uid=user.test0"), true,
@@ -765,8 +765,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("invalid RDN"), true,
@@ -788,8 +788,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), true,
@@ -811,8 +811,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               noControls,
                               DN.decode("dc=example,dc=com"),
                               RDN.decode("dc=exampletest"), true,
@@ -834,8 +834,8 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               new ASN1OctetString("uid=user.0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.test0"), false,
@@ -860,7 +860,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               new ASN1OctetString("uid=user.test0,ou=People,dc=example,dc=com"),
                               new ASN1OctetString("uid=user.0"), true,
@@ -893,8 +893,8 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -919,7 +919,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(),
                               controls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
@@ -953,8 +953,8 @@
    controls.add(authV1Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -978,8 +978,8 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -1004,7 +1004,7 @@
    InvocationCounterPlugin.resetAllCounters();
    modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.test0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.0"), true,
@@ -1037,8 +1037,8 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -1063,8 +1063,8 @@
    controls.add(authV2Control);
    InvocationCounterPlugin.resetAllCounters();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(proxyUserConn, proxyUserConn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(proxyUserConn, proxyUserConn.nextOperationID(),
                               proxyUserConn.nextMessageID(), controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
@@ -1091,8 +1091,8 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(), conn.nextMessageID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(), conn.nextMessageID(),
                               controls,
                               DN.decode("uid=user.0,ou=People,dc=example,dc=com"),
                               RDN.decode("uid=user.test0"), false,
opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
@@ -46,7 +46,7 @@
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
@@ -390,7 +390,7 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(e.getDN(), RDN.decode("cn=test2"), false);
    assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
@@ -47,7 +47,7 @@
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.protocols.ldap.LDAPAttribute;
@@ -723,7 +723,7 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(new ASN1OctetString("cn=test,o=test"),
                              new ASN1OctetString("cn=test2"), true);
    assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
@@ -756,7 +756,7 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(new ASN1OctetString("cn=test,o=test"),
                              new ASN1OctetString("cn=test2"), true,
                              new ASN1OctetString("dc=example,dc=com"));
@@ -791,7 +791,7 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(DN.decode("cn=test,o=test"),
                              RDN.decode("cn=test2"), true);
    assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
@@ -824,7 +824,7 @@
    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(DN.decode("cn=test,o=test"),
                              RDN.decode("cn=test2"), true,
                              DN.decode("dc=example,dc=com"));
opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -56,7 +56,7 @@
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.core.SchemaConfigManager;
@@ -688,7 +688,7 @@
  {
    assertEquals(conn.hasPrivilege(Privilege.JMX_WRITE, null), hasPrivilege);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(DN.decode("cn=Work Queue,cn=config"),
                              RDN.decode("cn=New RDN for Work Queue"), true,
                              null);
@@ -1186,8 +1186,8 @@
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V1 Test"), true, null);
    modifyDNOperation.run();
@@ -1196,7 +1196,7 @@
    if (hasProxyPrivilege)
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
      newEntryDN = modifyDNOperation.getNewDN();
    }
    else
    {
@@ -1388,8 +1388,8 @@
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V2 Test"), true, null);
    modifyDNOperation.run();
@@ -1399,7 +1399,7 @@
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS,
                   "Unexpected moddn failure for user " + authDN);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
      newEntryDN = modifyDNOperation.getNewDN();
    }
    else
    {
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -45,7 +45,7 @@
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.plugins.ShortCircuitPlugin;
@@ -975,7 +975,7 @@
        personWithUUIDEntry.getAttributes(), new ArrayList<Attribute>());
    // - MODDN parent entry 1 to baseDn2 in the LDAP server
    ModifyDNOperation modDNOp = new ModifyDNOperation(connection,
    ModifyDNOperationBasis modDNOp = new ModifyDNOperationBasis(connection,
        InternalClientConnection.nextOperationID(), InternalClientConnection
        .nextMessageID(), null,
        DN.decode("ou=baseDn1,"+baseDn),
@@ -1206,7 +1206,7 @@
      // Modify the entry DN
      DN newDN = DN.decode("uid= new person,ou=People,dc=example,dc=com") ;
      ModifyDNOperation modDNOp = new ModifyDNOperation(connection,
      ModifyDNOperationBasis modDNOp = new ModifyDNOperationBasis(connection,
          InternalClientConnection.nextOperationID(), InternalClientConnection
          .nextMessageID(), null, personEntry.getDN(), RDN
          .decode("uid=new person"), true, DN
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
@@ -42,7 +42,7 @@
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.replication.ReplicationTestCase;
@@ -79,6 +79,7 @@
import org.opends.server.util.TimeThread;
import org.opends.server.workflowelement.localbackend.LocalBackendAddOperation;
import org.opends.server.workflowelement.localbackend.LocalBackendDeleteOperation;
import org.opends.server.workflowelement.localbackend.LocalBackendModifyDNOperation;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -305,8 +306,8 @@
  {
    InternalClientConnection connection =
      InternalClientConnection.getRootConnection();
    ModifyDNOperation op =
      new ModifyDNOperation(connection, 1, 1, null,
    ModifyDNOperationBasis op =
      new ModifyDNOperationBasis(connection, 1, 1, null,
                  DN.decode(rawDN), RDN.decode(newRdn), deleteOldRdn,
                  (newSuperior.length() != 0 ? DN.decode(newSuperior) : null));
@@ -314,11 +315,13 @@
                                      (short) 123, (short) 45);
    op.setAttachment(SYNCHROCONTEXT,
        new ModifyDnContext(cn, "uniqueid", "newparentId"));
    ModifyDNMsg msg = new ModifyDNMsg(op);
    LocalBackendModifyDNOperation localOp =
      new LocalBackendModifyDNOperation(op);
    ModifyDNMsg msg = new ModifyDNMsg(localOp);
    ModifyDNMsg generatedMsg = (ModifyDNMsg) ReplicationMessage
        .generateMsg(msg.getBytes());
    Operation generatedOperation = generatedMsg.createOperation(connection);
    ModifyDNOperation mod2 = (ModifyDNOperation) generatedOperation;
    ModifyDNOperationBasis mod2 = (ModifyDNOperationBasis) generatedOperation;
    assertEquals(msg.getChangeNumber(), generatedMsg.getChangeNumber());
    assertEquals(op.getRawEntryDN(), mod2.getRawEntryDN());
@@ -327,7 +330,8 @@
    assertEquals(op.getRawNewSuperior(), mod2.getRawNewSuperior());
    // Create an update message from this op
    ModifyDNMsg updateMsg = (ModifyDNMsg) UpdateMessage.generateMsg(op, true);
    ModifyDNMsg updateMsg = (ModifyDNMsg) UpdateMessage.generateMsg(localOp,
        true);
    assertEquals(msg.getChangeNumber(), updateMsg.getChangeNumber());
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
@@ -42,7 +42,7 @@
import java.util.TreeSet;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.replication.ReplicationTestCase;
import org.opends.server.replication.common.ChangeNumber;
import org.opends.server.replication.common.ChangeNumberGenerator;
@@ -68,6 +68,7 @@
import org.opends.server.types.ModificationType;
import org.opends.server.types.RDN;
import org.opends.server.util.TimeThread;
import org.opends.server.workflowelement.localbackend.LocalBackendModifyDNOperation;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -669,12 +670,14 @@
        // - ModifyDN
        cn = new ChangeNumber(time, ts++, brokerIds[0]);
        ModifyDNOperation op = new ModifyDNOperation(connection, 1, 1, null, DN
        ModifyDNOperationBasis op = new ModifyDNOperationBasis(connection, 1, 1, null, DN
            .decode("o=test,dc=example,dc=com"), RDN.decode("o=test2"), true,
            null);
        op.setAttachment(SYNCHROCONTEXT, new ModifyDnContext(cn, "uniqueid",
        "newparentId"));
        ModifyDNMsg modDNMsg = new ModifyDNMsg(op);
        LocalBackendModifyDNOperation localOp =
          new LocalBackendModifyDNOperation(op);
        ModifyDNMsg modDNMsg = new ModifyDNMsg(localOp);
        broker1.publish(modDNMsg);
        if (itest > 0)
opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -52,7 +52,7 @@
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyDNOperationBasis;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.ModifyOperationBasis;
import org.opends.server.core.SchemaConfigManager;
@@ -597,7 +597,7 @@
  {
    assertEquals(conn.hasPrivilege(Privilege.CONFIG_WRITE, null), hasPrivilege);
    ModifyDNOperation modifyDNOperation =
    ModifyDNOperationBasis modifyDNOperation =
         conn.processModifyDN(DN.decode("cn=Work Queue,cn=config"),
                              RDN.decode("cn=New RDN for Work Queue"), true,
                              null);
@@ -1246,8 +1246,8 @@
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V1 Test"), true, null);
    modifyDNOperation.run();
@@ -1256,7 +1256,7 @@
    if (hasProxyPrivilege)
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
      newEntryDN = modifyDNOperation.getNewDN();
    }
    else
    {
@@ -1446,8 +1446,8 @@
    // Try to rename the entry.
    ModifyDNOperation modifyDNOperation =
         new ModifyDNOperation(conn, conn.nextOperationID(),
    ModifyDNOperationBasis modifyDNOperation =
         new ModifyDNOperationBasis(conn, conn.nextOperationID(),
                               conn.nextMessageID(), controls, e.getDN(),
                               RDN.decode("cn=Proxy V2 Test"), true, null);
    modifyDNOperation.run();
@@ -1457,7 +1457,7 @@
    {
      assertEquals(modifyDNOperation.getResultCode(), ResultCode.SUCCESS,
                   "Unexpected moddn failure for user " + authDN);
      newEntryDN = modifyDNOperation.getUpdatedEntry().getDN();
      newEntryDN = modifyDNOperation.getNewDN();
    }
    else
    {