From ff9755c40feeaf5a3208229d48b80b608ab7a68c Mon Sep 17 00:00:00 2001
From: jarnou <jarnou@localhost>
Date: Tue, 17 Jul 2007 08:14:43 +0000
Subject: [PATCH] This fix is the refactoring of the modrdn operation [issue 1180]

---
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java                    | 1300 +++++++++++++++
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java                  |   16 
 opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java                                                 |  952 +++++++++++
 opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java                                              |    6 
 opends/src/server/org/opends/server/api/AccessLogPublisher.java                                                      |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java                          |  116 
 opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java                           |    4 
 opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java                                               |  199 ++
 opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java |   10 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java         |   16 
 opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java                                        |   10 
 opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java                                         |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java                       |    4 
 opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java                  |  117 +
 opends/src/server/org/opends/server/core/PersistentSearch.java                                                       |    2 
 opends/src/server/org/opends/server/api/AccessControlHandler.java                                                    |    2 
 opends/src/server/org/opends/server/core/PluginConfigManager.java                                                    |   11 
 opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java                                         |    8 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java                      |    6 
 opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java                                           |   14 
 opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java                                            |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java                     |    6 
 opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java                                            |    2 
 opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java                                               |    6 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java                             |   16 
 opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java                          |    3 
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java                     |    2 
 opends/src/server/org/opends/server/core/ModifyDNOperation.java                                                      | 2046 ------------------------
 opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java                        |    4 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java            |    9 
 opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java                                 |   22 
 opends/src/server/org/opends/server/loggers/AccessLogger.java                                                        |    6 
 32 files changed, 2,770 insertions(+), 2,159 deletions(-)

diff --git a/opends/src/server/org/opends/server/api/AccessControlHandler.java b/opends/src/server/org/opends/server/api/AccessControlHandler.java
index 99d8a58..67f4c8e 100644
--- a/opends/src/server/org/opends/server/api/AccessControlHandler.java
+++ b/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);
 
 
diff --git a/opends/src/server/org/opends/server/api/AccessLogPublisher.java b/opends/src/server/org/opends/server/api/AccessLogPublisher.java
index 126ba97..6bed1c3 100644
--- a/opends/src/server/org/opends/server/api/AccessLogPublisher.java
+++ b/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);
 
 
 
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
index 56125c6..e321013 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
+++ b/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();
diff --git a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java b/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
index aea44cb..b980c79 100644
--- a/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
+++ b/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);
     }
diff --git a/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java b/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
index 50e2393..46aec3a 100644
--- a/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
+++ b/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;
   }
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperation.java b/opends/src/server/org/opends/server/core/ModifyDNOperation.java
index 80db37b..d7b6e3b 100644
--- a/opends/src/server/org/opends/server/core/ModifyDNOperation.java
+++ b/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);
 
 }
-
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java b/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
new file mode 100644
index 0000000..0dedeba
--- /dev/null
+++ b/opends/src/server/org/opends/server/core/ModifyDNOperationBasis.java
@@ -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;
+  }
+
+}
+
diff --git a/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java b/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
new file mode 100644
index 0000000..e1e14a9
--- /dev/null
+++ b/opends/src/server/org/opends/server/core/ModifyDNOperationWrapper.java
@@ -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();
+  }
+}
diff --git a/opends/src/server/org/opends/server/core/PersistentSearch.java b/opends/src/server/org/opends/server/core/PersistentSearch.java
index 0a20345..3aace28 100644
--- a/opends/src/server/org/opends/server/core/PersistentSearch.java
+++ b/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.
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 223c382..fda51ae 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/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;
 
diff --git a/opends/src/server/org/opends/server/loggers/AccessLogger.java b/opends/src/server/org/opends/server/loggers/AccessLogger.java
index ca4586f..33ddf03 100644
--- a/opends/src/server/org/opends/server/loggers/AccessLogger.java
+++ b/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)
     {
diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index d771aea..731c434 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/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)
diff --git a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
index 9ee023e..5388c5e 100644
--- a/opends/src/server/org/opends/server/loggers/TextAuditLogPublisher.java
+++ b/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)
diff --git a/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java b/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
index 448f6fa..ea0b076 100644
--- a/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
+++ b/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);
diff --git a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java b/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
index ce06fad..a0647f2 100644
--- a/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
+++ b/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);
diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
index 9a4bea1..5d1db9a 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/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(),
diff --git a/opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java
index 09ae24f..66d9e56 100644
--- a/opends/src/server/org/opends/server/replication/plugin/ReplicationDomain.java
+++ b/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)
diff --git a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java b/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
index ddce8df..b6ba1de 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ModifyDNMsg.java
+++ b/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),
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
new file mode 100644
index 0000000..02db5e9
--- /dev/null
+++ b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -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;
+  }
+
+
+}
diff --git a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java b/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
index 7d85435..2012bee 100644
--- a/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
+++ b/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
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
index 4b84935..1bdc080 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/GenericBackendTestCase.java
+++ b/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;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
index fa3e3bf..7335ff7 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
+++ b/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);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
index 46895dc..2bc7f8e 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
+++ b/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,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
index dc81c2b..a9bc8f8 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/GroupManagerTestCase.java
+++ b/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);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
index 57aec3b..7caec54 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestModifyDNOperation.java
+++ b/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,
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
index 8639b9c..267404f 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/plugins/LastModPluginTestCase.java
+++ b/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);
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
index 3933296..775f2ea 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/internal/InternalClientConnectionTestCase.java
+++ b/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"));
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
index 2e259ff..f7539f0 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
+++ b/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
     {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
index a4201ca..58cc853 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
+++ b/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
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
index 68de891..cab707d 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
+++ b/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());
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
index ed59add..e3eed8c 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/server/ReplicationServerTest.java
+++ b/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)
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
index 8eea58b..2a25b5b 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
+++ b/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
     {

--
Gitblit v1.10.0