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

Jean-Noel Rouvignac
22.46.2014 2e56b3f76709f8f82fabad8a51362c18cbba5fe4
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.
Added initializeAuthenticatedUsers().

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

EncodePassword.java:
In initializeServerComponents(), called DirectoryServer.initializeAuthenticatedUsers() to initialize DirectoryServer.authenticatedUsers and avoid the NPE.
Extracted method listPasswordStorageSchemes().
Code cleanup.


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