From 2e56b3f76709f8f82fabad8a51362c18cbba5fe4 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 22 Sep 2014 08:46:59 +0000
Subject: [PATCH] OPENDJ-1206 (CR-4368) Create a new ReplicationBackend/ChangelogBackend to support cn=changelog

---
 opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java    |   66 
 opendj3-server-dev/src/server/org/opends/server/util/CollectionUtils.java                                        |  109 ++
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java        |  218 ++--
 opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerSync.java                                    |  283 ++---
 opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java       |   63 
 opendj3-server-dev/src/server/org/opends/server/tools/EncodePassword.java                                        |  248 ++---
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java |  136 +-
 opendj3-server-dev/src/server/org/opends/server/types/DirectoryConfig.java                                       |   43 
 /dev/null                                                                                                        |  134 --
 opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java                                        |   91 -
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java           |  887 +++++------------
 opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java    |   41 
 opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java  |   51 
 opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java        |  294 +++---
 opendj3-server-dev/src/server/org/opends/server/core/AuthenticatedUsers.java                                     |  205 +--
 15 files changed, 1,168 insertions(+), 1,701 deletions(-)

diff --git a/opendj3-server-dev/src/server/org/opends/server/api/ChangeNotificationListener.java b/opendj3-server-dev/src/server/org/opends/server/api/ChangeNotificationListener.java
deleted file mode 100644
index bd0e883..0000000
--- a/opendj3-server-dev/src/server/org/opends/server/api/ChangeNotificationListener.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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
- *
- *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
- */
-package org.opends.server.api;
-
-
-
-import org.opends.server.types.Entry;
-import org.opends.server.types.operation.PostResponseAddOperation;
-import org.opends.server.types.operation.PostResponseDeleteOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
-import org.opends.server.types.operation.
-            PostResponseModifyDNOperation;
-
-
-
-/**
- * This interface defines a mechanism that Directory Server components
- * may use if they need to be notified of changes that are made in the
- * Directory Server.  Similar functionality can be achieved using
- * post-response plugins, but this interface is better suited to core
- * functionality that should not be considered optional, since plugins
- * may be disabled.  Further, change notification listeners will only
- * be invoked for successful operations.
- * <BR><BR>
- * Each change notification listener will be notified whenever an
- * update is made in the server (just before the response is sent to
- * the client), so the listener should use a very efficient mechanism
- * for determining whether or not any action is required for the
- * associated operation and quickly return for cases in which the
- * update is not applicable.  Also note that even though the listener
- * will be invoked before the response is sent to the client, it may
- * not alter that response in any way and therefore the listener will
- * be given what is essentially a read-only view of the associated
- * operation.
- * <BR><BR>
- * Note that while this interface can be used by clients to be
- * notified of changes to the configuration data just as easily as it
- * can be used for any other entry anywhere in the server, components
- * that are only interested in being notified of changes to the server
- * configuration should use the {@code ConfigAddListener},
- * {@code ConfigDeleteListener}, and/or the
- * {@code ConfigChangeListener} interfaces instead.  They will be more
- * efficient overall because they will only be invoked for operations
- * in the server configuration, and then only for the specific entries
- * with which the component has registered.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.VOLATILE,
-     mayInstantiate=false,
-     mayExtend=true,
-     mayInvoke=false)
-public interface ChangeNotificationListener
-{
-  /**
-   * Performs any processing that may be required after an add
-   * operation.
-   *
-   * @param  addOperation  The add operation that was performed in the
-   *                       server.
-   * @param  entry         The entry that was added to the server.
-   */
-  public void handleAddOperation(
-                   PostResponseAddOperation addOperation,
-                   Entry entry);
-
-
-
-  /**
-   * Performs any processing that may be required after a delete
-   * operation.
-   *
-   * @param  deleteOperation  The delete operation that was performed
-   *                          in the server.
-   * @param  entry            The entry that was removed from the
-   *                          server.
-   */
-  public void handleDeleteOperation(
-                   PostResponseDeleteOperation deleteOperation,
-                   Entry entry);
-
-
-
-  /**
-   * Performs any processing that may be required after a modify
-   * operation.
-   *
-   * @param  modifyOperation  The modify operation that was performed
-   *                          in the server.
-   * @param  oldEntry         The entry before it was updated.
-   * @param  newEntry         The entry after it was updated.
-   */
-  public void handleModifyOperation(
-                   PostResponseModifyOperation modifyOperation,
-                   Entry oldEntry, Entry newEntry);
-
-
-
-  /**
-   * Performs any processing that may be required after a modify DN
-   * operation.
-   *
-   * @param  modifyDNOperation  The modify DN operation that was
-   *                            performed in the server.
-   * @param  oldEntry           The entry before it was updated.
-   * @param  newEntry           The entry after it was updated.
-   */
-  public void handleModifyDNOperation(
-                   PostResponseModifyDNOperation modifyDNOperation,
-                   Entry oldEntry, Entry newEntry);
-}
-
diff --git a/opendj3-server-dev/src/server/org/opends/server/core/AuthenticatedUsers.java b/opendj3-server-dev/src/server/org/opends/server/core/AuthenticatedUsers.java
index 0f45e45..f90758f 100644
--- a/opendj3-server-dev/src/server/org/opends/server/core/AuthenticatedUsers.java
+++ b/opendj3-server-dev/src/server/org/opends/server/core/AuthenticatedUsers.java
@@ -25,28 +25,30 @@
  *      Portions Copyright 2011-2014 ForgeRock AS
  */
 package org.opends.server.core;
+
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
-import org.forgerock.i18n.LocalizableMessage;
-
-
-
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.opends.server.api.ChangeNotificationListener;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.DITCacheMap;
-import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.opends.server.types.DisconnectReason;
+import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
+import org.opends.server.api.plugin.PluginResult.PostResponse;
 import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DisconnectReason;
 import org.opends.server.types.Entry;
-import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
 import org.opends.server.types.operation.PostResponseModifyDNOperation;
+import org.opends.server.types.operation.PostResponseModifyOperation;
 
 import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.api.plugin.PluginType.*;
 
 /**
  * This class provides a data structure which maps an authenticated user DN to
@@ -58,31 +60,49 @@
  * user entries and notifying the corresponding client connections so that they
  * can update their cached versions.
  */
-public class AuthenticatedUsers
-       implements ChangeNotificationListener
+public class AuthenticatedUsers extends InternalDirectoryServerPlugin
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
-  // The mapping between authenticated user DNs and the associated client
-  // connection objects.
-  private DITCacheMap<CopyOnWriteArraySet<ClientConnection>> userMap;
+  /**
+   * The mapping between authenticated user DNs and the associated client
+   * connection objects.
+   */
+  private final DITCacheMap<CopyOnWriteArraySet<ClientConnection>> userMap;
 
-  // Lock to protect internal data structures.
+  /** Lock to protect internal data structures. */
   private final ReentrantReadWriteLock lock;
 
+  /** Dummy configuration DN. */
+  private static final String CONFIG_DN = "cn=Authenticated Users,cn=config";
 
   /**
    * Creates a new instance of this authenticated users object.
    */
   public AuthenticatedUsers()
   {
+    super(toDN(CONFIG_DN), EnumSet.of(
+        // No implementation is required for add operations, since a connection
+        // can not be authenticated as a user that does not exist yet.
+        POST_RESPONSE_MODIFY, POST_RESPONSE_MODIFY_DN, POST_RESPONSE_DELETE),
+        true);
     userMap = new DITCacheMap<CopyOnWriteArraySet<ClientConnection>>();
     lock = new ReentrantReadWriteLock();
 
-    DirectoryServer.registerChangeNotificationListener(this);
+    DirectoryServer.registerInternalPlugin(this);
   }
 
-
+  private static DN toDN(String dn)
+  {
+    try
+    {
+      return DN.valueOf(dn);
+    }
+    catch (DirectoryException e)
+    {
+      throw new RuntimeException(e);
+    }
+  }
 
   /**
    * Registers the provided user DN and client connection with this object.
@@ -97,8 +117,7 @@
     lock.writeLock().lock();
     try
     {
-      CopyOnWriteArraySet<ClientConnection> connectionSet =
-              userMap.get(userDN);
+      CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN);
       if (connectionSet == null)
       {
         connectionSet = new CopyOnWriteArraySet<ClientConnection>();
@@ -131,8 +150,7 @@
     lock.writeLock().lock();
     try
     {
-      CopyOnWriteArraySet<ClientConnection> connectionSet =
-              userMap.get(userDN);
+      CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN);
       if (connectionSet != null)
       {
         connectionSet.remove(clientConnection);
@@ -174,89 +192,57 @@
     }
   }
 
-
-
-  /**
-   * Performs any processing that may be required after an add
-   * operation.
-   *
-   * @param  addOperation  The add operation that was performed in the
-   *                       server.
-   * @param  entry         The entry that was added to the server.
-   */
-  public void handleAddOperation(
-                   PostResponseAddOperation addOperation,
-                   Entry entry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseDeleteOperation op)
   {
-    // No implementation is required for add operations, since a connection
-    // can't be authenticated as a user that doesn't exist yet.
-  }
+    if (op.getResultCode() != ResultCode.SUCCESS) {
+      return PostResponse.continueOperationProcessing();
+    }
 
-
-
-  /**
-   * Performs any processing that may be required after a delete
-   * operation.
-   *
-   * @param  deleteOperation  The delete operation that was performed
-   *                          in the server.
-   * @param  entry            The entry that was removed from the
-   *                          server.
-   */
-  public void handleDeleteOperation(
-                   PostResponseDeleteOperation deleteOperation,
-                   Entry entry)
-  {
+    final DN entryDN = op.getEntryDN();
     // Identify any client connections that may be authenticated
-    // or authorized as the user whose entry has been deleted and
-    // terminate them.
+    // or authorized as the user whose entry has been deleted and terminate them
     Set<CopyOnWriteArraySet<ClientConnection>> arraySet =
             new HashSet<CopyOnWriteArraySet<ClientConnection>>();
     lock.writeLock().lock();
     try
     {
-      userMap.removeSubtree(entry.getName(), arraySet);
+      userMap.removeSubtree(entryDN, arraySet);
     }
     finally
     {
       lock.writeLock().unlock();
     }
-    for (CopyOnWriteArraySet<ClientConnection>
-            connectionSet : arraySet)
+
+    for (CopyOnWriteArraySet<ClientConnection> connectionSet : arraySet)
     {
       for (ClientConnection conn : connectionSet)
       {
-        LocalizableMessage message = WARN_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE.get(
-                entry.getName());
-
+        LocalizableMessage message = WARN_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE.get(entryDN);
         conn.disconnect(DisconnectReason.INVALID_CREDENTIALS, true, message);
       }
     }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
-  /**
-   * Performs any processing that may be required after a modify
-   * operation.
-   *
-   * @param  modifyOperation  The modify operation that was performed
-   *                          in the server.
-   * @param  oldEntry         The entry before it was updated.
-   * @param  newEntry         The entry after it was updated.
-   */
-  public void handleModifyOperation(
-                   PostResponseModifyOperation modifyOperation,
-                   Entry oldEntry, Entry newEntry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseModifyOperation op)
   {
+    if (op.getResultCode() != ResultCode.SUCCESS) {
+      return PostResponse.continueOperationProcessing();
+    }
+
+    final Entry oldEntry = op.getCurrentEntry();
+    final Entry newEntry = op.getModifiedEntry();
     // Identify any client connections that may be authenticated
     // or authorized as the user whose entry has been modified
     // and update them with the latest version of the entry.
     lock.writeLock().lock();
     try
     {
-      CopyOnWriteArraySet<ClientConnection> connectionSet =
-           userMap.get(oldEntry.getName());
+      CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(oldEntry.getName());
       if (connectionSet != null)
       {
         for (ClientConnection conn : connectionSet)
@@ -269,23 +255,19 @@
     {
       lock.writeLock().unlock();
     }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
-  /**
-   * Performs any processing that may be required after a modify DN
-   * operation.
-   *
-   * @param  modifyDNOperation  The modify DN operation that was
-   *                            performed in the server.
-   * @param  oldEntry           The entry before it was updated.
-   * @param  newEntry           The entry after it was updated.
-   */
-  public void handleModifyDNOperation(
-                   PostResponseModifyDNOperation modifyDNOperation,
-                   Entry oldEntry, Entry newEntry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseModifyDNOperation op)
   {
+    if (op.getResultCode() != ResultCode.SUCCESS) {
+      return PostResponse.continueOperationProcessing();
+    }
+
+    Entry oldEntry = op.getOriginalEntry();
+    Entry newEntry = op.getUpdatedEntry();
     String oldDNString = oldEntry.getName().toNormalizedString();
     String newDNString = newEntry.getName().toNormalizedString();
 
@@ -298,8 +280,7 @@
       Set<CopyOnWriteArraySet<ClientConnection>> arraySet =
         new HashSet<CopyOnWriteArraySet<ClientConnection>>();
       userMap.removeSubtree(oldEntry.getName(), arraySet);
-      for (CopyOnWriteArraySet<ClientConnection>
-              connectionSet : arraySet)
+      for (CopyOnWriteArraySet<ClientConnection> connectionSet : arraySet)
       {
         DN authNDN = null;
         DN authZDN = null;
@@ -314,17 +295,11 @@
             authNDN = conn.getAuthenticationInfo().getAuthenticationDN();
             try
             {
-              StringBuilder builder = new StringBuilder(
-                  authNDN.toNormalizedString());
-              int oldDNIndex = builder.lastIndexOf(oldDNString);
-              builder.replace(oldDNIndex, builder.length(),
-                      newDNString);
-              String newAuthNDNString = builder.toString();
-              newAuthNDN = DN.valueOf(newAuthNDNString);
+              newAuthNDN = getNewAuthDN(authNDN, oldDNString, newDNString);
             }
             catch (Exception e)
             {
-              // Shouldnt happen.
+              // Should not happen.
               logger.traceException(e);
             }
           }
@@ -333,21 +308,15 @@
             authZDN = conn.getAuthenticationInfo().getAuthorizationDN();
             try
             {
-              StringBuilder builder = new StringBuilder(
-                  authZDN.toNormalizedString());
-              int oldDNIndex = builder.lastIndexOf(oldDNString);
-              builder.replace(oldDNIndex, builder.length(),
-                      newDNString);
-              String newAuthZDNString = builder.toString();
-              newAuthZDN = DN.valueOf(newAuthZDNString);
+              newAuthZDN = getNewAuthDN(authZDN, oldDNString, newDNString);
             }
             catch (Exception e)
             {
-              // Shouldnt happen.
+              // Should not happen.
               logger.traceException(e);
             }
           }
-          if ((newAuthNDN != null) && (authNDN != null) &&
+          if (newAuthNDN != null && authNDN != null &&
                authNDN.isDescendantOf(oldEntry.getName()))
           {
             if (newAuthNSet == null)
@@ -357,7 +326,7 @@
             conn.getAuthenticationInfo().setAuthenticationDN(newAuthNDN);
             newAuthNSet.add(conn);
           }
-          if ((newAuthZDN != null) && (authZDN != null) &&
+          if (newAuthZDN != null && authZDN != null &&
                authZDN.isDescendantOf(oldEntry.getName()))
           {
             if (newAuthZSet == null)
@@ -368,11 +337,11 @@
             newAuthZSet.add(conn);
           }
         }
-        if ((newAuthNDN != null) && (newAuthNSet != null))
+        if (newAuthNDN != null && newAuthNSet != null)
         {
           userMap.put(newAuthNDN, newAuthNSet);
         }
-        if ((newAuthZDN != null) && (newAuthZSet != null))
+        if (newAuthZDN != null && newAuthZSet != null)
         {
           userMap.put(newAuthZDN, newAuthZSet);
         }
@@ -382,6 +351,18 @@
     {
       lock.writeLock().unlock();
     }
+    return PostResponse.continueOperationProcessing();
+  }
+
+  private DN getNewAuthDN(DN authDN, String oldDNString, String newDNString) throws DirectoryException
+  {
+    // FIXME once we move to the SDK:
+    // Matt suggests we should be using the following code here:
+    // return authDN.rename(oldDNString, newDNString);
+    final StringBuilder builder = new StringBuilder(authDN.toNormalizedString());
+    final int oldDNIndex = builder.lastIndexOf(oldDNString);
+    builder.replace(oldDNIndex, builder.length(), newDNString);
+    return DN.valueOf(builder.toString());
   }
 }
 
diff --git a/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java b/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
index d66cfdf..f5a3d13 100644
--- a/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/core/DirectoryServer.java
@@ -26,16 +26,6 @@
  */
 package org.opends.server.core;
 
-import static org.forgerock.util.Reject.*;
-import static org.opends.messages.ConfigMessages.*;
-import static org.opends.messages.CoreMessages.*;
-import static org.opends.messages.ToolMessages.*;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.schema.SchemaConstants.*;
-import static org.opends.server.util.DynamicConstants.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -93,14 +83,12 @@
 import org.opends.server.api.AccountStatusNotificationHandler;
 import org.opends.server.api.AlertGenerator;
 import org.opends.server.api.AlertHandler;
-import org.opends.server.api.MatchingRule;
 import org.opends.server.api.AttributeSyntax;
 import org.opends.server.api.AuthenticationPolicy;
 import org.opends.server.api.Backend;
 import org.opends.server.api.BackendInitializationListener;
 import org.opends.server.api.BackupTaskListener;
 import org.opends.server.api.CertificateMapper;
-import org.opends.server.api.ChangeNotificationListener;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.CompressedSchema;
 import org.opends.server.api.ConfigAddListener;
@@ -119,6 +107,7 @@
 import org.opends.server.api.InitializationCompletedListener;
 import org.opends.server.api.InvokableComponent;
 import org.opends.server.api.KeyManagerProvider;
+import org.opends.server.api.MatchingRule;
 import org.opends.server.api.MatchingRuleFactory;
 import org.opends.server.api.MonitorProvider;
 import org.opends.server.api.PasswordGenerator;
@@ -238,6 +227,16 @@
 import com.forgerock.opendj.cli.StringArgument;
 import com.forgerock.opendj.util.OperatingSystem;
 
+import static org.forgerock.util.Reject.*;
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.CoreMessages.*;
+import static org.opends.messages.ToolMessages.*;
+import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.schema.SchemaConstants.*;
+import static org.opends.server.util.DynamicConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
 /**
  * This class defines the core of the Directory Server.  It manages the startup
  * and shutdown processes and coordinates activities between all other
@@ -547,13 +546,6 @@
   /** The set of backup task listeners registered with the Directory Server. */
   private CopyOnWriteArrayList<BackupTaskListener> backupTaskListeners;
 
-  /**
-   * The set of change notification listeners registered with the Directory
-   * Server.
-   */
-  private List<ChangeNotificationListener>
-               changeNotificationListeners;
-
   /** The set of connection handlers registered with the Directory Server. */
   private List<ConnectionHandler> connectionHandlers;
 
@@ -1145,8 +1137,6 @@
       directoryServer.backendInitializationListeners =
            new CopyOnWriteArraySet<BackendInitializationListener>();
       directoryServer.baseDnRegistry = new BaseDnRegistry();
-      directoryServer.changeNotificationListeners =
-           new CopyOnWriteArrayList<ChangeNotificationListener>();
       directoryServer.initializationCompletedListeners =
            new CopyOnWriteArrayList<InitializationCompletedListener>();
       directoryServer.shutdownListeners =
@@ -1164,7 +1154,6 @@
            new ConcurrentHashMap<String,ExtendedOperationHandler>();
       directoryServer.saslMechanismHandlers =
            new ConcurrentHashMap<String,SASLMechanismHandler>();
-      directoryServer.authenticatedUsers = new AuthenticatedUsers();
       directoryServer.offlineSchemaChanges = new LinkedList<Modification>();
       directoryServer.backupTaskListeners =
            new CopyOnWriteArrayList<BackupTaskListener>();
@@ -1586,8 +1575,9 @@
 
       initializeRootDNConfigManager();
 
+      initializeAuthenticatedUsers();
+      // initialize both subentry manager and group manager for this backend.
       initializeSubentryManager();
-
       initializeGroupManager();
 
       // Initialize both subentry manager and group manager
@@ -1622,7 +1612,6 @@
       directoryServer.offlineBackendsStateIDs.clear();
 
       initializeExtendedOperations();
-
       initializeSASLMechanisms();
 
       if (startConnectionHandlers)
@@ -1720,6 +1709,12 @@
     }
   }
 
+  /** Initializes authenticated users. */
+  public void initializeAuthenticatedUsers()
+  {
+    directoryServer.authenticatedUsers = new AuthenticatedUsers();
+  }
+
   /**
    * Registers a basic set of matching rules with the server that should always
    * be available regardless of the server configuration and may be needed for
@@ -6824,54 +6819,6 @@
     return directoryServer.workQueue.trySubmitOperation(operation);
   }
 
-
-  /**
-   * Retrieves the set of change notification listeners registered with the
-   * Directory Server.
-   *
-   * @return  The set of change notification listeners registered with the
-   *          Directory Server.
-   */
-  public static List<ChangeNotificationListener>
-                     getChangeNotificationListeners()
-  {
-    return directoryServer.changeNotificationListeners;
-  }
-
-
-
-  /**
-   * Registers the provided change notification listener with the Directory
-   * Server so that it will be notified of any add, delete, modify, or modify DN
-   * operations that are performed.
-   *
-   * @param  changeListener  The change notification listener to register with
-   *                         the Directory Server.
-   */
-  public static void registerChangeNotificationListener(
-                          ChangeNotificationListener changeListener)
-  {
-    directoryServer.changeNotificationListeners.add(changeListener);
-  }
-
-
-
-  /**
-   * Deregisters the provided change notification listener with the Directory
-   * Server so that it will no longer be notified of any add, delete, modify, or
-   * modify DN operations that are performed.
-   *
-   * @param  changeListener  The change notification listener to deregister with
-   *                         the Directory Server.
-   */
-  public static void deregisterChangeNotificationListener(
-                          ChangeNotificationListener changeListener)
-  {
-    directoryServer.changeNotificationListeners.remove(changeListener);
-  }
-
-
-
   /**
    * Retrieves the set of synchronization providers that have been registered
    * with the Directory Server.
diff --git a/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerSync.java b/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerSync.java
index 6bc9cf7..13648db 100644
--- a/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerSync.java
+++ b/opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerSync.java
@@ -26,14 +26,23 @@
  */
 package org.opends.server.crypto;
 
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.admin.ads.ADSContext;
 import org.opends.server.api.Backend;
 import org.opends.server.api.BackendInitializationListener;
-import org.opends.server.api.ChangeNotificationListener;
+import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
+import org.opends.server.api.plugin.PluginResult.PostResponse;
 import org.opends.server.config.ConfigConstants;
 import org.opends.server.controls.EntryChangeNotificationControl;
 import org.opends.server.controls.PersistentSearchChangeType;
@@ -43,71 +52,75 @@
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.LDAPControl;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.Control;
+import org.opends.server.types.CryptoManagerException;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.ObjectClass;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
 import org.opends.server.types.operation.PostResponseModifyOperation;
-import org.opends.server.types.operation.PostResponseModifyDNOperation;
 
 import static org.opends.messages.CoreMessages.*;
+import static org.opends.server.api.plugin.PluginType.*;
 import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
-import java.util.LinkedHashSet;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.HashMap;
-
 /**
  * This class defines an object that synchronizes certificates from the admin
  * data branch into the trust store backend, and synchronizes secret-key entries
  * from the admin data branch to the crypto manager secret-key cache.
  */
-public class CryptoManagerSync
-     implements BackendInitializationListener, ChangeNotificationListener
+public class CryptoManagerSync extends InternalDirectoryServerPlugin
+     implements BackendInitializationListener
 {
-  /**
-   * The debug log tracer for this object.
-   */
+  /** The debug log tracer for this object. */
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
-
-
-  // The DN of the administration suffix.
+  /** The DN of the administration suffix. */
   private DN adminSuffixDN;
 
-  // The DN of the instance keys container within the admin suffix.
+  /** The DN of the instance keys container within the admin suffix. */
   private DN instanceKeysDN;
 
-  // The DN of the secret keys container within the admin suffix.
+  /** The DN of the secret keys container within the admin suffix. */
   private DN secretKeysDN;
 
-  // The DN of the trust store root.
+  /** The DN of the trust store root. */
   private DN trustStoreRootDN;
 
-  // The attribute type that is used to specify a server instance certificate.
-  AttributeType attrCert;
+  /** The attribute type that is used to specify a server instance certificate. */
+  private final AttributeType attrCert;
 
-  // The attribute type that holds a server certificate identifier.
-  AttributeType attrAlias;
+  /** The attribute type that holds a server certificate identifier. */
+  private final AttributeType attrAlias;
 
-  // The attribute type that holds the time a key was compromised.
-  AttributeType attrCompromisedTime;
+  /** The attribute type that holds the time a key was compromised. */
+  private final AttributeType attrCompromisedTime;
 
-  // A filter on object class to select key entries.
+  /** A filter on object class to select key entries. */
   private SearchFilter keySearchFilter;
 
-  // The instance key objectclass.
-  private ObjectClass ocInstanceKey;
+  /** The instance key objectclass. */
+  private final ObjectClass ocInstanceKey;
 
-  // The cipher key objectclass.
-  private ObjectClass ocCipherKey;
+  /** The cipher key objectclass. */
+  private final ObjectClass ocCipherKey;
 
-  // The mac key objectclass.
-  private ObjectClass ocMacKey;
+  /** The mac key objectclass. */
+  private final ObjectClass ocMacKey;
+
+  /** Dummy configuration DN. */
+  private static final String CONFIG_DN = "cn=Crypto Manager Sync,cn=config";
 
   /**
    * Creates a new instance of this trust store synchronization thread.
@@ -116,29 +129,17 @@
    * initialization, such as a failure to publish the instance-key-pair
    * public-key-certificate in ADS.
    */
-  public CryptoManagerSync()
-          throws InitializationException
+  public CryptoManagerSync() throws InitializationException
   {
-    this(true);
-  }
-
-  /**
-   * Creates a new instance of this trust store synchronization thread.
-   *
-   * @param publishInstanceKey whether the instance key must be published in
-   * the ADS or not.
-   * @throws InitializationException in case an exception occurs during
-   * initialization, such as a failure to publish the instance-key-pair
-   * public-key-certificate in ADS.
-   */
-  public CryptoManagerSync(boolean publishInstanceKey)
-  throws InitializationException
-  {
+    super(toDN(CONFIG_DN), EnumSet.of(
+        // No implementation required for modify_dn operations
+        // FIXME: Technically it is possible to perform a subtree modDN
+        // in this case however such subtree modDN would essentially be
+        // moving configuration branches which should not happen.
+        POST_RESPONSE_ADD, POST_RESPONSE_MODIFY, POST_RESPONSE_DELETE),
+        true);
     try {
-      if (publishInstanceKey)
-      {
-        CryptoManagerImpl.publishInstanceKeyEntryInADS();
-      }
+      CryptoManagerImpl.publishInstanceKeyEntryInADS();
     }
     catch (CryptoManagerException ex) {
       throw new InitializationException(ex.getMessageObject());
@@ -160,15 +161,11 @@
     }
     catch (DirectoryException e)
     {
-      //
     }
 
-    ocInstanceKey = DirectoryServer.getObjectClass(
-         OC_CRYPTO_INSTANCE_KEY, true);
-    ocCipherKey = DirectoryServer.getObjectClass(
-         OC_CRYPTO_CIPHER_KEY, true);
-    ocMacKey = DirectoryServer.getObjectClass(
-         OC_CRYPTO_MAC_KEY, true);
+    ocInstanceKey = DirectoryServer.getObjectClass(OC_CRYPTO_INSTANCE_KEY, true);
+    ocCipherKey = DirectoryServer.getObjectClass(OC_CRYPTO_CIPHER_KEY, true);
+    ocMacKey = DirectoryServer.getObjectClass(OC_CRYPTO_MAC_KEY, true);
 
     attrCert = DirectoryServer.getAttributeType(
          ConfigConstants.ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE, true);
@@ -182,22 +179,32 @@
       searchAdminSuffix();
     }
 
-    DirectoryServer.registerChangeNotificationListener(this);
+    DirectoryServer.registerInternalPlugin(this);
+  }
+
+  private static DN toDN(final String dn) throws InitializationException
+  {
+    try
+    {
+      return DN.valueOf(dn);
+    }
+    catch (DirectoryException e)
+    {
+      throw new RuntimeException(e);
+    }
   }
 
 
   private void searchAdminSuffix()
   {
-    InternalClientConnection conn =
-         InternalClientConnection.getRootConnection();
     LinkedHashSet<String> attributes = new LinkedHashSet<String>(0);
 
     ArrayList<Control> controls = new ArrayList<Control>(0);
 
     InternalSearchOperation searchOperation =
-         new InternalSearchOperation(conn,
-                                     InternalClientConnection.nextOperationID(),
-                                     InternalClientConnection.nextMessageID(),
+         new InternalSearchOperation(getRootConnection(),
+                                     nextOperationID(),
+                                     nextMessageID(),
                                      controls,
                                      adminSuffixDN, SearchScope.WHOLE_SUBTREE,
                                      DereferenceAliasesPolicy.NEVER,
@@ -231,9 +238,7 @@
   }
 
 
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public void performBackendInitializationProcessing(Backend backend)
   {
@@ -250,9 +255,7 @@
     }
   }
 
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
   public void performBackendFinalizationProcessing(Backend backend)
   {
@@ -306,7 +309,7 @@
       {
         for (Control c : controls)
         {
-          if (c.getOID().equals(OID_ENTRY_CHANGE_NOTIFICATION))
+          if (OID_ENTRY_CHANGE_NOTIFICATION.equals(c.getOID()))
           {
             if (c instanceof LDAPControl)
             {
@@ -331,8 +334,7 @@
       if (ecn != null &&
            ecn.getChangeType() == PersistentSearchChangeType.DELETE)
       {
-        // The entry was deleted so we should remove it from the local trust
-        // store.
+        // entry was deleted so remove it from the local trust store
         if (dstEntry != null)
         {
           deleteEntry(dstDN);
@@ -340,24 +342,21 @@
       }
       else if (searchEntry.hasAttribute(attrCompromisedTime))
       {
-        // The key was compromised so we should remove it from the local
-        // trust store.
+        // key was compromised so remove it from the local trust store
         if (dstEntry != null)
         {
           deleteEntry(dstDN);
         }
       }
+      else if (dstEntry == null)
+      {
+        // The entry was added
+        addEntry(searchEntry, dstDN);
+      }
       else
       {
-        // The entry was added or modified.
-        if (dstEntry == null)
-        {
-          addEntry(searchEntry, dstDN);
-        }
-        else
-        {
-          modifyEntry(searchEntry, dstEntry);
-        }
+        // The entry was modified
+        modifyEntry(searchEntry, dstEntry);
       }
     }
   }
@@ -371,11 +370,8 @@
    */
   private void modifyEntry(Entry srcEntry, Entry dstEntry)
   {
-    List<Attribute> srcList;
-    srcList = srcEntry.getAttribute(attrCert);
-
-    List<Attribute> dstList;
-    dstList = dstEntry.getAttribute(attrCert);
+    List<Attribute> srcList = srcEntry.getAttribute(attrCert);
+    List<Attribute> dstList = dstEntry.getAttribute(attrCert);
 
     // Check for changes to the certificate value.
     boolean differ = false;
@@ -386,21 +382,12 @@
         differ = true;
       }
     }
-    else if (dstList == null)
+    else if (dstList == null
+        || srcList.size() != dstList.size()
+        || !srcList.equals(dstList))
     {
       differ = true;
     }
-    else if (srcList.size() != dstList.size())
-    {
-      differ = true;
-    }
-    else
-    {
-      if (!srcList.equals(dstList))
-      {
-        differ = true;
-      }
-    }
 
     if (differ)
     {
@@ -470,19 +457,22 @@
     }
   }
 
-
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
-  public void handleAddOperation(PostResponseAddOperation addOperation,
-                                 Entry entry)
+  public PostResponse doPostResponse(PostResponseAddOperation op)
   {
-    if (addOperation.getEntryDN().isDescendantOf(instanceKeysDN))
+    if (op.getResultCode() != ResultCode.SUCCESS)
+    {
+      return PostResponse.continueOperationProcessing();
+    }
+
+    final Entry entry = op.getEntryToAdd();
+    final DN entryDN = op.getEntryDN();
+    if (entryDN.isDescendantOf(instanceKeysDN))
     {
       handleInstanceKeyAddOperation(entry);
     }
-    else if (addOperation.getEntryDN().isDescendantOf(secretKeysDN))
+    else if (entryDN.isDescendantOf(secretKeysDN))
     {
       try
       {
@@ -501,6 +491,7 @@
             "Failed to import key entry: %s", e.getMessage()));
       }
     }
+    return PostResponse.continueOperationProcessing();
   }
 
 
@@ -521,19 +512,17 @@
     }
   }
 
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
-  public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation,
-                                    Entry entry)
+  public PostResponse doPostResponse(PostResponseDeleteOperation op)
   {
-    if (!deleteOperation.getEntryDN().isDescendantOf(instanceKeysDN))
+    if (op.getResultCode() != ResultCode.SUCCESS
+        || !op.getEntryDN().isDescendantOf(instanceKeysDN))
     {
-      return;
+      return PostResponse.continueOperationProcessing();
     }
 
-    RDN srcRDN = entry.getName().rdn();
+    RDN srcRDN = op.getEntryToDelete().getName().rdn();
 
     // Only process the entry if it has the expected form of RDN.
     // FIXME: Technically it is possible to perform a subtree in
@@ -542,24 +531,28 @@
     if (!srcRDN.isMultiValued() &&
          srcRDN.getAttributeType(0).equals(attrAlias))
     {
-      DN dstDN = trustStoreRootDN.child(srcRDN);
-
-      deleteEntry(dstDN);
+      DN destDN = trustStoreRootDN.child(srcRDN);
+      deleteEntry(destDN);
     }
+    return PostResponse.continueOperationProcessing();
   }
 
-  /**
-   * {@inheritDoc}
-   */
+  /** {@inheritDoc} */
   @Override
-  public void handleModifyOperation(PostResponseModifyOperation modifyOperation,
-                                    Entry oldEntry, Entry newEntry)
+  public PostResponse doPostResponse(PostResponseModifyOperation op)
   {
-    if (modifyOperation.getEntryDN().isDescendantOf(instanceKeysDN))
+    if (op.getResultCode() != ResultCode.SUCCESS)
+    {
+      return PostResponse.continueOperationProcessing();
+    }
+
+    final Entry newEntry = op.getModifiedEntry();
+    final DN entryDN = op.getEntryDN();
+    if (entryDN.isDescendantOf(instanceKeysDN))
     {
       handleInstanceKeyModifyOperation(newEntry);
     }
-    else if (modifyOperation.getEntryDN().isDescendantOf(secretKeysDN))
+    else if (entryDN.isDescendantOf(secretKeysDN))
     {
       try
       {
@@ -578,6 +571,7 @@
             "Failed to import modified key entry: %s", e.getMessage()));
       }
     }
+    return PostResponse.continueOperationProcessing();
   }
 
   private void handleInstanceKeyModifyOperation(Entry newEntry)
@@ -610,31 +604,14 @@
           deleteEntry(dstDN);
         }
       }
+      else if (dstEntry == null)
+      {
+        addEntry(newEntry, dstDN);
+      }
       else
       {
-        if (dstEntry == null)
-        {
-          addEntry(newEntry, dstDN);
-        }
-        else
-        {
-          modifyEntry(newEntry, dstEntry);
-        }
+        modifyEntry(newEntry, dstEntry);
       }
     }
   }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void handleModifyDNOperation(
-       PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry,
-       Entry newEntry)
-  {
-    // No implementation required.
-    // FIXME: Technically it is possible to perform a subtree modDN
-    // in this case however such subtree modDN would essentially be
-    // moving configuration branches which should not happen.
-  }
 }
diff --git a/opendj3-server-dev/src/server/org/opends/server/tools/EncodePassword.java b/opendj3-server-dev/src/server/org/opends/server/tools/EncodePassword.java
index 8cf2f5b..7cfe209 100644
--- a/opendj3-server-dev/src/server/org/opends/server/tools/EncodePassword.java
+++ b/opendj3-server-dev/src/server/org/opends/server/tools/EncodePassword.java
@@ -31,8 +31,7 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collections;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.forgerock.i18n.LocalizableMessage;
@@ -43,7 +42,6 @@
 import org.opends.server.admin.std.server.TrustStoreBackendCfg;
 import org.opends.server.api.Backend;
 import org.opends.server.api.PasswordStorageScheme;
-import org.opends.server.api.plugin.PluginType;
 import org.opends.server.config.ConfigConstants;
 import org.opends.server.config.ConfigEntry;
 import org.forgerock.opendj.config.server.ConfigException;
@@ -334,18 +332,15 @@
     // If we are not going to just list the storage schemes, then the clear-text
     // password must have been provided.  If we're going to encode a password,
     // then the scheme must have also been provided.
-    ByteString clearPW = null;
-    if (! listSchemes.isPresent())
+    if (!listSchemes.isPresent()
+        && !encodedPassword.isPresent()
+        && !encodedPasswordFile.isPresent()
+        && !schemeName.isPresent())
     {
-      if ((! encodedPassword.isPresent()) && (! encodedPasswordFile.isPresent())
-           && (! schemeName.isPresent()))
-      {
-        LocalizableMessage message =
-                ERR_ENCPW_NO_SCHEME.get(schemeName.getLongIdentifier());
-        err.println(wrapText(message, MAX_LINE_WIDTH));
-        err.println(argParser.getUsage());
-        return OPERATIONS_ERROR;
-      }
+      LocalizableMessage message = ERR_ENCPW_NO_SCHEME.get(schemeName.getLongIdentifier());
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+      err.println(argParser.getUsage());
+      return OPERATIONS_ERROR;
     }
 
 
@@ -463,7 +458,9 @@
 
 
       if(!initializeServerComponents(directoryServer, err))
-          return -1;
+      {
+        return -1;
+      }
 
       // Initialize the password storage schemes.
       try
@@ -502,71 +499,19 @@
     {
       if (authPasswordSyntax.isPresent())
       {
-        ConcurrentHashMap<String,PasswordStorageScheme> storageSchemes =
-             DirectoryServer.getAuthPasswordStorageSchemes();
-        if (storageSchemes.isEmpty())
-        {
-          LocalizableMessage message = ERR_ENCPW_NO_STORAGE_SCHEMES.get();
-          err.println(wrapText(message, MAX_LINE_WIDTH));
-        }
-        else
-        {
-          int size = storageSchemes.size();
-
-          ArrayList<String> nameList = new ArrayList<String>(size);
-          for (PasswordStorageScheme s : storageSchemes.values())
-          {
-            nameList.add(s.getAuthPasswordSchemeName());
-          }
-
-          String[] nameArray = new String[size];
-          nameList.toArray(nameArray);
-          Arrays.sort(nameArray);
-
-          for (String storageSchemeName : nameArray)
-          {
-            out.println(storageSchemeName);
-          }
-        }
-
-        return SUCCESS;
+        listPasswordStorageSchemes(out, err, DirectoryServer.getAuthPasswordStorageSchemes(), true);
       }
       else
       {
-        ConcurrentHashMap<String,PasswordStorageScheme> storageSchemes =
-             DirectoryServer.getPasswordStorageSchemes();
-        if (storageSchemes.isEmpty())
-        {
-          LocalizableMessage message = ERR_ENCPW_NO_STORAGE_SCHEMES.get();
-          err.println(wrapText(message, MAX_LINE_WIDTH));
-        }
-        else
-        {
-          int size = storageSchemes.size();
-
-          ArrayList<String> nameList = new ArrayList<String>(size);
-          for (PasswordStorageScheme s : storageSchemes.values())
-          {
-            nameList.add(s.getStorageSchemeName());
-          }
-
-          String[] nameArray = new String[size];
-          nameList.toArray(nameArray);
-          Arrays.sort(nameArray);
-
-          for (String storageSchemeName : nameArray)
-          {
-            out.println(storageSchemeName);
-          }
-        }
-
-        return SUCCESS;
+        listPasswordStorageSchemes(out, err, DirectoryServer.getPasswordStorageSchemes(), false);
       }
+      return SUCCESS;
     }
 
 
     // Either encode the clear-text password using the provided scheme, or
     // compare the clear-text password against the encoded password.
+    ByteString clearPW = null;
     if (compareMode)
     {
       // Check to see if the provided password value was encoded.  If so, then
@@ -798,6 +743,37 @@
     return SUCCESS;
   }
 
+  private static void listPasswordStorageSchemes(PrintStream out, PrintStream err,
+      ConcurrentHashMap<String, PasswordStorageScheme> storageSchemes, boolean authPasswordSchemeName)
+  {
+    if (storageSchemes.isEmpty())
+    {
+      LocalizableMessage message = ERR_ENCPW_NO_STORAGE_SCHEMES.get();
+      err.println(wrapText(message, MAX_LINE_WIDTH));
+    }
+    else
+    {
+      ArrayList<String> nameList = new ArrayList<String>(storageSchemes.size());
+      for (PasswordStorageScheme<?> s : storageSchemes.values())
+      {
+        if (authPasswordSchemeName)
+        {
+          nameList.add(s.getAuthPasswordSchemeName());
+        }
+        else
+        {
+          nameList.add(s.getStorageSchemeName());
+        }
+      }
+      Collections.sort(nameList);
+
+      for (String storageSchemeName : nameList)
+      {
+        out.println(storageSchemeName);
+      }
+    }
+  }
+
   private static LocalizableMessage getOutputMessage(boolean passwordMatches)
   {
     if (passwordMatches)
@@ -809,10 +785,8 @@
 
 
 
-  private static boolean
-          initializeServerComponents(DirectoryServer directoryServer,
-                                     PrintStream err) {
-
+  private static boolean initializeServerComponents(DirectoryServer directoryServer, PrintStream err)
+  {
       // Initialize the Directory Server crypto manager.
       try
       {
@@ -843,19 +817,13 @@
       //secret keys from the trust store backend (3DES, BLOWFISH, AES, RC4) via
       //the crypto-manager.
       try {
-          // Initialize the root DNs.
           directoryServer.initializeRootDNConfigManager();
-          //Initialize plugins.
-          HashSet<PluginType> pluginTypes = new HashSet<PluginType>(1);
-          directoryServer.initializePlugins(pluginTypes);
-          //Initialize Trust Backend.
+          directoryServer.initializePlugins(Collections.EMPTY_SET);
           initializeServerBackends(directoryServer, err);
-          // Initialize the subentry manager.
           directoryServer.initializeSubentryManager();
-          //Initialize PWD policy components.
           directoryServer.initializeAuthenticationPolicyComponents();
-          //Load the crypto-manager key cache among other things.
-         new CryptoManagerSync();
+          directoryServer.initializeAuthenticatedUsers();
+          new CryptoManagerSync();
     } catch (InitializationException ie) {
         LocalizableMessage message = ERR_ENCPW_CANNOT_INITIALIZE_SERVER_COMPONENTS.get(
                 getExceptionMessage(ie));
@@ -891,39 +859,39 @@
     for (String name : root.listBackends()) {
       BackendCfg backendCfg = root.getBackend(name);
       String backendID = backendCfg.getBackendId();
-      if(backendCfg instanceof TrustStoreBackendCfg ||
-          backendCfg instanceof LDIFBackendCfg) {
-        if(backendCfg.isEnabled()) {
-          String className = backendCfg.getJavaClass();
-          Class backendClass;
-          Backend backend;
-          try {
-            backendClass = DirectoryServer.loadClass(className);
-            backend = (Backend) backendClass.newInstance();
-          } catch (Exception e) {
-            LocalizableMessage msg = ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE.get(className, backendCfg.dn(),
-                stackTraceToSingleLineString(e));
-            err.println(wrapText(msg, MAX_LINE_WIDTH));
-            continue;
-          }
-          backend.setBackendID(backendID);
-          backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
-          try {
-            backend.configureBackend(backendCfg);
-            backend.initializeBackend();
-          } catch (Exception e) {
-            LocalizableMessage msg = ERR_CONFIG_BACKEND_CANNOT_INITIALIZE.get(className, backendCfg.dn(),
-                  stackTraceToSingleLineString(e));
-            err.println(wrapText(msg, MAX_LINE_WIDTH));
-          }
-          try {
-            DirectoryServer.registerBackend(backend);
-          } catch (Exception e)
-          {
-            LocalizableMessage msg = WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(),
-                  getExceptionMessage(e));
-            err.println(wrapText(msg, MAX_LINE_WIDTH));
-          }
+      if((backendCfg instanceof TrustStoreBackendCfg
+          || backendCfg instanceof LDIFBackendCfg)
+          && backendCfg.isEnabled())
+      {
+        String className = backendCfg.getJavaClass();
+        Class<?> backendClass;
+        Backend<BackendCfg> backend;
+        try {
+          backendClass = DirectoryServer.loadClass(className);
+          backend = (Backend<BackendCfg>) backendClass.newInstance();
+        } catch (Exception e) {
+          LocalizableMessage msg = ERR_CONFIG_BACKEND_CANNOT_INSTANTIATE.get(className, backendCfg.dn(),
+              stackTraceToSingleLineString(e));
+          err.println(wrapText(msg, MAX_LINE_WIDTH));
+          continue;
+        }
+        backend.setBackendID(backendID);
+        backend.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
+        try {
+          backend.configureBackend(backendCfg);
+          backend.initializeBackend();
+        } catch (Exception e) {
+          LocalizableMessage msg = ERR_CONFIG_BACKEND_CANNOT_INITIALIZE.get(className, backendCfg.dn(),
+              stackTraceToSingleLineString(e));
+          err.println(wrapText(msg, MAX_LINE_WIDTH));
+        }
+        try {
+          DirectoryServer.registerBackend(backend);
+        } catch (Exception e)
+        {
+          LocalizableMessage msg = WARN_CONFIG_BACKEND_CANNOT_REGISTER_BACKEND.get(backendCfg.getBackendId(),
+              getExceptionMessage(e));
+          err.println(wrapText(msg, MAX_LINE_WIDTH));
         }
       }
     }
@@ -935,7 +903,7 @@
    * @param err The error output.
    * @param argParser The argument parser.
    * @param clearPassword the clear password
-   * @param clearPasswordFile the fil in which the password in stored
+   * @param clearPasswordFile the file in which the password in stored
    * @param interactivePassword indicate if the password should be asked
    *        interactively.
    * @return the password or null if an error occurs.
@@ -944,29 +912,24 @@
       ArgumentParser argParser, StringArgument clearPassword,
       FileBasedArgument clearPasswordFile, BooleanArgument interactivePassword)
   {
-    ByteString clearPW = null;
     if (clearPassword.hasValue())
     {
-      clearPW = ByteString.valueOf(clearPassword.getValue());
+      return ByteString.valueOf(clearPassword.getValue());
     }
     else if (clearPasswordFile.hasValue())
     {
-      clearPW = ByteString.valueOf(clearPasswordFile.getValue());
+      return ByteString.valueOf(clearPasswordFile.getValue());
     }
     else if (interactivePassword.isPresent())
     {
-      EncodePassword encodePassword = new EncodePassword() ;
       try
       {
-        String pwd1, pwd2;
-        LocalizableMessage msg = INFO_ENCPW_INPUT_PWD_1.get();
-        pwd1 = encodePassword.getPassword(out, msg.toString());
-
-        msg = INFO_ENCPW_INPUT_PWD_2.get();
-        pwd2 = encodePassword.getPassword(out,msg.toString());
+        EncodePassword encodePassword = new EncodePassword();
+        String pwd1 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_1.get().toString());
+        String pwd2 = encodePassword.getPassword(INFO_ENCPW_INPUT_PWD_2.get().toString());
         if (pwd1.equals(pwd2))
         {
-          clearPW = ByteString.valueOf(pwd1);
+          return ByteString.valueOf(pwd1);
         }
         else
         {
@@ -981,7 +944,6 @@
         err.println(wrapText(message, MAX_LINE_WIDTH));
         return null;
       }
-
     }
     else
     {
@@ -992,38 +954,32 @@
       err.println(argParser.getUsage());
       return null;
     }
-    return clearPW;
   }
 
   /**
    * Get the password from JDK6 console or from masked password.
-   * @param out The output
    * @param prompt The message to print out.
    * @return the password
    * @throws IOException if an issue occurs when reading the password
    *         from the input
    */
-  private String getPassword(PrintStream out, String prompt)
-      throws IOException
+  private String getPassword(String prompt) throws IOException
   {
     String password;
     try
     {
       Console console = System.console();
-      if (console != null)
-      {
-        password = new String(console.readPassword(prompt));
-      }
-      else
+      if (console == null)
       {
         throw new IOException("No console");
       }
+      password = new String(console.readPassword(prompt));
     }
     catch (Exception e)
     {
       // Try the fallback to the old trick method.
       // Create the thread that will erase chars
-      ErasingThread erasingThread = new ErasingThread(out, prompt);
+      ErasingThread erasingThread = new ErasingThread(prompt);
       erasingThread.start();
 
       password = "";
@@ -1041,10 +997,6 @@
           {
             break;
           }
-          else
-          {
-            continue;
-          }
         }
         else if (c == '\n')
         {
@@ -1063,22 +1015,19 @@
 
   /**
    * Thread that mask user input.
-   *
    */
   private class ErasingThread extends Thread
   {
 
-    private boolean stop = false;
+    private boolean stop;
     private String prompt;
 
     /**
      * The class will mask the user input.
-     * @param out
-     *          the output
      * @param prompt
      *          The prompt displayed to the user
      */
-    public ErasingThread(PrintStream out, String prompt)
+    public ErasingThread(String prompt)
     {
       this.prompt = prompt;
     }
@@ -1115,7 +1064,6 @@
     {
       this.stop = true;
     }
-
   }
 
 }
diff --git a/opendj3-server-dev/src/server/org/opends/server/types/DirectoryConfig.java b/opendj3-server-dev/src/server/org/opends/server/types/DirectoryConfig.java
index 9051b6c..b5370ad 100644
--- a/opendj3-server-dev/src/server/org/opends/server/types/DirectoryConfig.java
+++ b/opendj3-server-dev/src/server/org/opends/server/types/DirectoryConfig.java
@@ -31,20 +31,20 @@
 import java.util.Set;
 
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.config.server.ConfigException;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.opends.server.api.AlertGenerator;
-import org.opends.server.api.MatchingRule;
 import org.opends.server.api.AttributeSyntax;
-import org.opends.server.api.ChangeNotificationListener;
 import org.opends.server.api.ConfigHandler;
 import org.opends.server.api.ExtendedOperationHandler;
 import org.opends.server.api.InvokableComponent;
+import org.opends.server.api.MatchingRule;
 import org.opends.server.api.SASLMechanismHandler;
 import org.opends.server.api.ServerShutdownListener;
 import org.opends.server.api.SubstringMatchingRule;
 import org.opends.server.config.ConfigEntry;
-import org.forgerock.opendj.config.server.ConfigException;
 import org.opends.server.core.DirectoryServer;
+
 import com.forgerock.opendj.util.OperatingSystem;
 
 /**
@@ -1062,43 +1062,6 @@
     DirectoryServer.deregisterSASLMechanismHandler(name);
   }
 
-
-
-  /**
-   * Registers the provided change notification listener with the
-   * Directory Server so that it will be notified of any add, delete,
-   * modify, or modify DN operations that are performed.
-   *
-   * @param  changeListener  The change notification listener to
-   *                         register with the Directory Server.
-   */
-  public static void
-       registerChangeNotificationListener(
-            ChangeNotificationListener changeListener)
-  {
-    DirectoryServer.registerChangeNotificationListener(
-                         changeListener);
-  }
-
-
-
-  /**
-   * Deregisters the provided change notification listener with the
-   * Directory Server so that it will no longer be notified of any
-   * add, delete, modify, or modify DN operations that are performed.
-   *
-   * @param  changeListener  The change notification listener to
-   *                         deregister with the Directory Server.
-   */
-  public static void deregisterChangeNotificationListener(
-                          ChangeNotificationListener changeListener)
-  {
-    DirectoryServer.deregisterChangeNotificationListener(
-                         changeListener);
-  }
-
-
-
   /**
    * Registers the provided shutdown listener with the Directory
    * Server so that it will be notified when the server shuts down.
diff --git a/opendj3-server-dev/src/server/org/opends/server/util/CollectionUtils.java b/opendj3-server-dev/src/server/org/opends/server/util/CollectionUtils.java
new file mode 100644
index 0000000..175be36
--- /dev/null
+++ b/opendj3-server-dev/src/server/org/opends/server/util/CollectionUtils.java
@@ -0,0 +1,109 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *      Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.util;
+
+import java.util.*;
+
+/**
+ * Utility class for {@link Collection}s.
+ */
+public final class CollectionUtils
+{
+
+  private CollectionUtils()
+  {
+    // private for utility classes
+  }
+
+  /**
+   * Creates a new {@link ArrayList} with the provided elements.
+   *
+   * @param <E>
+   *          the elements' type
+   * @param elements
+   *          the elements to add to the new ArrayList
+   * @return a new ArrayList with the provided elements
+   */
+  public static <E> ArrayList<E> newArrayList(E... elements)
+  {
+    return new ArrayList<E>(Arrays.asList(elements));
+  }
+
+  /**
+   * Creates a new {@link LinkedList} with the provided elements.
+   *
+   * @param <E>
+   *          the elements' type
+   * @param elements
+   *          the elements to add to the new LinkedList
+   * @return a new LinkedList with the provided elements
+   */
+  public static <E> LinkedList<E> newLinkedList(E... elements)
+  {
+    return new LinkedList<E>(Arrays.asList(elements));
+  }
+
+  /**
+   * Creates a new {@link HashSet} with the provided elements.
+   *
+   * @param <E>
+   *          the elements' type
+   * @param elements
+   *          the elements to add to the new HashSet
+   * @return a new HashSet with the provided elements
+   */
+  public static <E> HashSet<E> newHashSet(E... elements)
+  {
+    return new HashSet<E>(Arrays.asList(elements));
+  }
+
+  /**
+   * Creates a new {@link LinkedHashSet} with the provided elements.
+   *
+   * @param <E>
+   *          the elements' type
+   * @param elements
+   *          the elements to add to the new LinkedHashSet
+   * @return a new LinkedHashSet with the provided elements
+   */
+  public static <E> LinkedHashSet<E> newLinkedHashSet(E... elements)
+  {
+    return new LinkedHashSet<E>(Arrays.asList(elements));
+  }
+
+  /**
+   * Creates a new {@link TreeSet} with the provided elements.
+   *
+   * @param <E>
+   *          the elements' type
+   * @param elements
+   *          the elements to add to the new TreeSet
+   * @return a new TreeSet with the provided elements
+   */
+  public static <E> TreeSet<E> newTreeSet(E... elements)
+  {
+    return new TreeSet<E>(Arrays.asList(elements));
+  }
+}
diff --git a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
index 3d72d54..28a37dc 100644
--- a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
+++ b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -34,16 +34,48 @@
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizableMessageBuilder;
-import org.opends.server.api.*;
-import org.opends.server.api.plugin.PluginResult;
-import org.opends.server.controls.*;
-import org.opends.server.core.*;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.api.AttributeSyntax;
+import org.opends.server.api.AuthenticationPolicy;
+import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.api.PasswordStorageScheme;
+import org.opends.server.api.PasswordValidator;
+import org.opends.server.api.SynchronizationProvider;
+import org.opends.server.api.plugin.PluginResult;
+import org.opends.server.controls.LDAPAssertionRequestControl;
+import org.opends.server.controls.LDAPPostReadRequestControl;
+import org.opends.server.controls.PasswordPolicyErrorType;
+import org.opends.server.controls.PasswordPolicyResponseControl;
+import org.opends.server.controls.ProxiedAuthV1Control;
+import org.opends.server.controls.ProxiedAuthV2Control;
+import org.opends.server.core.AccessControlConfigManager;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.AddOperationWrapper;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.PasswordPolicy;
+import org.opends.server.core.PersistentSearch;
+import org.opends.server.core.PluginConfigManager;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ByteString;
+import org.opends.server.types.AdditionalLogItem;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeBuilder;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.ObjectClass;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SynchronizationProviderResult;
 import org.opends.server.types.operation.PostOperationAddOperation;
 import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostSynchronizationAddOperation;
@@ -183,27 +215,10 @@
         @Override
         public void run()
         {
-          // Notify persistent searches.
           for (PersistentSearch psearch : wfe.getPersistentSearches())
           {
             psearch.processAdd(entry);
           }
-
-          // Notify change listeners.
-          for (ChangeNotificationListener changeListener : DirectoryServer
-              .getChangeNotificationListeners())
-          {
-            try
-            {
-              changeListener.handleAddOperation(LocalBackendAddOperation.this, entry);
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              logger.error(ERR_ADD_ERROR_NOTIFYING_CHANGE_LISTENER, getExceptionMessage(e));
-            }
-          }
         }
       });
     }
diff --git a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
index 54c1c02..ec7ecb2 100644
--- a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
+++ b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -30,8 +30,9 @@
 import java.util.concurrent.locks.Lock;
 
 import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.ResultCode;
 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.PluginResult;
@@ -39,10 +40,22 @@
 import org.opends.server.controls.LDAPPreReadRequestControl;
 import org.opends.server.controls.ProxiedAuthV1Control;
 import org.opends.server.controls.ProxiedAuthV2Control;
-import org.opends.server.core.*;
-import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.core.AccessControlConfigManager;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DeleteOperationWrapper;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.PersistentSearch;
+import org.opends.server.core.PluginConfigManager;
+import org.opends.server.types.AdditionalLogItem;
+import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SynchronizationProviderResult;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
 import org.opends.server.types.operation.PostSynchronizationDeleteOperation;
@@ -170,31 +183,13 @@
     {
       registerPostResponseCallback(new Runnable()
       {
-
         @Override
         public void run()
         {
-          // Notify persistent searches.
           for (PersistentSearch psearch : wfe.getPersistentSearches())
           {
             psearch.processDelete(entry);
           }
-
-          // Notify change listeners.
-          for (ChangeNotificationListener changeListener : DirectoryServer
-              .getChangeNotificationListeners())
-          {
-            try
-            {
-              changeListener.handleDeleteOperation(LocalBackendDeleteOperation.this, entry);
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              logger.error(ERR_DELETE_ERROR_NOTIFYING_CHANGE_LISTENER, getExceptionMessage(e));
-            }
-          }
         }
       });
     }
diff --git a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
index 3a271d6..f24c30c 100644
--- a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
+++ b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -36,15 +36,37 @@
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ModificationType;
+import org.forgerock.opendj.ldap.ResultCode;
 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.PluginResult;
-import org.opends.server.controls.*;
-import org.opends.server.core.*;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.controls.LDAPAssertionRequestControl;
+import org.opends.server.controls.LDAPPostReadRequestControl;
+import org.opends.server.controls.LDAPPreReadRequestControl;
+import org.opends.server.controls.ProxiedAuthV1Control;
+import org.opends.server.controls.ProxiedAuthV2Control;
+import org.opends.server.core.AccessControlConfigManager;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyDNOperationWrapper;
+import org.opends.server.core.PersistentSearch;
+import org.opends.server.core.PluginConfigManager;
+import org.opends.server.types.AdditionalLogItem;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.Modification;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+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.PostSynchronizationModifyDNOperation;
@@ -200,32 +222,13 @@
     {
       registerPostResponseCallback(new Runnable()
       {
-
         @Override
         public void run()
         {
-          // Notify persistent searches.
           for (PersistentSearch psearch : wfe.getPersistentSearches())
           {
             psearch.processModifyDN(newEntry, currentEntry.getName());
           }
-
-          // Notify change listeners.
-          for (ChangeNotificationListener changeListener : DirectoryServer
-              .getChangeNotificationListeners())
-          {
-            try
-            {
-              changeListener.handleModifyDNOperation(
-                  LocalBackendModifyDNOperation.this, currentEntry, newEntry);
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              logger.error(ERR_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER, getExceptionMessage(e));
-            }
-          }
         }
       });
     }
diff --git a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
index 15bf98c..84da1f9 100644
--- a/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
+++ b/opendj3-server-dev/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -40,13 +40,51 @@
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.util.Reject;
 import org.forgerock.util.Utils;
-import org.opends.server.api.*;
+import org.opends.server.api.AttributeSyntax;
+import org.opends.server.api.AuthenticationPolicy;
+import org.opends.server.api.Backend;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.api.MatchingRule;
+import org.opends.server.api.PasswordStorageScheme;
+import org.opends.server.api.SynchronizationProvider;
 import org.opends.server.api.plugin.PluginResult;
-import org.opends.server.controls.*;
-import org.opends.server.core.*;
+import org.opends.server.controls.LDAPAssertionRequestControl;
+import org.opends.server.controls.LDAPPostReadRequestControl;
+import org.opends.server.controls.LDAPPreReadRequestControl;
+import org.opends.server.controls.PasswordPolicyErrorType;
+import org.opends.server.controls.PasswordPolicyResponseControl;
+import org.opends.server.controls.ProxiedAuthV1Control;
+import org.opends.server.controls.ProxiedAuthV2Control;
+import org.opends.server.core.AccessControlConfigManager;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.ModifyOperationWrapper;
+import org.opends.server.core.PasswordPolicy;
+import org.opends.server.core.PasswordPolicyState;
+import org.opends.server.core.PersistentSearch;
+import org.opends.server.core.PluginConfigManager;
 import org.opends.server.schema.AuthPasswordSyntax;
 import org.opends.server.schema.UserPasswordSyntax;
-import org.opends.server.types.*;
+import org.opends.server.types.AcceptRejectWarn;
+import org.opends.server.types.AccountStatusNotification;
+import org.opends.server.types.AccountStatusNotificationType;
+import org.opends.server.types.AdditionalLogItem;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeBuilder;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ObjectClass;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SynchronizationProviderResult;
 import org.opends.server.types.operation.PostOperationModifyOperation;
 import org.opends.server.types.operation.PostResponseModifyOperation;
 import org.opends.server.types.operation.PostSynchronizationModifyOperation;
@@ -314,33 +352,13 @@
     {
       registerPostResponseCallback(new Runnable()
       {
-
         @Override
         public void run()
         {
-          // Notify persistent searches.
           for (PersistentSearch psearch : wfe.getPersistentSearches())
           {
             psearch.processModify(modifiedEntry, currentEntry);
           }
-
-          // Notify change listeners.
-          for (ChangeNotificationListener changeListener : DirectoryServer
-              .getChangeNotificationListeners())
-          {
-            try
-            {
-              changeListener
-                  .handleModifyOperation(LocalBackendModifyOperation.this,
-                      currentEntry, modifiedEntry);
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              logger.error(ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER, getExceptionMessage(e));
-            }
-          }
         }
       });
     }
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
index 21cbf02..29ca781 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java
@@ -26,8 +26,10 @@
  */
 package org.opends.server.core;
 
+import java.io.IOException;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.locks.Lock;
@@ -53,6 +55,7 @@
 
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.util.CollectionUtils.*;
 import static org.testng.Assert.*;
 
 /**
@@ -78,21 +81,13 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @DataProvider(name = "addOperations")
-  public Object[][] getAddOperations()
-         throws Exception
+  public Object[][] getAddOperations() throws Exception
   {
     ArrayList<Control> noControls = new ArrayList<Control>();
 
-    ArrayList<RawAttribute> ldapAttrList = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    ldapAttrList.add(new LDAPAttribute("objectclass", values));
-
-    values.clear();
-    values.add(ByteString.valueOf("People"));
-    ldapAttrList.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> ldapAttrList = newRawAttributes(
+        new LDAPAttribute("objectclass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     Entry entry = TestCaseUtils.makeEntry(
          "dn: ou=People,o=test",
@@ -131,9 +126,8 @@
 
 
   /** {@inheritDoc} */
-  @Override()
-  protected Operation[] createTestOperations()
-         throws Exception
+  @Override
+  protected Operation[] createTestOperations() throws Exception
   {
     Object[][]  objs = getAddOperations();
     Operation[] ops  = new Operation[objs.length];
@@ -175,19 +169,12 @@
    * Tests the <CODE>getEntryDN</CODE> method for the case in which we expect
    * the rawEntryDN to be decoded.
    */
-  @Test()
+  @Test
   public void testGetEntryDNInitiallyNull()
   {
-    ArrayList<RawAttribute> ldapAttrList = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    ldapAttrList.add(new LDAPAttribute("objectclass", values));
-
-    values.clear();
-    values.add(ByteString.valueOf("People"));
-    ldapAttrList.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> ldapAttrList = newRawAttributes(
+        new LDAPAttribute("objectclass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     AddOperationBasis addOperation =
          new AddOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(),
@@ -196,7 +183,20 @@
     assertNotNull(addOperation.getEntryDN());
   }
 
+  private ArrayList<RawAttribute> newRawAttributes(RawAttribute... attributes)
+  {
+    return new ArrayList<RawAttribute>(Arrays.asList(attributes));
+  }
 
+  private ArrayList<ByteString> byteStrings(final String... v)
+  {
+    ArrayList<ByteString> values = new ArrayList<ByteString>();
+    for (String s : v)
+    {
+      values.add(ByteString.valueOf(s));
+    }
+    return values;
+  }
 
   /**
    * Tests the <CODE>getEntryDN</CODE> method for the case in which we expect
@@ -204,9 +204,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNInitiallyNonNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNInitiallyNonNull() throws Exception
   {
     Entry entry = TestCaseUtils.makeEntry(
          "dn: ou=People,o=test",
@@ -231,9 +230,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNNonNullChangedToNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNNonNullChangedToNull() throws Exception
   {
     Entry entry = TestCaseUtils.makeEntry(
          "dn: ou=People,o=test",
@@ -267,32 +265,27 @@
     assertNotNull(rawAttrs);
     assertFalse(rawAttrs.isEmpty());
 
-    ArrayList<RawAttribute> copiedAttrs =
-      new ArrayList<RawAttribute>(rawAttrs);
+    ArrayList<RawAttribute> copiedAttrs = new ArrayList<RawAttribute>(rawAttrs);
+    copiedAttrs.add(new LDAPAttribute("description", byteStrings("foo")));
     addOperation.setRawAttributes(copiedAttrs);
 
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("foo"));
-    addOperation.addRawAttribute(new LDAPAttribute("description", values));
-
-    assertTrue(find(addOperation));
+    assertTrue(find(addOperation, "description"));
 
     addOperation.setRawAttributes(rawAttrs);
 
-    assertFalse(find(addOperation));
+    assertFalse(find(addOperation, "description"));
   }
 
-  private boolean find(AddOperation addOperation)
+  private boolean find(AddOperation addOperation, final String attrName)
   {
-    boolean found = false;
     for (RawAttribute a : addOperation.getRawAttributes())
     {
-      if ("description".equalsIgnoreCase(a.getAttributeType()))
+      if (attrName.equalsIgnoreCase(a.getAttributeType()))
       {
         return true;
       }
     }
-    return found;
+    return false;
   }
 
 
@@ -302,9 +295,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testAddObjectClass()
-         throws Exception
+  @Test
+  public void testAddObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -336,9 +328,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testRemoveObjectClass()
-         throws Exception
+  @Test
+  public void testRemoveObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -372,9 +363,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSetAttributeOverwrite()
-         throws Exception
+  @Test
+  public void testSetAttributeOverwrite() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -428,9 +418,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSetAttributeAdd()
-         throws Exception
+  @Test
+  public void testSetAttributeAdd() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -464,9 +453,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSetAttributeRemove()
-         throws Exception
+  @Test
+  public void testSetAttributeRemove() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -519,22 +507,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessRaw()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessRaw() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     AddOperation addOperation =
          getRootConnection().processAdd(ByteString.valueOf("ou=People,o=test"), attrs);
@@ -542,17 +522,14 @@
     retrieveCompletedOperationElements(addOperation);
   }
 
-
-
   /**
    * Tests an internal add operation that should be successful using processed
    * arguments.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessProcessed()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessProcessed() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -575,22 +552,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureMalformedDN()
-         throws Exception
+  @Test
+  public void testInternalAddFailureMalformedDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     AddOperation addOperation =
          getRootConnection().processAdd(ByteString.valueOf("invalid"), attrs);
@@ -605,22 +574,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureAlreadyExists()
-         throws Exception
+  @Test
+  public void testInternalAddFailureAlreadyExists() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organization"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("test"));
-    attrs.add(new LDAPAttribute("o", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organization")),
+        new LDAPAttribute("o", byteStrings("test")));
 
     AddOperation addOperation =
          getRootConnection().processAdd(ByteString.valueOf("o=test"), attrs);
@@ -635,22 +596,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureNoSuchSuffix()
-         throws Exception
+  @Test
+  public void testInternalAddFailureNoSuchSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organization"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("undefined"));
-    attrs.add(new LDAPAttribute("o", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organization")),
+        new LDAPAttribute("o", byteStrings("undefined")));
 
     AddOperation addOperation =
          getRootConnection().processAdd(ByteString.valueOf("o=undefined"), attrs);
@@ -665,22 +618,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureNoSuchSuffixParent()
-         throws Exception
+  @Test
+  public void testInternalAddFailureNoSuchSuffixParent() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -697,22 +642,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureNoSuchParent()
-         throws Exception
+  @Test
+  public void testInternalAddFailureNoSuchParent() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -730,9 +667,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalAddFailureNoUserModification()
-         throws Exception
+  @Test
+  public void testExternalAddFailureNoUserModification() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -741,49 +677,18 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
-
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("cn=Directory Manager"));
-    attrs.add(new LDAPAttribute("creatorsName", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("20060101000000Z"));
-    attrs.add(new LDAPAttribute("createTimestamp", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")),
+        new LDAPAttribute("creatorsName", byteStrings("cn=Directory Manager")),
+        new LDAPAttribute("createTimestamp", byteStrings("20060101000000Z")));
 
     long addRequests  = ldapStatistics.getAddRequests();
     long addResponses = ldapStatistics.getAddResponses();
 
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest);
-    w.writeMessage(message);
-
-    message = r.readMessage();
-    AddResponseProtocolOp addResponse =
-         message.getAddResponseProtocolOp();
-    assertFalse(addResponse.getResultCode() == 0);
+    addSuccess(r, w, attrs);
 
     assertEquals(ldapStatistics.getAddRequests(), addRequests+1);
     waitForAddResponsesStat(addResponses+1);
@@ -791,30 +696,20 @@
     StaticUtils.close(s);
   }
 
-
-
   /**
    * Tests an internal add operation that fails because it has an undefined
    * objectclass.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureUndefinedObjectClass()
-         throws Exception
+  @Test
+  public void testInternalAddFailureUndefinedObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("undefined"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "undefined")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -824,17 +719,14 @@
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
-
-
   /**
    * Tests a successful internal add operation that contains a user-modifiable
    * operational attribute.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithOperationalAttribute()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithOperationalAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -865,30 +757,16 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulDisjointAttribute()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulDisjointAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("foo"));
-    attrs.add(new LDAPAttribute("description", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("bar"));
-    attrs.add(new LDAPAttribute("description", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("description", byteStrings("foo")),
+        new LDAPAttribute("ou", byteStrings("People")),
+        new LDAPAttribute("description", byteStrings("bar")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -898,38 +776,22 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
-
-
   /**
    * Tests a successful internal add operation that contains raw attributes with
    * options.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithRawAttributeOptions()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithRawAttributeOptions() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("foo"));
-    attrs.add(new LDAPAttribute("description", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("foo"));
-    attrs.add(new LDAPAttribute("description;lang-en-us", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("description", byteStrings("foo")),
+        new LDAPAttribute("ou", byteStrings("People")),
+        new LDAPAttribute("description;lang-en-us", byteStrings("foo")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -947,26 +809,15 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithRawAttributeOptionsOnlyOptions()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithRawAttributeOptionsOnlyOptions() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("foo"));
-    attrs.add(new LDAPAttribute("description;lang-en-us", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")),
+        new LDAPAttribute("description;lang-en-us", byteStrings("foo")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -976,17 +827,14 @@
     assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
   }
 
-
-
   /**
    * Tests a successful internal add operation that contains attributes with
    * options.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithAttributeOptions()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithAttributeOptions() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1019,23 +867,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureRootDSE()
-         throws Exception
+  @Test
+  public void testInternalAddFailureRootDSE() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("ds-root-dse"));
-    values.add(ByteString.valueOf("extensibleObject"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("Root DSE"));
-    attrs.add(new LDAPAttribute("cn", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "ds-root-dse", "extensibleObject")),
+        new LDAPAttribute("cn", byteStrings("Root DSE")));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -1044,16 +883,13 @@
     assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
   }
 
-
-
   /**
    * Tests a successful internal add operation that is missing RDN attributes.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithMissingRDNAttributes()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithMissingRDNAttributes() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1078,9 +914,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureWithMissingRDNAttributes()
-         throws Exception
+  @Test
+  public void testInternalAddFailureWithMissingRDNAttributes() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1105,9 +940,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulWithMissingParentObjectClass()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulWithMissingParentObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1151,9 +985,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureNoObjectClasses()
-         throws Exception
+  @Test
+  public void testInternalAddFailureNoObjectClasses() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1173,9 +1006,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureOnlyAbstractObjectClass()
-         throws Exception
+  @Test
+  public void testInternalAddFailureOnlyAbstractObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1196,9 +1028,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureNoStructuralObjectClass()
-         throws Exception
+  @Test
+  public void testInternalAddFailureNoStructuralObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1220,9 +1051,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureMultipleStructuralObjectClasses()
-         throws Exception
+  @Test
+  public void testInternalAddFailureMultipleStructuralObjectClasses() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1246,9 +1076,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureMissingRequiredAttribute()
-         throws Exception
+  @Test
+  public void testInternalAddFailureMissingRequiredAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1275,9 +1104,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureMissingRequiredAttributeExtensibleObject()
-         throws Exception
+  @Test
+  public void testInternalAddFailureMissingRequiredAttributeExtensibleObject() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1305,9 +1133,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureDisallowedAttribute()
-         throws Exception
+  @Test
+  public void testInternalAddFailureDisallowedAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1337,9 +1164,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessfulDisallowedAttributeExtensibleObject()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessfulDisallowedAttributeExtensibleObject() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1370,9 +1196,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureEmptyAttribute()
-         throws Exception
+  @Test
+  public void testInternalAddFailureEmptyAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(false);
 
@@ -1382,13 +1207,9 @@
          "objectClass: organization",
          "o: test");
 
-    Map<AttributeType,List<Attribute>> userAttrs = entry.getUserAttributes();
-
     AttributeType attrType = DirectoryServer.getAttributeType("description");
-    ArrayList<Attribute> attrList = new ArrayList<Attribute>();
-    attrList.add(Attributes.empty(attrType));
-    userAttrs.put(attrType, attrList);
-
+    Map<AttributeType,List<Attribute>> userAttrs = entry.getUserAttributes();
+    userAttrs.put(attrType, newArrayList(Attributes.empty(attrType)));
 
     InternalClientConnection conn = getRootConnection();
 
@@ -1406,9 +1227,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureServerCompletelyReadOnly()
-         throws Exception
+  @Test
+  public void testInternalAddFailureServerCompletelyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1440,9 +1260,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessServerExternallyReadOnly()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessServerExternallyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1475,9 +1294,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalAddFailureServerExternallyReadOnly()
-         throws Exception
+  @Test
+  public void testExternalAddFailureServerExternallyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1486,43 +1304,18 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
-
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     DirectoryServer.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
 
     long addRequests  = ldapStatistics.getAddRequests();
     long addResponses = ldapStatistics.getAddResponses();
 
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest);
-    w.writeMessage(message);
-
-    message = r.readMessage();
-    AddResponseProtocolOp addResponse =
-         message.getAddResponseProtocolOp();
-    assertFalse(addResponse.getResultCode() == 0);
+    addSuccess(r, w, attrs);
 
     assertEquals(ldapStatistics.getAddRequests(), addRequests+1);
     waitForAddResponsesStat(addResponses+1);
@@ -1532,7 +1325,26 @@
     DirectoryServer.setWritabilityMode(WritabilityMode.ENABLED);
   }
 
+  private void bind(LDAPReader r, LDAPWriter w) throws Exception
+  {
+    final BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
+        ByteString.valueOf("cn=Directory Manager"), 3, ByteString.valueOf("password"));
+    w.writeMessage(new LDAPMessage(1, bindRequest));
 
+    final LDAPMessage message = r.readMessage();
+    final BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
+    assertEquals(bindResponse.getResultCode(), 0);
+  }
+
+  private void addSuccess(LDAPReader r, LDAPWriter w,
+      ArrayList<RawAttribute> attrs) throws Exception
+  {
+    writeAddRequest(w, attrs, null);
+
+    LDAPMessage message = r.readMessage();
+    AddResponseProtocolOp addResponse = message.getAddResponseProtocolOp();
+    assertFalse(addResponse.getResultCode() == 0);
+  }
 
   /**
    * Tests a failed internal add operation with the backend in complete
@@ -1540,9 +1352,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddFailureBackendCompletelyReadOnly()
-         throws Exception
+  @Test
+  public void testInternalAddFailureBackendCompletelyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1575,9 +1386,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalAddSuccessBackendExternallyReadOnly()
-         throws Exception
+  @Test
+  public void testInternalAddSuccessBackendExternallyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1611,9 +1421,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalAddFailureBackendExternallyReadOnly()
-         throws Exception
+  @Test
+  public void testExternalAddFailureBackendExternallyReadOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1622,27 +1431,11 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
-
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
     Backend<?> b = DirectoryServer.getBackend(DN.valueOf("o=test"));
     b.setWritabilityMode(WritabilityMode.INTERNAL_ONLY);
@@ -1650,16 +1443,7 @@
     long addRequests  = ldapStatistics.getAddRequests();
     long addResponses = ldapStatistics.getAddResponses();
 
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest);
-    w.writeMessage(message);
-
-    message = r.readMessage();
-    AddResponseProtocolOp addResponse =
-         message.getAddResponseProtocolOp();
-    assertFalse(addResponse.getResultCode() == 0);
+    addSuccess(r, w, attrs);
 
     assertEquals(ldapStatistics.getAddRequests(), addRequests+1);
     waitForAddResponsesStat(addResponses+1);
@@ -1677,29 +1461,31 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSuccessWithNotificationListener()
-         throws Exception
+  @Test
+  public void testSuccessWithNotificationListener() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getAddCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try{
+      assertEquals(changeListener.getAddCount(), 0);
 
-    Entry entry = TestCaseUtils.makeEntry(
-         "dn: ou=People,o=test",
-         "objectClass: top",
-         "objectClass: organizationalUnit",
-         "ou: People");
+      Entry entry = TestCaseUtils.makeEntry(
+          "dn: ou=People,o=test",
+          "objectClass: top",
+          "objectClass: organizationalUnit",
+          "ou: People");
 
-    AddOperation addOperation = getRootConnection().processAdd(entry);
-    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
-    retrieveCompletedOperationElements(addOperation);
+      AddOperation addOperation = getRootConnection().processAdd(entry);
+      assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+      retrieveCompletedOperationElements(addOperation);
 
-    assertEquals(changeListener.getAddCount(), 1);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getAddCount(), 1);
+    }finally {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -1710,28 +1496,30 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testFailureWithNotificationListener()
-         throws Exception
+  @Test
+  public void testFailureWithNotificationListener() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getAddCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try{
+      assertEquals(changeListener.getAddCount(), 0);
 
-    Entry entry = TestCaseUtils.makeEntry(
-         "dn: ou=People,ou=nonexistent,o=test",
-         "objectClass: top",
-         "objectClass: organizationalUnit",
-         "ou: People");
+      Entry entry = TestCaseUtils.makeEntry(
+          "dn: ou=People,ou=nonexistent,o=test",
+          "objectClass: top",
+          "objectClass: organizationalUnit",
+          "ou: People");
 
-    AddOperation addOperation = getRootConnection().processAdd(entry);
-    assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
+      AddOperation addOperation = getRootConnection().processAdd(entry);
+      assertFalse(addOperation.getResultCode() == ResultCode.SUCCESS);
 
-    assertEquals(changeListener.getAddCount(), 0);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getAddCount(), 0);
+    }finally {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -1741,9 +1529,8 @@
    *
    * @throws  Exception  If an unexpected probem occurs.
    */
-  @Test()
-  public void testCancelBeforeStartup()
-         throws Exception
+  @Test
+  public void testCancelBeforeStartup() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1771,9 +1558,8 @@
    *
    * @throws  Exception  If an unexpected probem occurs.
    */
-  @Test()
-  public void testCancelAfterOperation()
-         throws Exception
+  @Test
+  public void testCancelAfterOperation() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1808,8 +1594,7 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test(groups = { "slow" })
-  public void testCannotLockEntry()
-         throws Exception
+  public void testCannotLockEntry() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1839,9 +1624,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPreParseAdd()
-         throws Exception
+  @Test
+  public void testDisconnectInPreParseAdd() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1850,44 +1634,39 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
+    addDisconnect(r, w, attrs, "PreParse");
 
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
+    StaticUtils.close(s);
+  }
 
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
+  private void addDisconnect(LDAPReader r, LDAPWriter w,
+      ArrayList<RawAttribute> attrs, String section) throws Exception
+  {
+    writeAddRequest(w, attrs, section);
 
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectControlList("PreParse"));
-    w.writeMessage(message);
-
-    message = r.readMessage();
+    LDAPMessage message = r.readMessage();
     if (message != null)
     {
       // If we got an element back, then it must be a notice of disconnect
       // unsolicited notification.
       assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
     }
+  }
 
-    StaticUtils.close(s);
+  private void writeAddRequest(LDAPWriter w, ArrayList<RawAttribute> attrs,
+      String section) throws IOException
+  {
+    AddRequestProtocolOp addRequest = new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"), attrs);
+    List<Control> controls = section != null
+        ? DisconnectClientPlugin.createDisconnectControlList(section)
+        : null;
+    w.writeMessage(new LDAPMessage(2, addRequest, controls));
   }
 
 
@@ -1898,9 +1677,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPreOperationAdd()
-         throws Exception
+  @Test
+  public void testDisconnectInPreOperationAdd() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1909,58 +1687,25 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectControlList(
-              "PreOperation"));
-    w.writeMessage(message);
-
-    message = r.readMessage();
-    if (message != null)
-    {
-      // If we got an element back, then it must be a notice of disconnect
-      // unsolicited notification.
-      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
-    }
+    addDisconnect(r, w, attrs, "PreOperation");
 
     StaticUtils.close(s);
   }
 
-
-
   /**
    * Tests an add operation that should be disconnected in a post-operation
    * plugin.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPostOperationAdd()
-         throws Exception
+  @Test
+  public void testDisconnectInPostOperationAdd() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1969,58 +1714,25 @@
     LDAPWriter w = new LDAPWriter(s);
     TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectControlList(
-              "PostOperation"));
-    w.writeMessage(message);
-
-    message = r.readMessage();
-    if (message != null)
-    {
-      // If we got an element back, then it must be a notice of disconnect
-      // unsolicited notification.
-      assertEquals(message.getProtocolOpType(), OP_TYPE_EXTENDED_RESPONSE);
-    }
+    addDisconnect(r, w, attrs, "PostOperation");
 
     StaticUtils.close(s);
   }
 
-
-
   /**
    * Tests an add operation that should be disconnected in a post-response
    * plugin.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPostResponseAdd()
-         throws Exception
+  @Test
+  public void testDisconnectInPostResponseAdd() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -2029,40 +1741,18 @@
     LDAPWriter w = new LDAPWriter(s);
     //TestCaseUtils.configureSocket(s);
 
-    BindRequestProtocolOp bindRequest =
-         new BindRequestProtocolOp(ByteString.valueOf("cn=Directory Manager"),
-                                   3, ByteString.valueOf("password"));
-    LDAPMessage message = new LDAPMessage(1, bindRequest);
-    w.writeMessage(message);
+    bind(r, w);
 
-    message = r.readMessage();
-    BindResponseProtocolOp bindResponse =
-         message.getBindResponseProtocolOp();
-    assertEquals(bindResponse.getResultCode(), 0);
+    ArrayList<RawAttribute> attrs = newRawAttributes(
+        new LDAPAttribute("objectClass", byteStrings("top", "organizationalUnit")),
+        new LDAPAttribute("ou", byteStrings("People")));
 
-
-    ArrayList<RawAttribute> attrs = new ArrayList<RawAttribute>();
-    ArrayList<ByteString> values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("top"));
-    values.add(ByteString.valueOf("organizationalUnit"));
-    attrs.add(new LDAPAttribute("objectClass", values));
-
-    values = new ArrayList<ByteString>();
-    values.add(ByteString.valueOf("People"));
-    attrs.add(new LDAPAttribute("ou", values));
-
-    AddRequestProtocolOp addRequest =
-         new AddRequestProtocolOp(ByteString.valueOf("ou=People,o=test"),
-                                  attrs);
-    message = new LDAPMessage(2, addRequest,
-         DisconnectClientPlugin.createDisconnectControlList(
-              "PostResponse"));
-    w.writeMessage(message);
+    writeAddRequest(w, attrs, "PostResponse");
 
 responseLoop:
     while (true)
     {
-      message = r.readMessage();
+      LDAPMessage message = r.readMessage();
       if (message == null)
       {
         // The connection has been closed.
@@ -2092,17 +1782,14 @@
     StaticUtils.close(s);
   }
 
-
-
   /**
    * Tests an add operation that attempts to add an entry with a user attribute
    * marked OBSOLETE in the server schema.
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testAddObsoleteUserAttribute()
-         throws Exception
+  @Test
+  public void testAddObsoleteUserAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(false);
 
@@ -2159,9 +1846,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testAddObsoleteOperationalAttribute()
-         throws Exception
+  @Test
+  public void testAddObsoleteOperationalAttribute() throws Exception
   {
     TestCaseUtils.initializeTestBackend(false);
 
@@ -2218,9 +1904,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testAddObsoleteObjectClass()
-         throws Exception
+  @Test
+  public void testAddObsoleteObjectClass() throws Exception
   {
     TestCaseUtils.initializeTestBackend(false);
 
@@ -2275,22 +1960,17 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testShortCircuitInPreParse()
-         throws Exception
+  @Test
+  public void testShortCircuitInPreParse() throws Exception
   {
     TestCaseUtils.initializeTestBackend(false);
 
     List<Control> controls =
          ShortCircuitPlugin.createShortCircuitControlList(0, "PreParse");
 
-    ArrayList<ByteString> ocValues = new ArrayList<ByteString>();
-    ocValues.add(ByteString.valueOf("top"));
-    ocValues.add(ByteString.valueOf("organization"));
-
-    ArrayList<RawAttribute> rawAttrs = new ArrayList<RawAttribute>();
-    rawAttrs.add(RawAttribute.create("objectClass", ocValues));
-    rawAttrs.add(RawAttribute.create("o", "test"));
+    ArrayList<RawAttribute> rawAttrs = newRawAttributes(
+        RawAttribute.create("objectClass", byteStrings("top", "organization")),
+        RawAttribute.create("o", "test"));
 
     AddOperationBasis addOperation =
          new AddOperationBasis(getRootConnection(), nextOperationID(), nextMessageID(),
@@ -2300,4 +1980,3 @@
     assertFalse(DirectoryServer.entryExists(DN.valueOf("o=test")));
   }
 }
-
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
index 44fa034..eb3f104 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
@@ -70,9 +70,8 @@
   }
 
   /** {@inheritDoc} */
-  @Override()
-  protected Operation[] createTestOperations()
-         throws Exception
+  @Override
+  protected Operation[] createTestOperations() throws Exception
   {
     List<Control> noControls = new ArrayList<Control>();
     return new Operation[]
@@ -132,7 +131,7 @@
    * Tests the <CODE>getEntryDN</CODE> method that should decode the rawEntryDN
    * to compute the entryDN.
    */
-  @Test()
+  @Test
   public void testGetEntryDNNull()
   {
     DeleteOperation deleteOperation =
@@ -147,9 +146,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNNotNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNNotNull() throws Exception
   {
     DeleteOperation deleteOperation =
         newDeleteOperation(null, DN.valueOf("o=test"));
@@ -167,9 +165,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNChangedToNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNChangedToNull() throws Exception
   {
     DeleteOperation deleteOperation =
         newDeleteOperation(null, DN.valueOf("o=test"));
@@ -203,9 +200,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryToDeleteExists()
-         throws Exception
+  @Test
+  public void testGetEntryToDeleteExists() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -223,13 +219,13 @@
 
   private DeleteOperation processDeleteRaw(String entryDN)
   {
-    InternalClientConnection conn =getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     return conn.processDelete(ByteString.valueOf(entryDN));
   }
 
   private DeleteOperation processDelete(String entryDN) throws DirectoryException
   {
-    InternalClientConnection conn =getRootConnection();
+    InternalClientConnection conn = getRootConnection();
     return conn.processDelete(DN.valueOf(entryDN));
   }
 
@@ -246,9 +242,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryToDeleteNonExistent()
-         throws Exception
+  @Test
+  public void testGetEntryToDeleteNonExistent() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -270,9 +265,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalDelete()
-         throws Exception
+  @Test
+  public void testExternalDelete() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -287,9 +281,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithValidRawDNSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithValidRawDNSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -305,9 +298,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithValidProcessedDNSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithValidProcessedDNSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -323,9 +315,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithValidRawDNLeaf()
-         throws Exception
+  @Test
+  public void testDeleteWithValidRawDNLeaf() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -346,9 +337,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithValidProcessedDNLeaf()
-         throws Exception
+  @Test
+  public void testDeleteWithValidProcessedDNLeaf() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -369,9 +359,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithMalformedRawDN()
-         throws Exception
+  @Test
+  public void testDeleteWithMalformedRawDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -387,9 +376,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonExistentSuffixRawDN()
-         throws Exception
+  @Test
+  public void testDeleteWithNonExistentSuffixRawDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -405,9 +393,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonExistentSuffixProcessedDN()
-         throws Exception
+  @Test
+  public void testDeleteWithNonExistentSuffixProcessedDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -422,9 +409,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithRawDNBelowNonExistentSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithRawDNBelowNonExistentSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -440,9 +426,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithProcessedDNBelowNonExistentSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithProcessedDNBelowNonExistentSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -458,9 +443,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonExistentRawDNBelowExistingSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithNonExistentRawDNBelowExistingSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -476,9 +460,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonExistentProcessedDNBelowExistingSuffix()
-         throws Exception
+  @Test
+  public void testDeleteWithNonExistentProcessedDNBelowExistingSuffix() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -493,9 +476,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonLeafRawDN()
-         throws Exception
+  @Test
+  public void testDeleteWithNonLeafRawDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -515,9 +497,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithNonLeafProcessedDN()
-         throws Exception
+  @Test
+  public void testDeleteWithNonLeafProcessedDN() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -538,9 +519,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithServerWritabilityDisabled()
-         throws Exception
+  @Test
+  public void testDeleteWithServerWritabilityDisabled() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -560,9 +540,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalDeleteWithServerWritabilityInternalOnly()
-         throws Exception
+  @Test
+  public void testInternalDeleteWithServerWritabilityInternalOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -582,9 +561,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalDeleteWithServerWritabilityInternalOnly()
-         throws Exception
+  @Test
+  public void testExternalDeleteWithServerWritabilityInternalOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -604,9 +582,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDeleteWithBackendWritabilityDisabled()
-         throws Exception
+  @Test
+  public void testDeleteWithBackendWritabilityDisabled() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -627,9 +604,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testInternalDeleteWithBackendWritabilityInternalOnly()
-         throws Exception
+  @Test
+  public void testInternalDeleteWithBackendWritabilityInternalOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -650,9 +626,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testExternalDeleteWithBackendWritabilityInternalOnly()
-         throws Exception
+  @Test
+  public void testExternalDeleteWithBackendWritabilityInternalOnly() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -683,9 +658,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testCancelBeforeStartup()
-         throws Exception
+  @Test
+  public void testCancelBeforeStartup() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -704,9 +678,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testCancelAfterOperation()
-         throws Exception
+  @Test
+  public void testCancelAfterOperation() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -731,8 +704,7 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test(groups = { "slow" })
-  public void testCannotLockEntry()
-         throws Exception
+  public void testCannotLockEntry() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -756,9 +728,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPreParseDelete()
-         throws Exception
+  @Test
+  public void testDisconnectInPreParseDelete() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -804,9 +775,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPreOperationDelete()
-         throws Exception
+  @Test
+  public void testDisconnectInPreOperationDelete() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -853,9 +823,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPostOperationDelete()
-         throws Exception
+  @Test
+  public void testDisconnectInPostOperationDelete() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -902,9 +871,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPostResponseDelete()
-         throws Exception
+  @Test
+  public void testDisconnectInPostResponseDelete() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -972,23 +940,28 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSuccessWithNotificationListener()
-         throws Exception
+  @Test
+  public void testSuccessWithNotificationListener() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getAddCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try
+    {
+      assertEquals(changeListener.getAddCount(), 0);
 
-    DeleteOperation deleteOperation = processDeleteRaw("o=test");
-    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
-    retrieveCompletedOperationElements(deleteOperation);
+      DeleteOperation deleteOperation = processDeleteRaw("o=test");
+      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
+      retrieveCompletedOperationElements(deleteOperation);
 
-    assertEquals(changeListener.getDeleteCount(), 1);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getDeleteCount(), 1);
+    }
+    finally
+    {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -999,22 +972,27 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testFailureWithNotificationListener()
-         throws Exception
+  @Test
+  public void testFailureWithNotificationListener() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getAddCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try
+    {
+      assertEquals(changeListener.getAddCount(), 0);
 
-    DeleteOperation deleteOperation = processDeleteRaw("cn=nonexistent,o=test");
-    assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
+      DeleteOperation deleteOperation = processDeleteRaw("cn=nonexistent,o=test");
+      assertFalse(deleteOperation.getResultCode() == ResultCode.SUCCESS);
 
-    assertEquals(changeListener.getDeleteCount(), 0);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getDeleteCount(), 0);
+    }
+    finally
+    {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -1025,9 +1003,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testShortCircuitInPreParse()
-         throws Exception
+  @Test
+  public void testShortCircuitInPreParse() throws Exception
   {
     TestCaseUtils.initializeTestBackend(true);
 
@@ -1041,4 +1018,3 @@
     assertTrue(DirectoryServer.entryExists(DN.valueOf("o=test")));
   }
 }
-
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
index 1d2f951..01dd576 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -36,6 +36,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
 import org.forgerock.opendj.ldap.ModificationType;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.SearchScope;
 import org.opends.server.TestCaseUtils;
 import org.opends.server.api.Backend;
@@ -44,20 +45,44 @@
 import org.opends.server.plugins.UpdatePreOpPlugin;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
-import org.opends.server.protocols.ldap.*;
+import org.opends.server.protocols.ldap.BindRequestProtocolOp;
+import org.opends.server.protocols.ldap.BindResponseProtocolOp;
+import org.opends.server.protocols.ldap.LDAPAttribute;
+import org.opends.server.protocols.ldap.LDAPControl;
+import org.opends.server.protocols.ldap.LDAPFilter;
+import org.opends.server.protocols.ldap.LDAPMessage;
+import org.opends.server.protocols.ldap.LDAPModification;
+import org.opends.server.protocols.ldap.ModifyRequestProtocolOp;
+import org.opends.server.protocols.ldap.ModifyResponseProtocolOp;
 import org.opends.server.tools.LDAPModify;
 import org.opends.server.tools.LDAPWriter;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.CancelRequest;
+import org.opends.server.types.CancelResult;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.LockManager;
+import org.opends.server.types.Modification;
+import org.opends.server.types.Operation;
+import org.opends.server.types.RawModification;
+import org.opends.server.types.WritabilityMode;
 import org.opends.server.util.Base64;
 import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.workflowelement.localbackend.LocalBackendModifyOperation;
-import org.testng.annotations.*;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
 
 import static org.opends.server.TestCaseUtils.*;
 import static org.opends.server.protocols.internal.InternalClientConnection.*;
 import static org.opends.server.protocols.ldap.LDAPConstants.*;
+import static org.opends.server.util.CollectionUtils.*;
 import static org.testng.Assert.*;
 
 /**
@@ -92,55 +117,45 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @DataProvider(name = "modifyOperations")
-  public Object[][] getModifyOperations()
-         throws Exception
+  public Object[][] getModifyOperations() throws Exception
   {
     List<ModifyOperation> opList = new ArrayList<ModifyOperation>();
 
     List<Control> noControls = new ArrayList<Control>();
 
-
-    List<RawModification> ldapMods = new ArrayList<RawModification>();
     LDAPAttribute ldapAttr = new LDAPAttribute("description", "foo");
-    ldapMods.add(add(ldapAttr));
+    List<RawModification> ldapMods = newRawModifications(add(ldapAttr));
 
     opList.add(newModifyOperation(null, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(null, ByteString.valueOf("o=test"), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.valueOf("o=test"), ldapMods));
 
-    ldapMods = new ArrayList<RawModification>();
-    ldapMods.add(delete(ldapAttr));
+    ldapMods = newRawModifications(delete(ldapAttr));
 
     opList.add(newModifyOperation(null, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(null, ByteString.valueOf("o=test"), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.valueOf("o=test"), ldapMods));
 
-    ldapMods = new ArrayList<RawModification>();
-    ldapMods.add(replace(ldapAttr));
+    ldapMods = newRawModifications(replace(ldapAttr));
 
     opList.add(newModifyOperation(null, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(null, ByteString.valueOf("o=test"), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.valueOf("o=test"), ldapMods));
 
-    ldapMods = new ArrayList<RawModification>();
-    ArrayList<ByteString> values2 = new ArrayList<ByteString>();
-    values2.add(ByteString.valueOf("bar"));
+    ArrayList<ByteString> values2 = newArrayList(ByteString.valueOf("bar"));
     LDAPAttribute ldapAttr2 = new LDAPAttribute("description", values2);
-    ldapMods.add(delete(ldapAttr));
-    ldapMods.add(add(ldapAttr2));
+    ldapMods = newRawModifications(delete(ldapAttr), add(ldapAttr2));
 
     opList.add(newModifyOperation(null, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(null, ByteString.valueOf("o=test"), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.valueOf("o=test"), ldapMods));
 
-    ldapMods = new ArrayList<RawModification>();
     ldapAttr2 = new LDAPAttribute("cn", values2);
-    ldapMods.add(replace(ldapAttr));
-    ldapMods.add(replace(ldapAttr2));
+    ldapMods = newRawModifications(replace(ldapAttr), replace(ldapAttr2));
 
     opList.add(newModifyOperation(null, ByteString.empty(), ldapMods));
     opList.add(newModifyOperation(noControls, ByteString.empty(), ldapMods));
@@ -149,8 +164,7 @@
 
 
 
-    List<Modification> mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.ADD,
+    List<Modification> mods = newModifications(new Modification(ModificationType.ADD,
         Attributes.create("description", "foo")));
 
     opList.add(newModifyOperation(null, DN.rootDN(), mods));
@@ -158,8 +172,7 @@
     opList.add(newModifyOperation(null, DN.valueOf("o=test"), mods));
     opList.add(newModifyOperation(noControls, DN.valueOf("o=test"), mods));
 
-    mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.DELETE,
+    mods = newModifications(new Modification(ModificationType.DELETE,
         Attributes.create("description", "foo")));
 
     opList.add(newModifyOperation(null, DN.rootDN(), mods));
@@ -167,8 +180,7 @@
     opList.add(newModifyOperation(null, DN.valueOf("o=test"), mods));
     opList.add(newModifyOperation(noControls, DN.valueOf("o=test"), mods));
 
-    mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
+    mods = newModifications(new Modification(ModificationType.REPLACE,
         Attributes.create("description", "foo")));
 
     opList.add(newModifyOperation(null, DN.rootDN(), mods));
@@ -176,22 +188,22 @@
     opList.add(newModifyOperation(null, DN.valueOf("o=test"), mods));
     opList.add(newModifyOperation(noControls, DN.valueOf("o=test"), mods));
 
-    mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.DELETE,
-        Attributes.create("description", "foo")));
-    mods.add(new Modification(ModificationType.ADD,
-        Attributes.create("description", "bar")));
+    mods = newModifications(
+        new Modification(ModificationType.DELETE,
+            Attributes.create("description", "foo")),
+        new Modification(ModificationType.ADD,
+            Attributes.create("description", "bar")));
 
     opList.add(newModifyOperation(null, DN.rootDN(), mods));
     opList.add(newModifyOperation(noControls, DN.rootDN(), mods));
     opList.add(newModifyOperation(null, DN.valueOf("o=test"), mods));
     opList.add(newModifyOperation(noControls, DN.valueOf("o=test"), mods));
 
-    mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("description", "foo")));
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("cn", "bar")));
+    mods = newModifications(
+        new Modification(ModificationType.REPLACE,
+            Attributes.create("description", "foo")),
+        new Modification(ModificationType.REPLACE,
+            Attributes.create("cn", "bar")));
 
     opList.add(newModifyOperation(null, DN.rootDN(), mods));
     opList.add(newModifyOperation(noControls, DN.rootDN(), mods));
@@ -241,9 +253,8 @@
 
 
   /** {@inheritDoc} */
-  @Override()
-  protected Operation[] createTestOperations()
-         throws Exception
+  @Override
+  protected Operation[] createTestOperations() throws Exception
   {
     Object[][]  objs = getModifyOperations();
     Operation[] ops  = new Operation[objs.length];
@@ -285,27 +296,25 @@
    * Tests the <CODE>getEntryDN</CODE> method that should decode
    * the raw entry dn and return a non-null DN.
    */
-  @Test()
+  @Test
   public void testGetEntryDNInitiallyNull()
   {
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyOperation modifyOperation = newModifyOperation(null, ByteString.empty(), mods);
     assertNotNull(modifyOperation.getEntryDN());
   }
 
 
-  private LDAPAttribute newLDAPAttribute(String sttributeType, String... valueStrings)
+  private LDAPAttribute newLDAPAttribute(String attributeType, String... valueStrings)
   {
     ArrayList<ByteString> values = new ArrayList<ByteString>();
     for (String valueStr : valueStrings)
     {
       values.add(ByteString.valueOf(valueStr));
     }
-    return new LDAPAttribute(sttributeType, values);
+    return new LDAPAttribute(attributeType, values);
   }
 
   /**
@@ -314,13 +323,12 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNInitiallyNonNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNInitiallyNonNull() throws Exception
   {
-    List<Modification> mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("description", "foo")));
+    List<Modification> mods = newModifications(
+        new Modification(ModificationType.REPLACE,
+            Attributes.create("description", "foo")));
     ModifyOperation modifyOperation = newModifyOperation(null, DN.rootDN(), mods);
     assertNotNull(modifyOperation.getEntryDN());
   }
@@ -334,15 +342,13 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetEntryDNNonNullChangedToNull()
-         throws Exception
+  @Test
+  public void testGetEntryDNNonNullChangedToNull() throws Exception
   {
-    List<Modification> mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("description", "foo")));
-    ModifyOperation modifyOperation =
-        newModifyOperation(null, DN.rootDN(), mods);
+    List<Modification> mods = newModifications(
+        new Modification(ModificationType.REPLACE,
+            Attributes.create("description", "foo")));
+    ModifyOperation modifyOperation = newModifyOperation(null, DN.rootDN(), mods);
     assertNotNull(modifyOperation.getEntryDN());
 
     modifyOperation.setRawEntryDN(ByteString.valueOf("ou=Users,o=test"));
@@ -363,9 +369,7 @@
          throws Exception
   {
     List<RawModification> rawMods = modifyOperation.getRawModifications();
-
-    List<RawModification> clonedMods =
-         new ArrayList<RawModification>(rawMods);
+    List<RawModification> clonedMods = new ArrayList<RawModification>(rawMods);
     modifyOperation.setRawModifications(clonedMods);
 
     LDAPAttribute attr = newLDAPAttribute("test", "test");
@@ -433,9 +437,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testGetAndAddModifications()
-         throws Exception
+  @Test
+  public void testGetAndAddModifications() throws Exception
   {
     Entry e = DirectoryServer.getEntry(DN.valueOf("o=test"));
     assertNull(e.getAttribute(DirectoryServer.getAttributeType("description", true)));
@@ -446,9 +449,9 @@
              Attributes.create("description", "foo")));
 
 
-    List<Modification> mods = new ArrayList<Modification>();
-    mods.add(new Modification(ModificationType.REPLACE,
-        Attributes.create("l", "Austin")));
+    List<Modification> mods = newModifications(
+        new Modification(ModificationType.REPLACE,
+            Attributes.create("l", "Austin")));
 
     ModifyOperation modifyOperation =
         getRootConnection().processModify(DN.valueOf("o=test"), mods);
@@ -466,7 +469,7 @@
   /**
    * Tests to ensure that a modify attempt fails if an invalid DN is provided.
    */
-  @Test()
+  @Test
   public void testFailInvalidDN()
   {
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
@@ -481,7 +484,7 @@
    * Tests to ensure that a modify attempt fails if the target DN is a suffix
    * that doesn't exist.
    */
-  @Test()
+  @Test
   public void testFailNoSuchSuffix()
   {
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
@@ -551,9 +554,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSuccessAddAttribute()
-         throws Exception
+  @Test
+  public void testSuccessAddAttribute() throws Exception
   {
     Entry e = DirectoryServer.getEntry(DN.valueOf("o=test"));
     assertNull(e.getAttribute(DirectoryServer.getAttributeType("description", true)));
@@ -575,9 +577,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSuccessAddAttributeValue()
-         throws Exception
+  @Test
+  public void testSuccessAddAttributeValue() throws Exception
   {
     Entry e = DirectoryServer.getEntry(DN.valueOf("o=test"));
 
@@ -2402,8 +2403,7 @@
     assertEquals(bindResponse.getResultCode(), 0);
 
     LDAPAttribute attr = newLDAPAttribute("entryUUID", "12345678-1234-1234-1234-1234567890ab");
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     long modifyRequests  = ldapStatistics.getModifyRequests();
     long modifyResponses = ldapStatistics.getModifyResponses();
@@ -2543,8 +2543,7 @@
     assertEquals(bindResponse.getResultCode(), 0);
 
     LDAPAttribute attr = newLDAPAttribute("objectClass", "extensibleObject");
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(add(attr));
+    List<RawModification> mods = newRawModifications(add(attr));
 
     long modifyRequests  = ldapStatistics.getModifyRequests();
     long modifyResponses = ldapStatistics.getModifyResponses();
@@ -2690,8 +2689,7 @@
     assertEquals(bindResponse.getResultCode(), 0);
 
     LDAPAttribute attr = newLDAPAttribute("objectClass", "extensibleObject");
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(add(attr));
+    List<RawModification> mods = newRawModifications(add(attr));
 
     long modifyRequests  = ldapStatistics.getModifyRequests();
     long modifyResponses = ldapStatistics.getModifyResponses();
@@ -2721,22 +2719,27 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testSuccessNotifyChangeListeners()
-         throws Exception
+  @Test
+  public void testSuccessNotifyChangeListeners() throws Exception
   {
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getModifyCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try
+    {
+      assertEquals(changeListener.getModifyCount(), 0);
 
-    LDAPAttribute attr = newLDAPAttribute("description", "foo");
-    ModifyOperation modifyOperation = processModify("o=test", replace(attr));
-    assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
-    retrieveSuccessfulOperationElements(modifyOperation);
+      LDAPAttribute attr = newLDAPAttribute("description", "foo");
+      ModifyOperation modifyOperation = processModify("o=test", replace(attr));
+      assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
+      retrieveSuccessfulOperationElements(modifyOperation);
 
-    assertEquals(changeListener.getModifyCount(), 1);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getModifyCount(), 1);
+    }
+    finally
+    {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -2748,21 +2751,26 @@
    * @throws  Exception  If an unexpected problem occurs.
    */
   @Test(dataProvider = "baseDNs")
-  public void testFailDoNotNotifyChangeListeners(String baseDN)
-         throws Exception
+  public void testFailDoNotNotifyChangeListeners(String baseDN) throws Exception
   {
     TestChangeNotificationListener changeListener =
          new TestChangeNotificationListener();
-    DirectoryServer.registerChangeNotificationListener(changeListener);
-    assertEquals(changeListener.getModifyCount(), 0);
+    DirectoryServer.registerInternalPlugin(changeListener);
+    try
+    {
+      assertEquals(changeListener.getModifyCount(), 0);
 
-    LDAPAttribute attr = newLDAPAttribute("dc", "foo");
-    ModifyOperation modifyOperation = processModify(baseDN, replace(attr));
-    assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
-    retrieveFailedOperationElements(modifyOperation);
+      LDAPAttribute attr = newLDAPAttribute("dc", "foo");
+      ModifyOperation modifyOperation = processModify(baseDN, replace(attr));
+      assertFalse(modifyOperation.getResultCode() == ResultCode.SUCCESS);
+      retrieveFailedOperationElements(modifyOperation);
 
-    assertEquals(changeListener.getModifyCount(), 0);
-    DirectoryServer.deregisterChangeNotificationListener(changeListener);
+      assertEquals(changeListener.getModifyCount(), 0);
+    }
+    finally
+    {
+      DirectoryServer.deregisterInternalPlugin(changeListener);
+    }
   }
 
 
@@ -2777,9 +2785,7 @@
          throws Exception
   {
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyOperation modifyOperation =
         newModifyOperation(null, ByteString.valueOf(baseDN), mods);
@@ -2803,9 +2809,7 @@
          throws Exception
   {
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyOperation modifyOperation =
         newModifyOperation(null, ByteString.valueOf(baseDN), mods);
@@ -2874,8 +2878,7 @@
 
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
 
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
@@ -2902,9 +2905,8 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testDisconnectInPreOperationModify()
-         throws Exception
+  @Test
+  public void testDisconnectInPreOperationModify() throws Exception
   {
 
     Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
@@ -2926,8 +2928,7 @@
 
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
 
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(ByteString.valueOf("o=test"), mods);
@@ -2978,8 +2979,7 @@
 
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
 
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
@@ -3054,9 +3054,7 @@
 
 
     LDAPAttribute attr = newLDAPAttribute("description", "foo");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(replace(attr));
+    List<RawModification> mods = newRawModifications(replace(attr));
 
     ModifyRequestProtocolOp modifyRequest =
          new ModifyRequestProtocolOp(ByteString.valueOf(baseDN), mods);
@@ -3097,10 +3095,18 @@
     StaticUtils.close(s);
   }
 
+  private List<Modification> newModifications(Modification... mods)
+  {
+    return newArrayList(mods);
+  }
 
+  private List<RawModification> newRawModifications(RawModification... mods)
+  {
+    return newArrayList(mods);
+  }
 
   /**
-   * Tests a modify operation that attemtps to set a value for an attribute type
+   * Tests a modify operation that attempts to set a value for an attribute type
    * that is marked OBSOLETE in the server schema.
    *
    * @param  baseDN  The base DN for the test backend.
@@ -3219,16 +3225,14 @@
    *
    * @throws  Exception  If an unexpected problem occurs.
    */
-  @Test()
-  public void testShortCircuitInPreParse()
-         throws Exception
+  @Test
+  public void testShortCircuitInPreParse() throws Exception
   {
     List<Control> controls =
          ShortCircuitPlugin.createShortCircuitControlList(0, "PreParse");
 
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(RawModification.create(ModificationType.REPLACE, "description",
-                                    "foo"));
+    List<RawModification> mods = newRawModifications(
+        RawModification.create(ModificationType.REPLACE, "description", "foo"));
 
     ModifyOperation modifyOperation =
         newModifyOperation(controls, ByteString.valueOf("o=test"), mods);
@@ -3269,9 +3273,7 @@
          "userPassword: password");
 
     LDAPAttribute attr = newLDAPAttribute("givenName", "Test");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(add(attr));
+    List<RawModification> mods = newRawModifications(add(attr));
 
     List<Control> requestControls = new ArrayList<Control>();
     requestControls.add(
@@ -3308,9 +3310,7 @@
          "userPassword: password");
 
     LDAPAttribute attr = newLDAPAttribute("givenName", "Foo");
-
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(delete(attr));
+    List<RawModification> mods = newRawModifications(delete(attr));
 
     List<Control> requestControls = new ArrayList<Control>();
     requestControls.add(
@@ -3347,8 +3347,7 @@
          "userPassword: password");
 
     LDAPAttribute attr = new LDAPAttribute("description");
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(delete(attr));
+    List<RawModification> mods = newRawModifications(delete(attr));
 
     List<Control> requestControls = new ArrayList<Control>();
     requestControls.add(
@@ -3523,11 +3522,10 @@
    *           If an unexpected problem occurs.
    */
   @Test
-  public void testModifyDelPasswordAttributeWithOption()
-      throws Exception
+  public void testModifyDelPasswordAttributeWithOption() throws Exception
   {
     // @formatter:off
-        Entry e = TestCaseUtils.makeEntry(
+    Entry e = TestCaseUtils.makeEntry(
         "dn: cn=Test User,o=test",
         "objectClass: top",
         "objectClass: person",
@@ -3565,8 +3563,7 @@
    *           If an unexpected problem occurs.
    */
   @Test
-  public void testModifyReplaceEmptyPasswordAttributeWithOption()
-      throws Exception
+  public void testModifyReplaceEmptyPasswordAttributeWithOption() throws Exception
   {
     // @formatter:off
         Entry e = TestCaseUtils.makeEntry(
@@ -3605,8 +3602,7 @@
    *           If an unexpected problem occurs.
    */
   @Test
-  public void testModifyAddPasswordAttributeWithOption()
-      throws Exception
+  public void testModifyAddPasswordAttributeWithOption() throws Exception
   {
     // @formatter:off
         TestCaseUtils.addEntry(
@@ -3643,8 +3639,7 @@
    *           If an unexpected problem occurs.
    */
   @Test
-  public void testModifyReplaceWithValuesPasswordAttributeWithOption()
-      throws Exception
+  public void testModifyReplaceWithValuesPasswordAttributeWithOption() throws Exception
   {
     // @formatter:off
         TestCaseUtils.addEntry(
@@ -3681,8 +3676,7 @@
    *           If an unexpected problem occurs.
    */
   @Test(dataProvider = "baseDNs")
-  public void testAddCertificateWithoutBinaryOption(String baseDN)
-         throws Exception
+  public void testAddCertificateWithoutBinaryOption(String baseDN) throws Exception
   {
     TestCaseUtils.addEntry(
          "dn: uid=test.user," + baseDN,
@@ -3755,8 +3749,8 @@
     // First check that adding "dc" fails because it is not allowed by
     // inetOrgPerson.
     LDAPAttribute attr = newLDAPAttribute("dc", "foo");
-    List<RawModification> mods = new ArrayList<RawModification>();
-    mods.add(add(attr));
+    List<RawModification> mods = newRawModifications(add(attr));
+
     ModifyOperation modifyOperation = processModify("cn=Test User," + baseDN, mods);
     assertEquals(modifyOperation.getResultCode(), ResultCode.OBJECTCLASS_VIOLATION);
 
diff --git a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java
index 3d0a33b..faea4f7 100644
--- a/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java
+++ b/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java
@@ -22,105 +22,109 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2014 ForgeRock AS
  */
 package org.opends.server.core;
 
-
-
+import java.util.EnumSet;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import org.opends.server.api.ChangeNotificationListener;
-import org.opends.server.types.Entry;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
+import org.opends.server.api.plugin.PluginResult.PostResponse;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
 import org.opends.server.types.operation.PostResponseAddOperation;
 import org.opends.server.types.operation.PostResponseDeleteOperation;
-import org.opends.server.types.operation.PostResponseModifyOperation;
 import org.opends.server.types.operation.PostResponseModifyDNOperation;
+import org.opends.server.types.operation.PostResponseModifyOperation;
 
-
+import static org.opends.server.api.plugin.PluginType.*;
 
 /**
  * This class provides a simple change notification listener that simply counts
  * the number of times that it is invoked during processing.
  */
-public class TestChangeNotificationListener
-       implements ChangeNotificationListener
+class TestChangeNotificationListener extends InternalDirectoryServerPlugin
 {
-  // The number of times that the listener has been invoked for add operations.
-  private AtomicInteger addCount;
+  /** The number of times that the listener has been invoked for add operations. */
+  private final AtomicInteger addCount = new AtomicInteger(0);
 
-  // The number of times that the listener has been invoked for delete
-  // operations.
-  private AtomicInteger deleteCount;
+  /**
+   * The number of times that the listener has been invoked for delete
+   * operations.
+   */
+  private final AtomicInteger deleteCount = new AtomicInteger(0);
 
-  // The number of times that the listener has been invoked for modify
-  // operations.
-  private AtomicInteger modifyCount;
+  /**
+   * The number of times that the listener has been invoked for modify
+   * operations.
+   */
+  private final AtomicInteger modifyCount = new AtomicInteger(0);
 
-  // The number of times that the listener has been invoked for modify DN
-  // operations.
-  private AtomicInteger modifyDNCount;
-
-
+  /**
+   * The number of times that the listener has been invoked for modify DN
+   * operations.
+   */
+  private final AtomicInteger modifyDNCount = new AtomicInteger(0);
 
   /**
    * Creates a new instance of this change notification listener.
+   *
+   * @throws DirectoryException
+   *           If a problem occurs while creating an instance of this class
    */
-  public TestChangeNotificationListener()
+  public TestChangeNotificationListener() throws DirectoryException
   {
-    addCount      = new AtomicInteger(0);
-    deleteCount   = new AtomicInteger(0);
-    modifyCount   = new AtomicInteger(0);
-    modifyDNCount = new AtomicInteger(0);
+    super(DN.valueOf("cn=TestChangeNotificationListener"),
+        EnumSet.of(POST_RESPONSE_ADD, POST_RESPONSE_MODIFY, POST_RESPONSE_MODIFY_DN, POST_RESPONSE_DELETE),
+        true);
   }
 
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public void handleAddOperation(PostResponseAddOperation addOperation,
-                                 Entry entry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseAddOperation op)
   {
-    addCount.incrementAndGet();
+    if (op.getResultCode() == ResultCode.SUCCESS)
+    {
+      addCount.incrementAndGet();
+    }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation,
-                                    Entry entry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseDeleteOperation op)
   {
-    deleteCount.incrementAndGet();
+    if (op.getResultCode() == ResultCode.SUCCESS)
+    {
+      deleteCount.incrementAndGet();
+    }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public void handleModifyOperation(PostResponseModifyOperation modifyOperation,
-                                    Entry oldEntry, Entry newEntry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseModifyOperation op)
   {
-    modifyCount.incrementAndGet();
+    if (op.getResultCode() == ResultCode.SUCCESS)
+    {
+      modifyCount.incrementAndGet();
+    }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public void handleModifyDNOperation(
-                   PostResponseModifyDNOperation modifyDNOperation,
-                   Entry oldEntry, Entry newEntry)
+  /** {@inheritDoc} */
+  @Override
+  public PostResponse doPostResponse(PostResponseModifyDNOperation op)
   {
-    modifyDNCount.incrementAndGet();
+    if (op.getResultCode() == ResultCode.SUCCESS)
+    {
+      modifyDNCount.incrementAndGet();
+    }
+    return PostResponse.continueOperationProcessing();
   }
 
-
-
   /**
    * Resets all of the counts to zero.
    */
@@ -132,8 +136,6 @@
     modifyDNCount.set(0);
   }
 
-
-
   /**
    * Retrieves the current invocation count for add operations.
    *
@@ -144,8 +146,6 @@
     return addCount.get();
   }
 
-
-
   /**
    * Retrieves the current invocation count for delete operations.
    *
@@ -156,8 +156,6 @@
     return deleteCount.get();
   }
 
-
-
   /**
    * Retrieves the current invocation count for modify operations.
    *
@@ -168,8 +166,6 @@
     return modifyCount.get();
   }
 
-
-
   /**
    * Retrieves the current invocation count for modify DN operations.
    *

--
Gitblit v1.10.0