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

Jean-Noel Rouvignac
27.29.2014 e13a57df8301091f093cf0b1a16527da8f9b3926
OPENDJ-1206 (CR-4368) Create a new ReplicationBackend/ChangelogBackend to support cn=changelog

Preparation work: ChangeNotificationListener interface only cover a subset of its DirectoryServerPlugin superclass capabilities, so it is redundant.
So I removed ChangeNotificationListener to ease moving persistent searches to the backend.
The two ChangeNotificationListener implementations are now subclasses of InternalDirectoryServerPlugin.
Updated all code after removing ChangeNotificationListener.



ChangeNotificationListener.java: REMOVED



AuthenticatedUsers.java:
Now extends InternalDirectoryServerPlugin instead of implementing ChangeNotificationListener.
Extracted method getNewAuthNDN() + toDN().

CryptoManagerSync.java:
Now extends InternalDirectoryServerPlugin instead of implementing ChangeNotificationListener.
Extracted method getNewAuthNDN() + toDN().



DirectoryServer.java:
Removed references to removed type ChangeNotificationListener.
Be careful with when AuthenticatedUsers is initialized.

DirectoryConfig.java, LocalBackend*Operation.java:
Removed references to removed type ChangeNotificationListener.



CollectionUtils.java: ADDED

TestChangeNotificationListener.java:
Now extends InternalDirectoryServerPlugin instead of implementing ChangeNotificationListener.

AddOperationTestCase.java:
Extracted methods newRawAttributes(), byteStrings(), addSuccess(), addDisconnect(), bind(), writeAddRequest() + used CollectionUtils.
Consequence of the changes to TestChangeNotificationListener.

DeleteOperationTestCase.java:
Consequence of the changes to TestChangeNotificationListener.

ModifyOperationTestCase.java:
Extracted methods newModifications(), newRawModifications() + used CollectionUtils.
Consequence of the changes to TestChangeNotificationListener.
12 files modified
1 files deleted
1 files added
2509 ■■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/api/ChangeNotificationListener.java 134 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java 204 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java 105 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java 317 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/types/DirectoryConfig.java 48 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/util/CollectionUtils.java 109 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java 21 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java 22 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java 23 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java 23 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/AddOperationTestCase.java 887 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java 218 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java 262 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/TestChangeNotificationListener.java 136 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/api/ChangeNotificationListener.java
File was deleted
opendj-sdk/opends/src/server/org/opends/server/core/AuthenticatedUsers.java
@@ -22,32 +22,29 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      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.opends.messages.Message;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.opends.server.api.ChangeNotificationListener;
import org.opends.messages.Message;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.DITCacheMap;
import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
import org.opends.server.api.plugin.PluginResult.PostResponse;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.Entry;
import org.opends.server.types.operation.PostResponseAddOperation;
import org.opends.server.types.*;
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.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
/**
@@ -60,34 +57,52 @@
 * 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
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  // 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.decode(dn);
    }
    catch (DirectoryException e)
    {
      throw new RuntimeException(e);
    }
  }
  /**
   * Registers the provided user DN and client connection with this object.
@@ -102,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>();
@@ -136,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);
@@ -179,89 +192,59 @@
    }
  }
  /**
   * 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.getDN(), arraySet);
      userMap.removeSubtree(entryDN, arraySet);
    }
    finally
    {
      lock.writeLock().unlock();
    }
    for (CopyOnWriteArraySet<ClientConnection>
            connectionSet : arraySet)
    for (CopyOnWriteArraySet<ClientConnection> connectionSet : arraySet)
    {
      for (ClientConnection conn : connectionSet)
      {
        Message message = WARN_CLIENTCONNECTION_DISCONNECT_DUE_TO_DELETE.get(
                String.valueOf(entry.getDN()));
                String.valueOf(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.getDN());
      CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(oldEntry.getDN());
      if (connectionSet != null)
      {
        for (ClientConnection conn : connectionSet)
@@ -274,23 +257,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.getDN().toNormalizedString();
    String newDNString = newEntry.getDN().toNormalizedString();
@@ -303,8 +282,7 @@
      Set<CopyOnWriteArraySet<ClientConnection>> arraySet =
        new HashSet<CopyOnWriteArraySet<ClientConnection>>();
      userMap.removeSubtree(oldEntry.getDN(), arraySet);
      for (CopyOnWriteArraySet<ClientConnection>
              connectionSet : arraySet)
      for (CopyOnWriteArraySet<ClientConnection> connectionSet : arraySet)
      {
        DN authNDN = null;
        DN authZDN = null;
@@ -319,17 +297,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.decode(newAuthNDNString);
              newAuthNDN = getNewAuthDN(authNDN, oldDNString, newDNString);
            }
            catch (Exception e)
            {
              // Shouldnt happen.
              // Should not happen.
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
@@ -341,24 +313,18 @@
            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.decode(newAuthZDNString);
              newAuthZDN = getNewAuthDN(authZDN, oldDNString, newDNString);
            }
            catch (Exception e)
            {
              // Shouldnt happen.
              // Should not happen.
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
            }
          }
          if ((newAuthNDN != null) && (authNDN != null) &&
          if (newAuthNDN != null && authNDN != null &&
               authNDN.isDescendantOf(oldEntry.getDN()))
          {
            if (newAuthNSet == null)
@@ -368,7 +334,7 @@
            conn.getAuthenticationInfo().setAuthenticationDN(newAuthNDN);
            newAuthNSet.add(conn);
          }
          if ((newAuthZDN != null) && (authZDN != null) &&
          if (newAuthZDN != null && authZDN != null &&
               authZDN.isDescendantOf(oldEntry.getDN()))
          {
            if (newAuthZSet == null)
@@ -379,11 +345,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);
        }
@@ -393,6 +359,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.decode(builder.toString());
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -26,19 +26,6 @@
 */
package org.opends.server.core;
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.loggers.AccessLogger.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
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 static org.opends.server.util.Validator.*;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
@@ -94,6 +81,19 @@
import org.opends.server.workflowelement.WorkflowElementConfigManager;
import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
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.loggers.AccessLogger.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
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 static org.opends.server.util.Validator.*;
/**
 * This class defines the core of the Directory Server.  It manages the startup
 * and shutdown processes and coordinates activities between all other
@@ -405,13 +405,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;
@@ -922,8 +915,6 @@
      directoryServer.backendInitializationListeners =
           new CopyOnWriteArraySet<BackendInitializationListener>();
      directoryServer.baseDnRegistry = new BaseDnRegistry();
      directoryServer.changeNotificationListeners =
           new CopyOnWriteArrayList<ChangeNotificationListener>();
      directoryServer.initializationCompletedListeners =
           new CopyOnWriteArrayList<InitializationCompletedListener>();
      directoryServer.shutdownListeners =
@@ -941,7 +932,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>();
@@ -1378,23 +1368,15 @@
      certificateMapperConfigManager.initializeCertificateMappers();
      // Initialize the identity mappers.
      initializeIdentityMappers();
      // Initialize the root DNs.
      rootDNConfigManager = new RootDNConfigManager();
      rootDNConfigManager.initializeRootDNs();
      // Initialize the subentry manager.
      directoryServer.authenticatedUsers = new AuthenticatedUsers();
      // initialize both subentry manager and group manager for this backend.
      initializeSubentryManager();
      // Initialize the group manager.
      initializeGroupManager();
      // Now we can initialize both subentry manager and group manager
      // for this backend.
      subentryManager.performBackendInitializationProcessing(configHandler);
      groupManager.performBackendInitializationProcessing(configHandler);
@@ -1424,14 +1406,9 @@
      // Reset the map as we can no longer guarantee offline state.
      directoryServer.offlineBackendsStateIDs.clear();
      // Initialize all the extended operation handlers.
      initializeExtendedOperations();
      // Initialize all the SASL mechanism handlers.
      initializeSASLMechanisms();
      // Initialize all the connection handlers
      // (including the administration connector).
      if (startConnectionHandlers)
@@ -1439,13 +1416,9 @@
        initializeConnectionHandlers();
      }
      // Initialize all the monitor providers.
      monitorConfigManager = new MonitorConfigManager();
      monitorConfigManager.initializeMonitorProviders();
      // Initialize all the authentication policy components.
      initializeAuthenticationPolicyComponents();
@@ -7155,54 +7128,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.
opendj-sdk/opends/src/server/org/opends/server/crypto/CryptoManagerSync.java
@@ -22,95 +22,93 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2014 ForgeRock AS
 */
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.opends.admin.ads.ADSContext;
import org.opends.messages.Message;
import org.opends.server.api.Backend;
import org.opends.server.api.BackendInitializationListener;
import org.opends.server.api.ChangeNotificationListener;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
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;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.loggers.debug.DebugTracer;
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.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.server.util.StaticUtils.stackTraceToSingleLineString;
import static org.opends.server.util.ServerConstants.OC_TOP;
import static org.opends.server.util.ServerConstants.
     OID_ENTRY_CHANGE_NOTIFICATION;
import org.opends.server.config.ConfigConstants;
import static org.opends.server.config.ConfigConstants.OC_CRYPTO_INSTANCE_KEY;
import static org.opends.server.config.ConfigConstants.OC_CRYPTO_CIPHER_KEY;
import static org.opends.server.config.ConfigConstants.OC_CRYPTO_MAC_KEY;
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.controls.PersistentSearchChangeType;
import org.opends.server.controls.EntryChangeNotificationControl;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.AddOperation;
import static org.opends.messages.CoreMessages.*;
import org.opends.messages.Message;
import org.opends.admin.ads.ADSContext;
import java.util.LinkedHashSet;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.HashMap;
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.loggers.debug.DebugLogger.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * 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 DebugTracer TRACER = getTracer();
  // 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.
@@ -119,29 +117,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());
@@ -163,15 +149,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);
@@ -185,22 +167,32 @@
      searchAdminSuffix();
    }
    DirectoryServer.registerChangeNotificationListener(this);
    DirectoryServer.registerInternalPlugin(this);
  }
  private static DN toDN(final String dn) throws InitializationException
  {
    try
    {
      return DN.decode(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,
                                     DereferencePolicy.NEVER_DEREF_ALIASES,
@@ -242,9 +234,8 @@
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public void performBackendInitializationProcessing(Backend backend)
  {
    DN[] baseDNs = backend.getBaseDNs();
@@ -260,9 +251,8 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  /** {@inheritDoc} */
  @Override
  public void performBackendFinalizationProcessing(Backend backend)
  {
    // No implementation required.
@@ -315,7 +305,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)
            {
@@ -340,8 +330,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);
@@ -349,24 +338,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);
      }
    }
  }
@@ -380,11 +366,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;
@@ -395,21 +378,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)
    {
@@ -485,18 +459,22 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleAddOperation(PostResponseAddOperation addOperation,
                                 Entry entry)
  /** {@inheritDoc} */
  @Override
  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
      {
@@ -511,11 +489,11 @@
      }
      catch (CryptoManagerException e)
      {
        Message message = Message.raw("Failed to import key entry: %s",
                                      e.getMessage());
        ErrorLogger.logError(message);
        ErrorLogger.logError(
            Message.raw("Failed to import key entry: %s", e.getMessage()));
      }
    }
    return PostResponse.continueOperationProcessing();
  }
@@ -536,18 +514,17 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation,
                                    Entry entry)
  /** {@inheritDoc} */
  @Override
  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.getDN().getRDN();
    RDN srcRDN = op.getEntryToDelete().getDN().getRDN();
    // Only process the entry if it has the expected form of RDN.
    // FIXME: Technically it is possible to perform a subtree in
@@ -556,23 +533,28 @@
    if (!srcRDN.isMultiValued() &&
         srcRDN.getAttributeType(0).equals(attrAlias))
    {
      DN dstDN = trustStoreRootDN.concat(srcRDN);
      deleteEntry(dstDN);
      DN destDN = trustStoreRootDN.concat(srcRDN);
      deleteEntry(destDN);
    }
    return PostResponse.continueOperationProcessing();
  }
  /**
   * {@inheritDoc}
   */
  public void handleModifyOperation(PostResponseModifyOperation modifyOperation,
                                    Entry oldEntry, Entry newEntry)
  /** {@inheritDoc} */
  @Override
  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
      {
@@ -592,6 +574,7 @@
        ErrorLogger.logError(message);
      }
    }
    return PostResponse.continueOperationProcessing();
  }
  private void handleInstanceKeyModifyOperation(Entry newEntry)
@@ -624,30 +607,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}
   */
  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.
  }
}
opendj-sdk/opends/src/server/org/opends/server/types/DirectoryConfig.java
@@ -22,21 +22,17 @@
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 *      Portions copyright 2013 ForgeRock AS.
 *      Portions copyright 2013-2014 ForgeRock AS.
 */
package org.opends.server.types;
import java.util.List;
import org.opends.messages.Message;
import java.util.Map;
import java.util.Set;
import org.opends.messages.Message;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.ChangeNotificationListener;
import org.opends.server.api.ConfigHandler;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.ExtendedOperationHandler;
@@ -50,10 +46,9 @@
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
/**
 * This interface defines a set of methods that may be used by
 * third-party code to obtatin information about the core Directory
 * third-party code to obtain information about the core Directory
 * Server configuration and the instances of various kinds of
 * components that have registered themselves with the server.
 * <BR><BR>
@@ -1089,43 +1084,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.
opendj-sdk/opends/src/server/org/opends/server/util/CollectionUtils.java
New file
@@ -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));
  }
}
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -184,31 +184,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)
            {
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
              logError(ERR_ADD_ERROR_NOTIFYING_CHANGE_LISTENER
                  .get(getExceptionMessage(e)));
            }
          }
        }
      });
    }
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -31,7 +31,6 @@
import org.opends.messages.Message;
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;
@@ -176,31 +175,10 @@
        @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)
            {
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
              logError(ERR_DELETE_ERROR_NOTIFYING_CHANGE_LISTENER
                  .get(getExceptionMessage(e)));
            }
          }
        }
      });
    }
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -34,7 +34,6 @@
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
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;
@@ -204,32 +203,10 @@
        @Override
        public void run()
        {
          // Notify persistent searches.
          for (PersistentSearch psearch : wfe.getPersistentSearches())
          {
            psearch.processModifyDN(newEntry, currentEntry.getDN());
          }
          // Notify change listeners.
          for (ChangeNotificationListener changeListener : DirectoryServer
              .getChangeNotificationListeners())
          {
            try
            {
              changeListener.handleModifyDNOperation(
                  LocalBackendModifyDNOperation.this, currentEntry, newEntry);
            }
            catch (Exception e)
            {
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
              logError(ERR_MODDN_ERROR_NOTIFYING_CHANGE_LISTENER
                  .get(getExceptionMessage(e)));
            }
          }
        }
      });
    }
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -317,33 +317,10 @@
        @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)
            {
              if (debugEnabled())
              {
                TRACER.debugCaught(DebugLogLevel.ERROR, e);
              }
              logError(ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER
                  .get(getExceptionMessage(e)));
            }
          }
        }
      });
    }
opendj-sdk/opends/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;
@@ -51,6 +53,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.*;
/**
@@ -76,21 +79,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",
@@ -129,9 +124,8 @@
  /** {@inheritDoc} */
  @Override()
  protected Operation[] createTestOperations()
         throws Exception
  @Override
  protected Operation[] createTestOperations() throws Exception
  {
    Object[][]  objs = getAddOperations();
    Operation[] ops  = new Operation[objs.length];
@@ -173,19 +167,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(),
@@ -194,7 +181,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
@@ -202,9 +202,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",
@@ -229,9 +228,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",
@@ -265,32 +263,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;
  }
@@ -300,9 +293,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testAddObjectClass()
         throws Exception
  @Test
  public void testAddObjectClass() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -334,9 +326,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testRemoveObjectClass()
         throws Exception
  @Test
  public void testRemoveObjectClass() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -370,9 +361,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.decode("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.decode("o=test")));
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/DeleteOperationTestCase.java
@@ -68,9 +68,8 @@
  }
  /** {@inheritDoc} */
  @Override()
  protected Operation[] createTestOperations()
         throws Exception
  @Override
  protected Operation[] createTestOperations() throws Exception
  {
    List<Control> noControls = new ArrayList<Control>();
    return new Operation[]
@@ -130,7 +129,7 @@
   * Tests the <CODE>getEntryDN</CODE> method that should decode the rawEntryDN
   * to compute the entryDN.
   */
  @Test()
  @Test
  public void testGetEntryDNNull()
  {
    DeleteOperation deleteOperation =
@@ -145,9 +144,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.decode("o=test"));
@@ -165,9 +163,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.decode("o=test"));
@@ -201,9 +198,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetEntryToDeleteExists()
         throws Exception
  @Test
  public void testGetEntryToDeleteExists() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -221,13 +217,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.decode(entryDN));
  }
@@ -244,9 +240,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testGetEntryToDeleteNonExistent()
         throws Exception
  @Test
  public void testGetEntryToDeleteNonExistent() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -268,9 +263,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testExternalDelete()
         throws Exception
  @Test
  public void testExternalDelete() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -285,9 +279,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithValidRawDNSuffix()
         throws Exception
  @Test
  public void testDeleteWithValidRawDNSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -303,9 +296,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithValidProcessedDNSuffix()
         throws Exception
  @Test
  public void testDeleteWithValidProcessedDNSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -321,9 +313,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithValidRawDNLeaf()
         throws Exception
  @Test
  public void testDeleteWithValidRawDNLeaf() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -344,9 +335,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithValidProcessedDNLeaf()
         throws Exception
  @Test
  public void testDeleteWithValidProcessedDNLeaf() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -367,9 +357,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithMalformedRawDN()
         throws Exception
  @Test
  public void testDeleteWithMalformedRawDN() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -385,9 +374,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonExistentSuffixRawDN()
         throws Exception
  @Test
  public void testDeleteWithNonExistentSuffixRawDN() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -403,9 +391,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonExistentSuffixProcessedDN()
         throws Exception
  @Test
  public void testDeleteWithNonExistentSuffixProcessedDN() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -420,9 +407,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithRawDNBelowNonExistentSuffix()
         throws Exception
  @Test
  public void testDeleteWithRawDNBelowNonExistentSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -438,9 +424,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithProcessedDNBelowNonExistentSuffix()
         throws Exception
  @Test
  public void testDeleteWithProcessedDNBelowNonExistentSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -456,9 +441,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonExistentRawDNBelowExistingSuffix()
         throws Exception
  @Test
  public void testDeleteWithNonExistentRawDNBelowExistingSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -474,9 +458,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonExistentProcessedDNBelowExistingSuffix()
         throws Exception
  @Test
  public void testDeleteWithNonExistentProcessedDNBelowExistingSuffix() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -491,9 +474,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonLeafRawDN()
         throws Exception
  @Test
  public void testDeleteWithNonLeafRawDN() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -513,9 +495,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithNonLeafProcessedDN()
         throws Exception
  @Test
  public void testDeleteWithNonLeafProcessedDN() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -536,9 +517,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithServerWritabilityDisabled()
         throws Exception
  @Test
  public void testDeleteWithServerWritabilityDisabled() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -558,9 +538,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testInternalDeleteWithServerWritabilityInternalOnly()
         throws Exception
  @Test
  public void testInternalDeleteWithServerWritabilityInternalOnly() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -580,9 +559,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testExternalDeleteWithServerWritabilityInternalOnly()
         throws Exception
  @Test
  public void testExternalDeleteWithServerWritabilityInternalOnly() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -602,9 +580,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDeleteWithBackendWritabilityDisabled()
         throws Exception
  @Test
  public void testDeleteWithBackendWritabilityDisabled() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -625,9 +602,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testInternalDeleteWithBackendWritabilityInternalOnly()
         throws Exception
  @Test
  public void testInternalDeleteWithBackendWritabilityInternalOnly() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -648,9 +624,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testExternalDeleteWithBackendWritabilityInternalOnly()
         throws Exception
  @Test
  public void testExternalDeleteWithBackendWritabilityInternalOnly() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -681,9 +656,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testCancelBeforeStartup()
         throws Exception
  @Test
  public void testCancelBeforeStartup() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -702,9 +676,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testCancelAfterOperation()
         throws Exception
  @Test
  public void testCancelAfterOperation() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -729,8 +702,7 @@
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups = { "slow" })
  public void testCannotLockEntry()
         throws Exception
  public void testCannotLockEntry() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -754,9 +726,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreParseDelete()
         throws Exception
  @Test
  public void testDisconnectInPreParseDelete() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -802,9 +773,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPreOperationDelete()
         throws Exception
  @Test
  public void testDisconnectInPreOperationDelete() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -851,9 +821,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostOperationDelete()
         throws Exception
  @Test
  public void testDisconnectInPostOperationDelete() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -900,9 +869,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testDisconnectInPostResponseDelete()
         throws Exception
  @Test
  public void testDisconnectInPostResponseDelete() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -970,23 +938,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);
    }
  }
@@ -997,22 +970,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);
    }
  }
@@ -1023,9 +1001,8 @@
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testShortCircuitInPreParse()
         throws Exception
  @Test
  public void testShortCircuitInPreParse() throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
@@ -1039,4 +1016,3 @@
    assertTrue(DirectoryServer.entryExists(DN.decode("o=test")));
  }
}
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -53,6 +53,7 @@
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.*;
/**
@@ -87,55 +88,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));
@@ -144,8 +135,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.nullDN(), mods));
@@ -153,8 +143,7 @@
    opList.add(newModifyOperation(null, DN.decode("o=test"), mods));
    opList.add(newModifyOperation(noControls, DN.decode("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.nullDN(), mods));
@@ -162,8 +151,7 @@
    opList.add(newModifyOperation(null, DN.decode("o=test"), mods));
    opList.add(newModifyOperation(noControls, DN.decode("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.nullDN(), mods));
@@ -171,22 +159,22 @@
    opList.add(newModifyOperation(null, DN.decode("o=test"), mods));
    opList.add(newModifyOperation(noControls, DN.decode("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.nullDN(), mods));
    opList.add(newModifyOperation(noControls, DN.nullDN(), mods));
    opList.add(newModifyOperation(null, DN.decode("o=test"), mods));
    opList.add(newModifyOperation(noControls, DN.decode("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.nullDN(), mods));
    opList.add(newModifyOperation(noControls, DN.nullDN(), mods));
@@ -236,9 +224,8 @@
  /** {@inheritDoc} */
  @Override()
  protected Operation[] createTestOperations()
         throws Exception
  @Override
  protected Operation[] createTestOperations() throws Exception
  {
    Object[][]  objs = getModifyOperations();
    Operation[] ops  = new Operation[objs.length];
@@ -280,27 +267,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);
  }
  /**
@@ -309,13 +294,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.nullDN(), mods);
    assertNotNull(modifyOperation.getEntryDN());
  }
@@ -329,15 +313,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.nullDN(), mods);
    List<Modification> mods = newModifications(
        new Modification(ModificationType.REPLACE,
            Attributes.create("description", "foo")));
    ModifyOperation modifyOperation = newModifyOperation(null, DN.nullDN(), mods);
    assertNotNull(modifyOperation.getEntryDN());
    modifyOperation.setRawEntryDN(ByteString.valueOf("ou=Users,o=test"));
@@ -358,9 +340,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");
@@ -428,9 +408,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.decode("o=test"));
    assertNull(e.getAttribute(DirectoryServer.getAttributeType("description", true)));
@@ -441,9 +420,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.decode("o=test"), mods);
@@ -461,7 +440,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");
@@ -476,7 +455,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");
@@ -546,9 +525,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.decode("o=test"));
    assertNull(e.getAttribute(DirectoryServer.getAttributeType("description", true)));
@@ -570,9 +548,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.decode("o=test"));
@@ -2397,8 +2374,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();
@@ -2538,8 +2514,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();
@@ -2685,8 +2660,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();
@@ -2716,22 +2690,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);
    }
  }
@@ -2743,21 +2722,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);
    }
  }
@@ -2772,9 +2756,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);
@@ -2798,9 +2780,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);
@@ -2869,8 +2849,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);
@@ -2897,9 +2876,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());
@@ -2921,8 +2899,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);
@@ -2973,8 +2950,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);
@@ -3049,9 +3025,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);
@@ -3092,10 +3066,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.
@@ -3214,16 +3196,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);
@@ -3264,9 +3244,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(
@@ -3303,9 +3281,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(
@@ -3342,8 +3318,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(
@@ -3518,11 +3493,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",
@@ -3560,8 +3534,7 @@
   *           If an unexpected problem occurs.
   */
  @Test
  public void testModifyReplaceEmptyPasswordAttributeWithOption()
      throws Exception
  public void testModifyReplaceEmptyPasswordAttributeWithOption() throws Exception
  {
    // @formatter:off
        Entry e = TestCaseUtils.makeEntry(
@@ -3600,8 +3573,7 @@
   *           If an unexpected problem occurs.
   */
  @Test
  public void testModifyAddPasswordAttributeWithOption()
      throws Exception
  public void testModifyAddPasswordAttributeWithOption() throws Exception
  {
    // @formatter:off
        TestCaseUtils.addEntry(
@@ -3638,8 +3610,7 @@
   *           If an unexpected problem occurs.
   */
  @Test
  public void testModifyReplaceWithValuesPasswordAttributeWithOption()
      throws Exception
  public void testModifyReplaceWithValuesPasswordAttributeWithOption() throws Exception
  {
    // @formatter:off
        TestCaseUtils.addEntry(
@@ -3676,8 +3647,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,
@@ -3750,8 +3720,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);
opendj-sdk/opends/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.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.ResultCode;
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.decode("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.
   *