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

jdemendi
16.02.2007 4a13a6f1bfb01263a8cabce941e94e1e7b883e00
opendj-sdk/opends/src/server/org/opends/server/api/AccessControlHandler.java
@@ -161,8 +161,8 @@
   * @return  {@code true} if the operation should be allowed by the
   *          access control configuration, or {@code false} if not.
   */
  public abstract boolean isAllowed(CompareOperation
                                         compareOperation);
  public abstract boolean isAllowed(LocalBackendCompareOperation
      compareOperation);
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciHandler.java
@@ -880,7 +880,7 @@
     * @param operation The compare operation to check access on.
     * @return  True if access is allowed.
     */
   public boolean isAllowed(CompareOperation operation) {
   public boolean isAllowed(LocalBackendCompareOperation operation) {
       AciLDAPOperationContainer operationContainer =
               new AciLDAPOperationContainer(operation, ACI_COMPARE);
       String baseName;
opendj-sdk/opends/src/server/org/opends/server/authorization/dseecompat/AciLDAPOperationContainer.java
@@ -58,7 +58,9 @@
     * @param operation The compare operation to evaluate.
     * @param rights  The rights of a compare operation.
     */
    public AciLDAPOperationContainer(CompareOperation operation, int rights) {
    public AciLDAPOperationContainer(LocalBackendCompareOperation operation,
        int rights)
    {
        super(operation, rights, operation.getEntryToCompare());
    }
opendj-sdk/opends/src/server/org/opends/server/core/CompareOperation.java
@@ -26,188 +26,27 @@
 */
package org.opends.server.core;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.opends.server.api.Backend;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PostOperationPluginResult;
import org.opends.server.api.plugin.PreOperationPluginResult;
import org.opends.server.api.plugin.PreParsePluginResult;
import org.opends.server.controls.LDAPAssertionRequestControl;
import org.opends.server.controls.ProxiedAuthV1Control;
import org.opends.server.controls.ProxiedAuthV2Control;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.types.AbstractOperation;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
import org.opends.server.types.Control;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.LDAPException;
import org.opends.server.types.LockManager;
import org.opends.server.types.OperationType;
import org.opends.server.types.Privilege;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.operation.PostOperationCompareOperation;
import org.opends.server.types.operation.PostResponseCompareOperation;
import org.opends.server.types.operation.PreOperationCompareOperation;
import org.opends.server.types.operation.PreParseCompareOperation;
import static org.opends.server.core.CoreConstants.*;
import static org.opends.server.loggers.AccessLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import org.opends.server.types.Operation;
/**
 * This class defines an operation that may be used to determine whether a
 * This interface defines an operation that may be used to determine whether a
 * specified entry in the Directory Server contains a given attribute-value
 * pair.
 */
public class CompareOperation
       extends AbstractOperation
       implements PreParseCompareOperation, PreOperationCompareOperation,
                  PostOperationCompareOperation, PostResponseCompareOperation
public interface CompareOperation extends Operation
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = DebugLogger.getTracer();
  // The attribute type for this compare operation.
  private AttributeType attributeType;
  // The assertion value for the compare operation.
  private ByteString assertionValue;
  // The raw, unprocessed entry DN as included in the client request.
  private ByteString rawEntryDN;
  // The cancel request that has been issued for this compare operation.
  private CancelRequest cancelRequest;
  // The DN of the entry for the compare operation.
  private DN entryDN;
  // The proxied authorization target DN for this operation.
  private DN proxiedAuthorizationDN;
  // The entry to be compared.
  private Entry entry;
  // The set of response controls for this compare operation.
  private List<Control> responseControls;
  // The attribute type for the compare operation.
  private String rawAttributeType;
  /**
   * Creates a new compare operation with the provided information.
   *
   * @param  clientConnection  The client connection with which this operation
   *                           is associated.
   * @param  operationID       The operation ID for this operation.
   * @param  messageID         The message ID of the request with which this
   *                           operation is associated.
   * @param  requestControls   The set of controls included in the request.
   * @param  rawEntryDN        The raw, unprocessed entry DN as provided in the
   *                           client request.  This may or may not be a valid
   *                           DN as no validation will have been performed yet.
   * @param  rawAttributeType  The raw attribute type for the compare operation.
   * @param  assertionValue    The assertion value for the compare operation.
   */
  public CompareOperation(ClientConnection clientConnection, long operationID,
                          int messageID, List<Control> requestControls,
                          ByteString rawEntryDN, String rawAttributeType,
                          ByteString assertionValue)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.rawEntryDN       = rawEntryDN;
    this.rawAttributeType = rawAttributeType;
    this.assertionValue   = assertionValue;
    responseControls       = new ArrayList<Control>();
    entry                  = null;
    entryDN                = null;
    attributeType          = null;
    cancelRequest          = null;
    proxiedAuthorizationDN = null;
  }
  /**
   * Creates a new compare operation with the provided information.
   *
   * @param  clientConnection  The client connection with which this operation
   *                           is associated.
   * @param  operationID       The operation ID for this operation.
   * @param  messageID         The message ID of the request with which this
   *                           operation is associated.
   * @param  requestControls   The set of controls included in the request.
   * @param  entryDN           The entry DN for this compare operation.
   * @param  attributeType     The attribute type for this compare operation.
   * @param  assertionValue    The assertion value for the compare operation.
   */
  public CompareOperation(ClientConnection clientConnection, long operationID,
                          int messageID, List<Control> requestControls,
                          DN entryDN, AttributeType attributeType,
                          ByteString assertionValue)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.entryDN        = entryDN;
    this.attributeType  = attributeType;
    this.assertionValue = assertionValue;
    responseControls       = new ArrayList<Control>();
    rawEntryDN             = new ASN1OctetString(entryDN.toString());
    rawAttributeType       = attributeType.getNameOrOID();
    cancelRequest          = null;
    entry                  = null;
    proxiedAuthorizationDN = null;
  }
  /**
   * Retrieves the raw, unprocessed entry DN as included in the client request.
   * The DN that is returned may or may not be a valid DN, since no validation
   * will have been performed upon it.
   *
   * @return  The raw, unprocessed entry DN as included in the client request.
   */
  public final ByteString getRawEntryDN()
  {
    return rawEntryDN;
  }
  public ByteString getRawEntryDN();
  /**
@@ -217,13 +56,7 @@
   * @param  rawEntryDN  The raw, unprocessed entry DN as included in the client
   *                     request.
   */
  public final void setRawEntryDN(ByteString rawEntryDN)
  {
    this.rawEntryDN = rawEntryDN;
    entryDN = null;
  }
  public void setRawEntryDN(ByteString rawEntryDN);
  /**
@@ -234,11 +67,7 @@
   * @return  The DN of the entry to compare, or <CODE>null</CODE> if the raw
   *          entry DN has not yet been processed.
   */
  public final DN getEntryDN()
  {
    return entryDN;
  }
  public DN getEntryDN();
  /**
@@ -246,11 +75,7 @@
   *
   * @return  The raw attribute type for this compare operation.
   */
  public final String getRawAttributeType()
  {
    return rawAttributeType;
  }
  public String getRawAttributeType();
  /**
@@ -260,13 +85,7 @@
   * @param  rawAttributeType  The raw attribute type for this compare
   *                           operation.
   */
  public final void setRawAttributeType(String rawAttributeType)
  {
    this.rawAttributeType = rawAttributeType;
    attributeType = null;
  }
  public void setRawAttributeType(String rawAttributeType);
  /**
@@ -276,23 +95,23 @@
   *
   * @return  The attribute type for this compare operation.
   */
  public final AttributeType getAttributeType()
  {
    return attributeType;
  }
  public AttributeType getAttributeType();
  /**
   * Specifies the attribute type for this compare operation.
   *
   * @param attributeType  The attribute type for this compare operation.
   */
  public void setAttributeType(AttributeType attributeType);
  /**
   * Retrieves the assertion value for this compare operation.
   *
   * @return  The assertion value for this compare operation.
   */
  public final ByteString getAssertionValue()
  {
    return assertionValue;
  }
  public ByteString getAssertionValue();
  /**
@@ -301,926 +120,23 @@
   *
   * @param  assertionValue  The assertion value for this compare operation.
   */
  public final void setAssertionValue(ByteString assertionValue)
  {
    this.assertionValue = assertionValue;
  }
  public void setAssertionValue(ByteString assertionValue);
  /**
   * Retrieves the entry to target with the compare operation.  This should not
   * be called by pre-parse plugins.
   * Retrieves the proxied authorization target DN for this compare operation.
   *
   * @return  The entry to target with the compare operation, or
   *          <CODE>null</CODE> if the entry is not yet available.
   * @return  The proxied authorization target DN for this compare operation
   */
  public final Entry getEntryToCompare()
  {
    return entry;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final OperationType getOperationType()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    return OperationType.COMPARE;
  }
  public DN getProxiedAuthorizationDN();
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void disconnectClient(DisconnectReason disconnectReason,
                                     boolean sendNotification, String message,
                                     int messageID)
  {
    // Before calling clientConnection.disconnect, we need to mark this
    // operation as cancelled so that the attempt to cancel it later won't cause
    // an unnecessary delay.
    setCancelResult(CancelResult.CANCELED);
    clientConnection.disconnect(disconnectReason, sendNotification, message,
                                messageID);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final String[][] getRequestLogElements()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    return new String[][]
    {
      new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) },
      new String[] { LOG_ELEMENT_COMPARE_ATTR, rawAttributeType }
    };
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final String[][] getResponseLogElements()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    String resultCode = String.valueOf(getResultCode().getIntValue());
    String errorMessage;
    StringBuilder errorMessageBuffer = getErrorMessage();
    if (errorMessageBuffer == null)
    {
      errorMessage = null;
    }
    else
    {
      errorMessage = errorMessageBuffer.toString();
    }
    String matchedDNStr;
    DN matchedDN = getMatchedDN();
    if (matchedDN == null)
    {
      matchedDNStr = null;
    }
    else
    {
      matchedDNStr = matchedDN.toString();
    }
    String referrals;
    List<String> referralURLs = getReferralURLs();
    if ((referralURLs == null) || referralURLs.isEmpty())
    {
      referrals = null;
    }
    else
    {
      StringBuilder buffer = new StringBuilder();
      Iterator<String> iterator = referralURLs.iterator();
      buffer.append(iterator.next());
      while (iterator.hasNext())
      {
        buffer.append(", ");
        buffer.append(iterator.next());
      }
      referrals = buffer.toString();
    }
    String processingTime =
         String.valueOf(getProcessingTime());
    return new String[][]
    {
      new String[] { LOG_ELEMENT_RESULT_CODE, resultCode },
      new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage },
      new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr },
      new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals },
      new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime }
    };
  }
  /**
   * Retrieves the proxied authorization DN for this operation if proxied
   * authorization has been requested.
   * Specifies the proxied authorization target DN for this compare operation.
   *
   * @return  The proxied authorization DN for this operation if proxied
   *          authorization has been requested, or {@code null} if proxied
   *          authorization has not been requested.
   * @param proxiedAuthorizationDN  The proxied authorization target DN for
   *                                this compare operation
   */
  public DN getProxiedAuthorizationDN()
  {
    return proxiedAuthorizationDN;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final List<Control> getResponseControls()
  {
    return responseControls;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void addResponseControl(Control control)
  {
    responseControls.add(control);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void removeResponseControl(Control control)
  {
    responseControls.remove(control);
  }
  /**
   * Performs the work of actually processing this operation.  This
   * should include all processing for the operation, including
   * invoking plugins, logging messages, performing access control,
   * managing synchronization, and any other work that might need to
   * be done in the course of processing.
   */
  public final void run()
  {
    setResultCode(ResultCode.UNDEFINED);
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
         DirectoryServer.getPluginConfigManager();
    boolean skipPostOperation = false;
    // Start the processing timer.
    setProcessingStartTime();
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      return;
    }
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
compareProcessing:
    {
      // Invoke the pre-parse compare plugins.
      PreParsePluginResult preParseResult =
           pluginConfigManager.invokePreParseComparePlugins(this);
      if (preParseResult.connectionTerminated())
      {
        // There's no point in continuing with anything.  Log the request and
        // result and return.
        setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_PREPARSE_DISCONNECT;
        appendErrorMessage(getMessage(msgID));
        setProcessingStopTime();
        logCompareRequest(this);
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
      else if (preParseResult.sendResponseImmediately())
      {
        skipPostOperation = true;
        logCompareRequest(this);
        break compareProcessing;
      }
      else if (preParseResult.skipCoreProcessing())
      {
        skipPostOperation = false;
        break compareProcessing;
      }
      // Log the compare request message.
      logCompareRequest(this);
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
      // Process the entry DN to convert it from the raw form to the form
      // required for the rest of the compare processing.
      try
      {
        if (entryDN == null)
        {
          entryDN = DN.decode(rawEntryDN);
        }
      }
      catch (DirectoryException de)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, de);
        }
        setResultCode(de.getResultCode());
        appendErrorMessage(de.getErrorMessage());
        skipPostOperation = true;
        break compareProcessing;
      }
      // If the target entry is in the server configuration, then make sure the
      // requester has the CONFIG_READ privilege.
      if (DirectoryServer.getConfigHandler().handlesEntry(entryDN) &&
          (! clientConnection.hasPrivilege(Privilege.CONFIG_READ, this)))
      {
        int msgID = MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES;
        appendErrorMessage(getMessage(msgID));
        setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
        skipPostOperation = true;
        break compareProcessing;
      }
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
      // Grab a read lock on the entry.
      Lock readLock = null;
      for (int i=0; i < 3; i++)
      {
        readLock = LockManager.lockRead(entryDN);
        if (readLock != null)
        {
          break;
        }
      }
      if (readLock == null)
      {
        int    msgID   = MSGID_COMPARE_CANNOT_LOCK_ENTRY;
        String message = getMessage(msgID, String.valueOf(entryDN));
        setResultCode(DirectoryServer.getServerErrorResultCode());
        appendErrorMessage(message);
        skipPostOperation = true;
        break compareProcessing;
      }
      try
      {
        // Get the entry.  If it does not exist, then fail.
        try
        {
          entry = DirectoryServer.getEntry(entryDN);
          if (entry == null)
          {
            setResultCode(ResultCode.NO_SUCH_OBJECT);
            appendErrorMessage(getMessage(MSGID_COMPARE_NO_SUCH_ENTRY,
                                          String.valueOf(entryDN)));
            // See if one of the entry's ancestors exists.
            DN parentDN = entryDN.getParentDNInSuffix();
            while (parentDN != null)
            {
              try
              {
                if (DirectoryServer.entryExists(parentDN))
                {
                  setMatchedDN(parentDN);
                  break;
                }
              }
              catch (Exception e)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
                }
                break;
              }
              parentDN = parentDN.getParentDNInSuffix();
            }
            break compareProcessing;
          }
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResultCode(de.getResultCode());
          appendErrorMessage(de.getErrorMessage());
          break compareProcessing;
        }
        // Check to see if there are any controls in the request.  If so, then
        // see if there is any special processing required.
        List<Control> requestControls = getRequestControls();
        if ((requestControls != null) && (! requestControls.isEmpty()))
        {
          for (int i=0; i < requestControls.size(); i++)
          {
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
              if (c instanceof LDAPAssertionRequestControl)
              {
                assertControl = (LDAPAssertionRequestControl) c;
              }
              else
              {
                try
                {
                  assertControl = LDAPAssertionRequestControl.decodeControl(c);
                  requestControls.set(i, assertControl);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  setResultCode(ResultCode.valueOf(le.getResultCode()));
                  appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              try
              {
                // FIXME -- We need to determine whether the current user has
                //          permission to make this determination.
                SearchFilter filter = assertControl.getSearchFilter();
                if (! filter.matchesEntry(entry))
                {
                  setResultCode(ResultCode.ASSERTION_FAILED);
                  appendErrorMessage(getMessage(MSGID_COMPARE_ASSERTION_FAILED,
                                                String.valueOf(entryDN)));
                  break compareProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(ResultCode.PROTOCOL_ERROR);
                int msgID = MSGID_COMPARE_CANNOT_PROCESS_ASSERTION_FILTER;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              de.getErrorMessage()));
                break compareProcessing;
              }
            }
            else if (oid.equals(OID_PROXIED_AUTH_V1))
            {
              // The requester must have the PROXIED_AUTH privilige in order to
              // be able to use this control.
              if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
                proxyControl = (ProxiedAuthV1Control) c;
              }
              else
              {
                try
                {
                  proxyControl = ProxiedAuthV1Control.decodeControl(c);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  setResultCode(ResultCode.valueOf(le.getResultCode()));
                  appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(this,
                                                 authorizationEntry) == false) {
                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                proxiedAuthorizationDN = DN.nullDN();
              }
              else
              {
                proxiedAuthorizationDN = authorizationEntry.getDN();
              }
            }
            else if (oid.equals(OID_PROXIED_AUTH_V2))
            {
              // The requester must have the PROXIED_AUTH privilige in order to
              // be able to use this control.
              if (! clientConnection.hasPrivilege(Privilege.PROXIED_AUTH, this))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                appendErrorMessage(getMessage(msgID));
                setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
                proxyControl = (ProxiedAuthV2Control) c;
              }
              else
              {
                try
                {
                  proxyControl = ProxiedAuthV2Control.decodeControl(c);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  setResultCode(ResultCode.valueOf(le.getResultCode()));
                  appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                setResultCode(de.getResultCode());
                appendErrorMessage(de.getErrorMessage());
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(this,
                                                 authorizationEntry) == false) {
                setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                proxiedAuthorizationDN = DN.nullDN();
              }
              else
              {
                proxiedAuthorizationDN = authorizationEntry.getDN();
              }
            }
            // NYI -- Add support for additional controls.
            else if (c.isCritical())
            {
              Backend backend = DirectoryServer.getBackend(entryDN);
              if ((backend == null) || (! backend.supportsControl(oid)))
              {
                setResultCode(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
                int msgID = MSGID_COMPARE_UNSUPPORTED_CRITICAL_CONTROL;
                appendErrorMessage(getMessage(msgID, String.valueOf(entryDN),
                                              oid));
                break compareProcessing;
              }
            }
          }
        }
        // Check to see if the client has permission to perform the
        // compare.
        // FIXME: for now assume that this will check all permission
        // pertinent to the operation. This includes proxy authorization
        // and any other controls specified.
        // FIXME: earlier checks to see if the entry already exists may
        // have already exposed sensitive information to the client.
        if (AccessControlConfigManager.getInstance()
            .getAccessControlHandler().isAllowed(this) == false) {
          setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
          int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
          appendErrorMessage(getMessage(msgID, String.valueOf(entryDN)));
          skipPostOperation = true;
          break compareProcessing;
        }
        // Check for and handle a request to cancel this operation.
        if (cancelRequest != null)
        {
          indicateCancelled(cancelRequest);
          setProcessingStopTime();
          logCompareResponse(this);
          pluginConfigManager.invokePostResponseComparePlugins(this);
          return;
        }
        // Invoke the pre-operation compare plugins.
        PreOperationPluginResult preOpResult =
             pluginConfigManager.invokePreOperationComparePlugins(this);
        if (preOpResult.connectionTerminated())
        {
          // There's no point in continuing with anything.  Log the request and
          // result and return.
          setResultCode(ResultCode.CANCELED);
          int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
          appendErrorMessage(getMessage(msgID));
          setProcessingStopTime();
          logCompareResponse(this);
          pluginConfigManager.invokePostResponseComparePlugins(this);
          return;
        }
        else if (preOpResult.sendResponseImmediately())
        {
          skipPostOperation = true;
          break compareProcessing;
        }
        else if (preOpResult.skipCoreProcessing())
        {
          skipPostOperation = false;
          break compareProcessing;
        }
        // Get the base attribute type and set of options.
        String          baseName;
        HashSet<String> options;
        int             semicolonPos = rawAttributeType.indexOf(';');
        if (semicolonPos > 0)
        {
          baseName = toLowerCase(rawAttributeType.substring(0, semicolonPos));
          options = new HashSet<String>();
          int nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
          while (nextPos > 0)
          {
            options.add(rawAttributeType.substring(semicolonPos+1, nextPos));
            semicolonPos = nextPos;
            nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
          }
          options.add(rawAttributeType.substring(semicolonPos+1));
        }
        else
        {
          baseName = toLowerCase(rawAttributeType);
          options  = null;
        }
        // Actually perform the compare operation.
        List<Attribute> attrList = null;
        if (attributeType == null)
        {
          attributeType = DirectoryServer.getAttributeType(baseName);
        }
        if (attributeType == null)
        {
          attrList = entry.getAttribute(baseName, options);
          attributeType = DirectoryServer.getDefaultAttributeType(baseName);
        }
        else
        {
          attrList = entry.getAttribute(attributeType, options);
        }
        if ((attrList == null) || attrList.isEmpty())
        {
          setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
          if (options == null)
          {
            appendErrorMessage(getMessage(MSGID_COMPARE_OP_NO_SUCH_ATTR,
                                          String.valueOf(entryDN), baseName));
          }
          else
          {
            appendErrorMessage(getMessage(
                                    MSGID_COMPARE_OP_NO_SUCH_ATTR_WITH_OPTIONS,
                                    String.valueOf(entryDN), baseName));
          }
        }
        else
        {
          AttributeValue value = new AttributeValue(attributeType,
                                                    assertionValue);
          boolean matchFound = false;
          for (Attribute a : attrList)
          {
            if (a.hasValue(value))
            {
              matchFound = true;
              break;
            }
          }
          if (matchFound)
          {
            setResultCode(ResultCode.COMPARE_TRUE);
          }
          else
          {
            setResultCode(ResultCode.COMPARE_FALSE);
          }
        }
      }
      finally
      {
        LockManager.unlock(entryDN, readLock);
      }
    }
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      logCompareResponse(this);
      pluginConfigManager.invokePostResponseComparePlugins(this);
      return;
    }
    // Invoke the post-operation compare plugins.
    if (! skipPostOperation)
    {
      PostOperationPluginResult postOperationResult =
           pluginConfigManager.invokePostOperationComparePlugins(this);
      if (postOperationResult.connectionTerminated())
      {
        setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_POSTOP_DISCONNECT;
        appendErrorMessage(getMessage(msgID));
        setProcessingStopTime();
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
    }
    // Indicate that it is now too late to attempt to cancel the operation.
    setCancelResult(CancelResult.TOO_LATE);
    // Stop the processing timer.
    setProcessingStopTime();
    // Send the compare response to the client.
    clientConnection.sendResponse(this);
    // Log the compare response message.
    logCompareResponse(this);
    // Invoke the post-response compare plugins.
    pluginConfigManager.invokePostResponseComparePlugins(this);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final CancelResult cancel(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    CancelResult cancelResult = getCancelResult();
    long stopWaitingTime = System.currentTimeMillis() + 5000;
    while ((cancelResult == null) &&
           (System.currentTimeMillis() < stopWaitingTime))
    {
      try
      {
        Thread.sleep(50);
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
      cancelResult = getCancelResult();
    }
    if (cancelResult == null)
    {
      // This can happen in some rare cases (e.g., if a client disconnects and
      // there is still a lot of data to send to that client), and in this case
      // we'll prevent the cancel thread from blocking for a long period of
      // time.
      cancelResult = CancelResult.CANNOT_CANCEL;
    }
    return cancelResult;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final CancelRequest getCancelRequest()
  {
    return cancelRequest;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean setCancelRequest(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    buffer.append("CompareOperation(connID=");
    buffer.append(clientConnection.getConnectionID());
    buffer.append(", opID=");
    buffer.append(operationID);
    buffer.append(", dn=");
    buffer.append(rawEntryDN);
    buffer.append(", attr=");
    buffer.append(rawAttributeType);
    buffer.append(")");
  }
  public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN);
}
opendj-sdk/opends/src/server/org/opends/server/core/CompareOperationBasis.java
New file
@@ -0,0 +1,720 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import static org.opends.server.core.CoreConstants.*;
import static org.opends.server.loggers.AccessLogger.logCompareRequest;
import static org.opends.server.loggers.AccessLogger.logCompareResponse;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.PreParsePluginResult;
import org.opends.server.loggers.debug.DebugLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.protocols.asn1.ASN1OctetString;
import org.opends.server.types.AbstractOperation;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ByteString;
import org.opends.server.types.CancelRequest;
import org.opends.server.types.CancelResult;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.Entry;
import org.opends.server.types.Operation;
import org.opends.server.types.OperationType;
import org.opends.server.types.ResultCode;
import org.opends.server.types.operation.PostResponseCompareOperation;
import org.opends.server.types.operation.PreParseCompareOperation;
import org.opends.server.workflowelement.localbackend.
       LocalBackendCompareOperation;
/**
 * This class defines an operation that may be used to determine whether a
 * specified entry in the Directory Server contains a given attribute-value
 * pair.
 */
public class CompareOperationBasis
             extends AbstractOperation
             implements PreParseCompareOperation, CompareOperation,
                        Runnable, PostResponseCompareOperation
{
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = DebugLogger.getTracer();
  // The attribute type for this compare operation.
  private AttributeType attributeType;
  // The assertion value for the compare operation.
  private ByteString assertionValue;
  // The raw, unprocessed entry DN as included in the client request.
  private ByteString rawEntryDN;
  // The cancel request that has been issued for this compare operation.
  private CancelRequest cancelRequest;
  // The DN of the entry for the compare operation.
  private DN entryDN;
  // The proxied authorization target DN for this operation.
  private DN proxiedAuthorizationDN;
  // The set of response controls for this compare operation.
  private List<Control> responseControls;
  // The attribute type for the compare operation.
  private String rawAttributeType;
  /**
   * Creates a new compare operation with the provided information.
   *
   * @param  clientConnection  The client connection with which this operation
   *                           is associated.
   * @param  operationID       The operation ID for this operation.
   * @param  messageID         The message ID of the request with which this
   *                           operation is associated.
   * @param  requestControls   The set of controls included in the request.
   * @param  rawEntryDN        The raw, unprocessed entry DN as provided in the
   *                           client request.  This may or may not be a valid
   *                           DN as no validation will have been performed yet.
   * @param  rawAttributeType  The raw attribute type for the compare operation.
   * @param  assertionValue    The assertion value for the compare operation.
   */
  public CompareOperationBasis(
                          ClientConnection clientConnection, long operationID,
                          int messageID, List<Control> requestControls,
                          ByteString rawEntryDN, String rawAttributeType,
                          ByteString assertionValue)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.rawEntryDN       = rawEntryDN;
    this.rawAttributeType = rawAttributeType;
    this.assertionValue   = assertionValue;
    responseControls       = new ArrayList<Control>();
    entryDN                = null;
    attributeType          = null;
    cancelRequest          = null;
    proxiedAuthorizationDN = null;
  }
  /**
   * Creates a new compare operation with the provided information.
   *
   * @param  clientConnection  The client connection with which this operation
   *                           is associated.
   * @param  operationID       The operation ID for this operation.
   * @param  messageID         The message ID of the request with which this
   *                           operation is associated.
   * @param  requestControls   The set of controls included in the request.
   * @param  entryDN           The entry DN for this compare operation.
   * @param  attributeType     The attribute type for this compare operation.
   * @param  assertionValue    The assertion value for the compare operation.
   */
  public CompareOperationBasis(
                          ClientConnection clientConnection, long operationID,
                          int messageID, List<Control> requestControls,
                          DN entryDN, AttributeType attributeType,
                          ByteString assertionValue)
  {
    super(clientConnection, operationID, messageID, requestControls);
    this.entryDN        = entryDN;
    this.attributeType  = attributeType;
    this.assertionValue = assertionValue;
    responseControls       = new ArrayList<Control>();
    rawEntryDN             = new ASN1OctetString(entryDN.toString());
    rawAttributeType       = attributeType.getNameOrOID();
    cancelRequest          = null;
    proxiedAuthorizationDN = null;
  }
  /**
   * {@inheritDoc}
   */
  public final ByteString getRawEntryDN()
  {
    return rawEntryDN;
  }
  /**
   * {@inheritDoc}
   */
  public final void setRawEntryDN(ByteString rawEntryDN)
  {
    this.rawEntryDN = rawEntryDN;
    entryDN = null;
  }
  /**
   * {@inheritDoc}
   */
  public final DN getEntryDN()
  {
    return entryDN;
  }
  /**
   * {@inheritDoc}
   */
  public final String getRawAttributeType()
  {
    return rawAttributeType;
  }
  /**
   * {@inheritDoc}
   */
  public final void setRawAttributeType(String rawAttributeType)
  {
    this.rawAttributeType = rawAttributeType;
    attributeType = null;
  }
  /**
   * {@inheritDoc}
   */
  public final AttributeType getAttributeType()
  {
    return attributeType;
  }
  /**
   * {@inheritDoc}
   */
  public void setAttributeType(AttributeType attributeType)
  {
    this.attributeType = attributeType;
  }
  /**
   * {@inheritDoc}
   */
  public final ByteString getAssertionValue()
  {
    return assertionValue;
  }
  /**
   * {@inheritDoc}
   */
  public final void setAssertionValue(ByteString assertionValue)
  {
    this.assertionValue = assertionValue;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final OperationType getOperationType()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    return OperationType.COMPARE;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void disconnectClient(DisconnectReason disconnectReason,
                                     boolean sendNotification, String message,
                                     int messageID)
  {
    // Before calling clientConnection.disconnect, we need to mark this
    // operation as cancelled so that the attempt to cancel it later won't cause
    // an unnecessary delay.
    setCancelResult(CancelResult.CANCELED);
    clientConnection.disconnect(disconnectReason, sendNotification, message,
                                messageID);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final String[][] getRequestLogElements()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    return new String[][]
    {
      new String[] { LOG_ELEMENT_ENTRY_DN, String.valueOf(rawEntryDN) },
      new String[] { LOG_ELEMENT_COMPARE_ATTR, rawAttributeType }
    };
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final String[][] getResponseLogElements()
  {
    // Note that no debugging will be done in this method because it is a likely
    // candidate for being called by the logging subsystem.
    String resultCode = String.valueOf(getResultCode().getIntValue());
    String errorMessage;
    StringBuilder errorMessageBuffer = getErrorMessage();
    if (errorMessageBuffer == null)
    {
      errorMessage = null;
    }
    else
    {
      errorMessage = errorMessageBuffer.toString();
    }
    String matchedDNStr;
    DN matchedDN = getMatchedDN();
    if (matchedDN == null)
    {
      matchedDNStr = null;
    }
    else
    {
      matchedDNStr = matchedDN.toString();
    }
    String referrals;
    List<String> referralURLs = getReferralURLs();
    if ((referralURLs == null) || referralURLs.isEmpty())
    {
      referrals = null;
    }
    else
    {
      StringBuilder buffer = new StringBuilder();
      Iterator<String> iterator = referralURLs.iterator();
      buffer.append(iterator.next());
      while (iterator.hasNext())
      {
        buffer.append(", ");
        buffer.append(iterator.next());
      }
      referrals = buffer.toString();
    }
    String processingTime =
         String.valueOf(getProcessingTime());
    return new String[][]
    {
      new String[] { LOG_ELEMENT_RESULT_CODE, resultCode },
      new String[] { LOG_ELEMENT_ERROR_MESSAGE, errorMessage },
      new String[] { LOG_ELEMENT_MATCHED_DN, matchedDNStr },
      new String[] { LOG_ELEMENT_REFERRAL_URLS, referrals },
      new String[] { LOG_ELEMENT_PROCESSING_TIME, processingTime }
    };
  }
  /**
   * Retrieves the proxied authorization DN for this operation if proxied
   * authorization has been requested.
   *
   * @return  The proxied authorization DN for this operation if proxied
   *          authorization has been requested, or {@code null} if proxied
   *          authorization has not been requested.
   */
  public DN getProxiedAuthorizationDN()
  {
    return proxiedAuthorizationDN;
  }
  /**
   * {@inheritDoc}
   */
  public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN)
  {
    this.proxiedAuthorizationDN = proxiedAuthorizationDN;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final List<Control> getResponseControls()
  {
    return responseControls;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void addResponseControl(Control control)
  {
    responseControls.add(control);
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void removeResponseControl(Control control)
  {
    responseControls.remove(control);
  }
  /**
   * Performs the work of actually processing this operation.  This
   * should include all processing for the operation, including
   * invoking plugins, logging messages, performing access control,
   * managing synchronization, and any other work that might need to
   * be done in the course of processing.
   */
  public final void run()
  {
    setResultCode(ResultCode.UNDEFINED);
    // Start the processing timer.
    setProcessingStartTime();
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      return;
    }
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
         DirectoryServer.getPluginConfigManager();
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
    boolean workflowExecuted = false;
compareProcessing:
    {
      // Invoke the pre-parse compare plugins.
      PreParsePluginResult preParseResult =
           pluginConfigManager.invokePreParseComparePlugins(this);
      if (preParseResult.connectionTerminated())
      {
        // There's no point in continuing with anything.  Log the request and
        // result and return.
        setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_PREPARSE_DISCONNECT;
        appendErrorMessage(getMessage(msgID));
        setProcessingStopTime();
        logCompareRequest(this);
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
      else if (preParseResult.sendResponseImmediately())
      {
        logCompareRequest(this);
        break compareProcessing;
      }
      else if (preParseResult.skipCoreProcessing())
      {
        break compareProcessing;
      }
      // Log the compare request message.
      logCompareRequest(this);
      // Check for and handle a request to cancel this operation.
      if (cancelRequest != null)
      {
        indicateCancelled(cancelRequest);
        setProcessingStopTime();
        logCompareResponse(this);
        pluginConfigManager.invokePostResponseComparePlugins(this);
        return;
      }
      // Process the entry DN to convert it from the raw form to the form
      // required for the rest of the compare processing.
      try
      {
        if (entryDN == null)
        {
          entryDN = DN.decode(rawEntryDN);
        }
      }
      catch (DirectoryException de)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, de);
        }
        setResultCode(de.getResultCode());
        appendErrorMessage(de.getErrorMessage());
        break compareProcessing;
      }
      // Retrieve the network group registered with the client connection
      // and get a workflow to process the operation.
      NetworkGroup ng = getClientConnection().getNetworkGroup();
      Workflow workflow = ng.getWorkflowCandidate(entryDN);
      if (workflow == null)
      {
        // We have found no workflow for the requested base DN, just return
        // a no such entry result code and stop the processing.
        updateOperationErrMsgAndResCode();
        break compareProcessing;
      }
      workflow.execute(this);
      workflowExecuted = true;
    }
    // Check for and handle a request to cancel this operation.
    if (cancelRequest != null)
    {
      indicateCancelled(cancelRequest);
      setProcessingStopTime();
      logCompareResponse(this);
      pluginConfigManager.invokePostResponseComparePlugins(this);
      return;
    }
    // Indicate that it is now too late to attempt to cancel the operation.
    setCancelResult(CancelResult.TOO_LATE);
    // Stop the processing timer.
    setProcessingStopTime();
    // Send the compare response to the client unless the operation result
    // code is CANCELED
    if (getResultCode() != ResultCode.CANCELED)
    {
      clientConnection.sendResponse(this);
    }
    // Log the compare response message.
    logCompareResponse(this);
    // Invoke the post-response compare plugins.
    if (workflowExecuted)
    {
      List localOperations =
        (List)getAttachment(Operation.LOCALBACKENDOPERATIONS);
      if (localOperations != null)
      {
        for (Object localOp : localOperations)
        {
          LocalBackendCompareOperation localOperation =
            (LocalBackendCompareOperation)localOp;
          pluginConfigManager.invokePostResponseComparePlugins(localOperation);
        }
      }
    }
    else
    {
      pluginConfigManager.invokePostResponseComparePlugins(this);
    }
  }
  /**
   * Updates the error message and the result code of the operation.
   *
   * This method is called because no workflow was found to process
   * the operation.
   */
  private void updateOperationErrMsgAndResCode()
  {
    setResultCode(ResultCode.NO_SUCH_OBJECT);
    appendErrorMessage(
      getMessage(MSGID_COMPARE_NO_SUCH_ENTRY, String.valueOf(getEntryDN())));
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final CancelResult cancel(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    CancelResult cancelResult = getCancelResult();
    long stopWaitingTime = System.currentTimeMillis() + 5000;
    while ((cancelResult == null) &&
           (System.currentTimeMillis() < stopWaitingTime))
    {
      try
      {
        Thread.sleep(50);
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
      cancelResult = getCancelResult();
    }
    if (cancelResult == null)
    {
      // This can happen in some rare cases (e.g., if a client disconnects and
      // there is still a lot of data to send to that client), and in this case
      // we'll prevent the cancel thread from blocking for a long period of
      // time.
      cancelResult = CancelResult.CANNOT_CANCEL;
    }
    return cancelResult;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final CancelRequest getCancelRequest()
  {
    return cancelRequest;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public boolean setCancelRequest(CancelRequest cancelRequest)
  {
    this.cancelRequest = cancelRequest;
    return true;
  }
  /**
   * {@inheritDoc}
   */
  @Override()
  public final void toString(StringBuilder buffer)
  {
    buffer.append("CompareOperation(connID=");
    buffer.append(clientConnection.getConnectionID());
    buffer.append(", opID=");
    buffer.append(operationID);
    buffer.append(", dn=");
    buffer.append(rawEntryDN);
    buffer.append(", attr=");
    buffer.append(rawAttributeType);
    buffer.append(")");
  }
  /**
   * {@inheritDoc}
   *
   * This method always returns null.
   */
  public Entry getEntryToCompare()
  {
    return null;
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/CompareOperationWrapper.java
New file
@@ -0,0 +1,158 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
/**
 * This abstract class wraps/decorates a given compare operation.
 * This class will be extended by sub-classes to enhance the
 * functionnality of the CompareOperationBasis.
 */
public abstract class CompareOperationWrapper
  extends OperationWrapper
  implements CompareOperation
{
  // The wrapped operation
  private CompareOperation compare;
  /**
   * Creates a new compare operation based on the provided compare operation.
   *
   * @param compare The compare operation to wrap
   */
  public CompareOperationWrapper(CompareOperation compare)
  {
    super(compare);
    this.compare = compare;
  }
  /**
   * {@inheritDoc}
   */
  public ByteString getRawEntryDN()
  {
    return compare.getRawEntryDN();
  }
  /**
   * {@inheritDoc}
   */
  public void setRawEntryDN(ByteString rawEntryDN)
  {
    compare.setRawEntryDN(rawEntryDN);
  }
  /**
   * {@inheritDoc}
   */
  public DN getEntryDN()
  {
    return compare.getEntryDN();
  }
  /**
   * {@inheritDoc}
   */
  public String getRawAttributeType()
  {
    return compare.getRawAttributeType();
  }
  /**
   * {@inheritDoc}
   */
  public void setRawAttributeType(String rawAttributeType)
  {
    compare.setRawAttributeType(rawAttributeType);
  }
  /**
   * {@inheritDoc}
   */
  public AttributeType getAttributeType()
  {
    return compare.getAttributeType();
  }
  /**
   * {@inheritDoc}
   */
  public void setAttributeType(AttributeType attributeType)
  {
    compare.setAttributeType(attributeType);
  }
  /**
   * {@inheritDoc}
   */
  public ByteString getAssertionValue()
  {
    return compare.getAssertionValue();
  }
  /**
   * {@inheritDoc}
   */
  public void setAssertionValue(ByteString assertionValue)
  {
    compare.setAssertionValue(assertionValue);
  }
  /**
   * {@inheritDoc}
   */
  public DN getProxiedAuthorizationDN()
  {
    return compare.getProxiedAuthorizationDN();
  }
  /**
   * {@inheritDoc}
   */
  public void setProxiedAuthorizationDN(DN proxiedAuthorizationDN)
  {
    compare.setProxiedAuthorizationDN(proxiedAuthorizationDN);
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/DefaultAccessControlHandler.java
@@ -116,7 +116,7 @@
   * {@inheritDoc}
   */
  @Override
  public boolean isAllowed(CompareOperation compareOperation)
  public boolean isAllowed(LocalBackendCompareOperation compareOperation)
  {
    return true;
  }
opendj-sdk/opends/src/server/org/opends/server/core/OperationWrapper.java
New file
@@ -0,0 +1,511 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import java.util.List;
import java.util.Map;
import org.opends.server.api.ClientConnection;
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.DisconnectReason;
import org.opends.server.types.Entry;
import org.opends.server.types.Operation;
import org.opends.server.types.OperationType;
import org.opends.server.types.ResultCode;
/**
 * This abstract class is a generic operation wrapper intended to be
 * subclassed by a specific operation wrapper.
 */
public class OperationWrapper implements Operation
{
  // The wrapped operation.
  private Operation operation;
  /**
   * Creates a new generic operation wrapper.
   *
   * @param operation  the generic operation to wrap
   */
  public OperationWrapper(Operation operation)
  {
    this.operation = operation;
  }
  /**
   * {@inheritDoc}
   */
  public void addRequestControl(Control control)
  {
    operation.addRequestControl(control);
  }
  /**
   * {@inheritDoc}
   */
  public void addResponseControl(Control control)
  {
    operation.addResponseControl(control);
  }
  /**
   * {@inheritDoc}
   */
  public void appendAdditionalLogMessage(String message)
  {
    operation.appendAdditionalLogMessage(message);
  }
  /**
   * {@inheritDoc}
   */
  public void appendErrorMessage(String message)
  {
    operation.appendErrorMessage(message);
  }
  /**
   * {@inheritDoc}
   */
  public CancelResult cancel(CancelRequest cancelRequest)
  {
    return operation.cancel(cancelRequest);
  }
  /**
   * {@inheritDoc}
   */
  public void disconnectClient(
    DisconnectReason disconnectReason,
    boolean sendNotification,
    String message,
    int messageID)
  {
    operation.disconnectClient(
      disconnectReason, sendNotification, message, messageID);
  }
  /**
   * {@inheritDoc}
   */
  public boolean dontSynchronize()
  {
    return operation.dontSynchronize();
  }
  /**
   * {@inheritDoc}
   */
  public StringBuilder getAdditionalLogMessage()
  {
    return operation.getAdditionalLogMessage();
  }
  /**
   * {@inheritDoc}
   */
  public Object getAttachment(String name)
  {
    return operation.getAttachment(name);
  }
  /**
   * {@inheritDoc}
   */
  public Map<String, Object> getAttachments()
  {
    return operation.getAttachments();
  }
  /**
   * {@inheritDoc}
   */
  public DN getAuthorizationDN()
  {
    return operation.getAuthorizationDN();
  }
  /**
   * {@inheritDoc}
   */
  public Entry getAuthorizationEntry()
  {
    return operation.getAuthorizationEntry();
  }
  /**
   * {@inheritDoc}
   */
  public CancelRequest getCancelRequest()
  {
    return operation.getCancelRequest();
  }
  /**
   * {@inheritDoc}
   */
  public CancelResult getCancelResult()
  {
    return operation.getCancelResult();
  }
  /**
   * {@inheritDoc}
   */
  public ClientConnection getClientConnection()
  {
    return operation.getClientConnection();
  }
  /**
   * {@inheritDoc}
   */
  public String[][] getCommonLogElements()
  {
    return operation.getCommonLogElements();
  }
  /**
   * {@inheritDoc}
   */
  public long getConnectionID()
  {
    return operation.getConnectionID();
  }
  /**
   * {@inheritDoc}
   */
  public StringBuilder getErrorMessage()
  {
    return operation.getErrorMessage();
  }
  /**
   * {@inheritDoc}
   */
  public DN getMatchedDN()
  {
    return operation.getMatchedDN();
  }
  /**
   * {@inheritDoc}
   */
  public int getMessageID()
  {
    return operation.getMessageID();
  }
  /**
   * {@inheritDoc}
   */
  public long getOperationID()
  {
    return operation.getOperationID();
  }
  /**
   * {@inheritDoc}
   */
  public OperationType getOperationType()
  {
    return operation.getOperationType();
  }
  /**
   * {@inheritDoc}
   */
  public long getProcessingStartTime()
  {
    return operation.getProcessingStartTime();
  }
  /**
   * {@inheritDoc}
   */
  public long getProcessingStopTime()
  {
    return operation.getProcessingStopTime();
  }
  /**
   * {@inheritDoc}
   */
  public long getProcessingTime()
  {
    return operation.getProcessingTime();
  }
  /**
   * {@inheritDoc}
   */
  public List<String> getReferralURLs()
  {
    return operation.getReferralURLs();
  }
  /**
   * {@inheritDoc}
   */
  public List<Control> getRequestControls()
  {
    return operation.getRequestControls();
  }
  /**
   * {@inheritDoc}
   */
  public String[][] getRequestLogElements()
  {
    return operation.getRequestLogElements();
  }
  /**
   * {@inheritDoc}
   */
  public List<Control> getResponseControls()
  {
    return operation.getResponseControls();
  }
  /**
   * {@inheritDoc}
   */
  public String[][] getResponseLogElements()
  {
    return operation.getResponseLogElements();
  }
  /**
   * {@inheritDoc}
   */
  public ResultCode getResultCode()
  {
    return operation.getResultCode();
  }
  /**
   * {@inheritDoc}
   */
  public void indicateCancelled(CancelRequest cancelRequest)
  {
    operation.indicateCancelled(cancelRequest);
  }
  /**
   * {@inheritDoc}
   */
  public boolean isInternalOperation()
  {
    return operation.isInternalOperation();
  }
  /**
   * {@inheritDoc}
   */
  public boolean isSynchronizationOperation()
  {
    return operation.isSynchronizationOperation();
  }
  /**
   * {@inheritDoc}
   */
  public void operationCompleted()
  {
    operation.operationCompleted();
  }
  /**
   * {@inheritDoc}
   */
  public Object removeAttachment(String name)
  {
    return operation.removeAttachment(name);
  }
  /**
   * {@inheritDoc}
   */
  public void removeRequestControl(Control control)
  {
    operation.removeRequestControl(control);
  }
  /**
   * {@inheritDoc}
   */
  public void removeResponseControl(Control control)
  {
    operation.removeResponseControl(control);
  }
  /**
   * {@inheritDoc}
   */
  public void setAdditionalLogMessage(StringBuilder additionalLogMessage)
  {
    operation.setAdditionalLogMessage(additionalLogMessage);
  }
  /**
   * {@inheritDoc}
   */
  public Object setAttachment(String name, Object value)
  {
    return operation.setAttachment(name, value);
  }
  /**
   * {@inheritDoc}
   */
  public void setAttachments(Map<String, Object> attachments)
  {
    operation.setAttachments(attachments);
  }
  /**
   * {@inheritDoc}
   */
  public void setAuthorizationEntry(Entry authorizationEntry)
  {
    operation.setAuthorizationEntry(authorizationEntry);
  }
  /**
   * {@inheritDoc}
   */
  public boolean setCancelRequest(CancelRequest cancelRequest)
  {
    return operation.setCancelRequest(cancelRequest);
  }
  /**
   * {@inheritDoc}
   */
  public void setCancelResult(CancelResult cancelResult)
  {
    operation.setCancelResult(cancelResult);
  }
  /**
   * {@inheritDoc}
   */
  public void setDontSynchronize(boolean dontSynchronize)
  {
    operation.setDontSynchronize(dontSynchronize);
  }
  /**
   * {@inheritDoc}
   */
  public void setErrorMessage(StringBuilder errorMessage)
  {
    operation.setErrorMessage(errorMessage);
  }
  /**
   * {@inheritDoc}
   */
  public void setInternalOperation(boolean isInternalOperation)
  {
    operation.setInternalOperation(isInternalOperation);
  }
  /**
   * {@inheritDoc}
   */
  public void setMatchedDN(DN matchedDN)
  {
    operation.setMatchedDN(matchedDN);
  }
  /**
   * {@inheritDoc}
   */
  public void setProcessingStartTime()
  {
    operation.setProcessingStartTime();
  }
  /**
   * {@inheritDoc}
   */
  public void setProcessingStopTime()
  {
    operation.setProcessingStopTime();
  }
  /**
   * {@inheritDoc}
   */
  public void setReferralURLs(List<String> referralURLs)
  {
    operation.setReferralURLs(referralURLs);
  }
  /**
   * {@inheritDoc}
   */
  public void setResponseData(DirectoryException directoryException)
  {
    operation.setResponseData(directoryException);
  }
  /**
   * {@inheritDoc}
   */
  public void setResultCode(ResultCode resultCode)
  {
    operation.setResultCode(resultCode);
  }
  /**
   * {@inheritDoc}
   */
  public void setSynchronizationOperation(boolean isSynchronizationOperation)
  {
    operation.setSynchronizationOperation(isSynchronizationOperation);
  }
  /**
   * {@inheritDoc}
   */
  public void toString(StringBuilder buffer)
  {
    operation.toString(buffer);
  }
}
opendj-sdk/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -82,21 +82,25 @@
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.operation.PostOperationAddOperation;
import org.opends.server.types.operation.PostOperationBindOperation;
import org.opends.server.types.operation.PostOperationCompareOperation;
import org.opends.server.types.operation.PostOperationDeleteOperation;
import org.opends.server.types.operation.PostOperationModifyOperation;
import org.opends.server.types.operation.PostOperationSearchOperation;
import org.opends.server.types.operation.PostResponseAddOperation;
import org.opends.server.types.operation.PostResponseBindOperation;
import org.opends.server.types.operation.PostResponseCompareOperation;
import org.opends.server.types.operation.PostResponseDeleteOperation;
import org.opends.server.types.operation.PostResponseModifyOperation;
import org.opends.server.types.operation.PostResponseSearchOperation;
import org.opends.server.types.operation.PreOperationAddOperation;
import org.opends.server.types.operation.PreOperationBindOperation;
import org.opends.server.types.operation.PreOperationCompareOperation;
import org.opends.server.types.operation.PreOperationDeleteOperation;
import org.opends.server.types.operation.PreOperationModifyOperation;
import org.opends.server.types.operation.PreOperationSearchOperation;
import org.opends.server.types.operation.PreParseAddOperation;
import org.opends.server.types.operation.PreParseBindOperation;
import org.opends.server.types.operation.PreParseCompareOperation;
import org.opends.server.types.operation.PreParseDeleteOperation;
import org.opends.server.types.operation.PreParseModifyOperation;
import org.opends.server.types.operation.PreParseSearchOperation;
@@ -1971,7 +1975,7 @@
   * @return  The result of processing the pre-parse compare plugins.
   */
  public PreParsePluginResult invokePreParseComparePlugins(
                                   CompareOperation compareOperation)
    PreParseCompareOperation compareOperation)
  {
    PreParsePluginResult result = null;
@@ -2705,7 +2709,7 @@
   * @return  The result of processing the pre-operation compare plugins.
   */
  public PreOperationPluginResult invokePreOperationComparePlugins(
                                       CompareOperation compareOperation)
     PreOperationCompareOperation compareOperation)
  {
    PreOperationPluginResult result = null;
@@ -3439,7 +3443,7 @@
   * @return  The result of processing the post-operation compare plugins.
   */
  public PostOperationPluginResult invokePostOperationComparePlugins(
                                        CompareOperation compareOperation)
      PostOperationCompareOperation compareOperation)
  {
    PostOperationPluginResult result = null;
@@ -4161,7 +4165,7 @@
   * @return  The result of processing the post-response compare plugins.
   */
  public PostResponsePluginResult invokePostResponseComparePlugins(
                                       CompareOperation compareOperation)
      PostResponseCompareOperation compareOperation)
  {
    PostResponsePluginResult result = null;
opendj-sdk/opends/src/server/org/opends/server/protocols/internal/InternalClientConnection.java
@@ -954,8 +954,8 @@
                                         String attributeType,
                                         ByteString assertionValue)
  {
    CompareOperation compareOperation =
         new CompareOperation(this, nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(this, nextOperationID(),
                              nextMessageID(),
                              new ArrayList<Control>(0), rawEntryDN,
                              attributeType, assertionValue);
@@ -985,8 +985,8 @@
                                         AttributeType attributeType,
                                         ByteString assertionValue)
  {
    CompareOperation compareOperation =
         new CompareOperation(this, nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(this, nextOperationID(),
                              nextMessageID(),
                              new ArrayList<Control>(0), entryDN,
                              attributeType, assertionValue);
opendj-sdk/opends/src/server/org/opends/server/protocols/jmx/JmxClientConnection.java
@@ -589,8 +589,8 @@
                                        String attributeType,
                                        ASN1OctetString assertionValue)
  {
    CompareOperation compareOperation =
         new CompareOperation(this, nextOperationID(), nextMessageID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(this, nextOperationID(), nextMessageID(),
                              new ArrayList<Control>(0), rawEntryDN,
                              attributeType, assertionValue);
opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -56,7 +56,7 @@
import org.opends.server.core.AbandonOperation;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.BindOperationBasis;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.CompareOperationBasis;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ExtendedOperation;
@@ -2063,8 +2063,8 @@
    }
    CompareRequestProtocolOp protocolOp = message.getCompareRequestProtocolOp();
    CompareOperation compareOp =
         new CompareOperation(this, nextOperationID.getAndIncrement(),
    CompareOperationBasis compareOp =
         new CompareOperationBasis(this, nextOperationID.getAndIncrement(),
                              message.getMessageID(), controls,
                              protocolOp.getDN(), protocolOp.getAttributeType(),
                              protocolOp.getAssertionValue());
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
New file
@@ -0,0 +1,86 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.workflowelement.localbackend;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.CompareOperationWrapper;
import org.opends.server.types.Entry;
import org.opends.server.types.operation.PostOperationCompareOperation;
import org.opends.server.types.operation.PostResponseCompareOperation;
import org.opends.server.types.operation.PreOperationCompareOperation;
/**
 * This class defines an operation that may be used to determine whether a
 * specified entry in the Directory Server contains a given attribute-value
 * pair.
 */
public class LocalBackendCompareOperation extends CompareOperationWrapper
    implements PreOperationCompareOperation,
               PostOperationCompareOperation,
               PostResponseCompareOperation
{
  // The entry to be compared.
  private Entry entry = null;
  /**
   * Creates a new compare operation based on the provided compare operation.
   *
   * @param compare  the compare operation
   */
  public LocalBackendCompareOperation(CompareOperation compare)
  {
    super(compare);
    LocalBackendWorkflowElement.attachLocalOperation (compare, this);
  }
  /**
   * Retrieves the entry to target with the compare operation.
   *
   * @return  The entry to target with the compare operation, or
   *          <CODE>null</CODE> if the entry is not yet available.
   */
  public Entry getEntryToCompare()
  {
    return entry;
  }
  /**
   * Set the entry to target with the compare operation.
   *
   * @param  entry   The entry to target with the compare operation.
   */
  public void setEntryToCompare(Entry entry)
  {
    this.entry = entry;
  }
}
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -74,6 +74,7 @@
import org.opends.server.core.AccessControlConfigManager;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
@@ -178,6 +179,9 @@
    case MODIFY:
      processModify((ModifyOperation) operation);
      break;
    case COMPARE:
      processCompare((CompareOperation) operation);
      break;
    default:
      // jdemendi - temporary code, just make sure that we don't fell into
      // that incomplete code...
@@ -5860,9 +5864,9 @@
  /**
   * Perform a delete operation against a local backend.
   * Performs a delete operation against a local backend.
   *
   * @param operation - The operation to perform
   * @param operation the operation to perform
   */
  public void processDelete(DeleteOperation operation){
    LocalBackendDeleteOperation localOperation =
@@ -5871,9 +5875,9 @@
  }
  /**
   * Perform a local delete operation against a local backend.
   * Performs a local delete operation against a local backend.
   *
   * @param operation - The operation to perform
   * @param operation the operation to perform
   */
  private void processLocalDelete(LocalBackendDeleteOperation localOp)
  {
@@ -6673,6 +6677,576 @@
  /**
   * Perform a compare operation against a local backend.
   *
   * @param operation - The operation to perform
   */
  public void processCompare(CompareOperation operation)
  {
    LocalBackendCompareOperation localOperation =
      new LocalBackendCompareOperation(operation);
    processLocalCompare(localOperation);
  }
  /**
   * Perform a local compare operation against a local backend.
   *
   * @param operation - The operation to perform
   */
  private void processLocalCompare(LocalBackendCompareOperation localOp)
  {
    // Get the plugin config manager that will be used for invoking plugins.
    PluginConfigManager pluginConfigManager =
         DirectoryServer.getPluginConfigManager();
    boolean skipPostOperation = false;
    // Get a reference to the client connection
    ClientConnection clientConnection = localOp.getClientConnection();
    // Check for and handle a request to cancel this operation.
    if (localOp.getCancelRequest() != null)
    {
      return;
    }
    // Create a labeled block of code that we can break out of if a problem is
    // detected.
compareProcessing:
    {
      // Process the entry DN to convert it from the raw form to the form
      // required for the rest of the compare processing.
      DN entryDN = localOp.getEntryDN();
      if (entryDN == null)
      {
        skipPostOperation = true;
        break compareProcessing;
      }
      // If the target entry is in the server configuration, then make sure the
      // requester has the CONFIG_READ privilege.
      if (DirectoryServer.getConfigHandler().handlesEntry(entryDN) &&
          (! clientConnection.hasPrivilege(Privilege.CONFIG_READ, localOp)))
      {
        int msgID = MSGID_COMPARE_CONFIG_INSUFFICIENT_PRIVILEGES;
        localOp.appendErrorMessage(getMessage(msgID));
        localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
        skipPostOperation = true;
        break compareProcessing;
      }
      // Check for and handle a request to cancel this operation.
      if (localOp.getCancelRequest() != null)
      {
        return;
      }
      // Grab a read lock on the entry.
      Lock readLock = null;
      for (int i=0; i < 3; i++)
      {
        readLock = LockManager.lockRead(entryDN);
        if (readLock != null)
        {
          break;
        }
      }
      if (readLock == null)
      {
        int    msgID   = MSGID_COMPARE_CANNOT_LOCK_ENTRY;
        String message = getMessage(msgID, String.valueOf(entryDN));
        localOp.setResultCode(DirectoryServer.getServerErrorResultCode());
        localOp.appendErrorMessage(message);
        skipPostOperation = true;
        break compareProcessing;
      }
      Entry entry = null;
      try
      {
        // Get the entry.  If it does not exist, then fail.
        try
        {
          entry = DirectoryServer.getEntry(entryDN);
          localOp.setEntryToCompare(entry);
          if (entry == null)
          {
            localOp.setResultCode(ResultCode.NO_SUCH_OBJECT);
            localOp.appendErrorMessage(getMessage(MSGID_COMPARE_NO_SUCH_ENTRY,
                                          String.valueOf(entryDN)));
            // See if one of the entry's ancestors exists.
            DN parentDN = entryDN.getParentDNInSuffix();
            while (parentDN != null)
            {
              try
              {
                if (DirectoryServer.entryExists(parentDN))
                {
                  localOp.setMatchedDN(parentDN);
                  break;
                }
              }
              catch (Exception e)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
                }
                break;
              }
              parentDN = parentDN.getParentDNInSuffix();
            }
            break compareProcessing;
          }
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          localOp.setResultCode(de.getResultCode());
          localOp.appendErrorMessage(de.getErrorMessage());
          break compareProcessing;
        }
        // Check to see if there are any controls in the request.  If so, then
        // see if there is any special processing required.
        List<Control> requestControls = localOp.getRequestControls();
        if ((requestControls != null) && (! requestControls.isEmpty()))
        {
          for (int i=0; i < requestControls.size(); i++)
          {
            Control c   = requestControls.get(i);
            String  oid = c.getOID();
            if (oid.equals(OID_LDAP_ASSERTION))
            {
              LDAPAssertionRequestControl assertControl;
              if (c instanceof LDAPAssertionRequestControl)
              {
                assertControl = (LDAPAssertionRequestControl) c;
              }
              else
              {
                try
                {
                  assertControl = LDAPAssertionRequestControl.decodeControl(c);
                  requestControls.set(i, assertControl);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  localOp.appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              try
              {
                // FIXME -- We need to determine whether the current user has
                //          permission to make this determination.
                SearchFilter filter = assertControl.getSearchFilter();
                if (! filter.matchesEntry(entry))
                {
                  localOp.setResultCode(ResultCode.ASSERTION_FAILED);
                  localOp.appendErrorMessage(
                      getMessage(MSGID_COMPARE_ASSERTION_FAILED,
                      String.valueOf(entryDN)));
                  break compareProcessing;
                }
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                localOp.setResultCode(ResultCode.PROTOCOL_ERROR);
                int msgID = MSGID_COMPARE_CANNOT_PROCESS_ASSERTION_FILTER;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN),
                    de.getErrorMessage()));
                break compareProcessing;
              }
            }
            else if (oid.equals(OID_PROXIED_AUTH_V1))
            {
              // The requester must have the PROXIED_AUTH privilige in order to
              // be able to use this control.
              if (! clientConnection.hasPrivilege(
                       Privilege.PROXIED_AUTH, localOp))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                localOp.appendErrorMessage(getMessage(msgID));
                localOp.setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV1Control proxyControl;
              if (c instanceof ProxiedAuthV1Control)
              {
                proxyControl = (ProxiedAuthV1Control) c;
              }
              else
              {
                try
                {
                  proxyControl = ProxiedAuthV1Control.decodeControl(c);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  localOp.appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                localOp.setResultCode(de.getResultCode());
                localOp.appendErrorMessage(de.getErrorMessage());
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                                                 authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                localOp.setProxiedAuthorizationDN(DN.nullDN());
              }
              else
              {
                localOp.setProxiedAuthorizationDN(authorizationEntry.getDN());
              }
            }
            else if (oid.equals(OID_PROXIED_AUTH_V2))
            {
              // The requester must have the PROXIED_AUTH privilige in order to
              // be able to use this control.
              if (! clientConnection.hasPrivilege(
                       Privilege.PROXIED_AUTH, localOp))
              {
                int msgID = MSGID_PROXYAUTH_INSUFFICIENT_PRIVILEGES;
                localOp.appendErrorMessage(getMessage(msgID));
                localOp.setResultCode(ResultCode.AUTHORIZATION_DENIED);
                break compareProcessing;
              }
              ProxiedAuthV2Control proxyControl;
              if (c instanceof ProxiedAuthV2Control)
              {
                proxyControl = (ProxiedAuthV2Control) c;
              }
              else
              {
                try
                {
                  proxyControl = ProxiedAuthV2Control.decodeControl(c);
                }
                catch (LDAPException le)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugCaught(DebugLogLevel.ERROR, le);
                  }
                  localOp.setResultCode(ResultCode.valueOf(le.getResultCode()));
                  localOp.appendErrorMessage(le.getMessage());
                  break compareProcessing;
                }
              }
              Entry authorizationEntry;
              try
              {
                authorizationEntry = proxyControl.getAuthorizationEntry();
              }
              catch (DirectoryException de)
              {
                if (debugEnabled())
                {
                  TRACER.debugCaught(DebugLogLevel.ERROR, de);
                }
                localOp.setResultCode(de.getResultCode());
                localOp.appendErrorMessage(de.getErrorMessage());
                break compareProcessing;
              }
              if (AccessControlConfigManager.getInstance()
                      .getAccessControlHandler().isProxiedAuthAllowed(localOp,
                                                 authorizationEntry) == false) {
                localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
                int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN)));
                skipPostOperation = true;
                break compareProcessing;
              }
              localOp.setAuthorizationEntry(authorizationEntry);
              if (authorizationEntry == null)
              {
                localOp.setProxiedAuthorizationDN(DN.nullDN());
              }
              else
              {
                localOp.setProxiedAuthorizationDN(authorizationEntry.getDN());
              }
            }
            // NYI -- Add support for additional controls.
            else if (c.isCritical())
            {
              Backend backend = DirectoryServer.getBackend(entryDN);
              if ((backend == null) || (! backend.supportsControl(oid)))
              {
                localOp.setResultCode(
                    ResultCode.UNAVAILABLE_CRITICAL_EXTENSION);
                int msgID = MSGID_COMPARE_UNSUPPORTED_CRITICAL_CONTROL;
                localOp.appendErrorMessage(
                    getMessage(msgID, String.valueOf(entryDN), oid));
                break compareProcessing;
              }
            }
          }
        }
        // Check to see if the client has permission to perform the
        // compare.
        // FIXME: for now assume that this will check all permission
        // pertinent to the operation. This includes proxy authorization
        // and any other controls specified.
        // FIXME: earlier checks to see if the entry already exists may
        // have already exposed sensitive information to the client.
        if (AccessControlConfigManager.getInstance()
            .getAccessControlHandler().isAllowed(localOp) == false) {
          localOp.setResultCode(ResultCode.INSUFFICIENT_ACCESS_RIGHTS);
          int msgID = MSGID_COMPARE_AUTHZ_INSUFFICIENT_ACCESS_RIGHTS;
          localOp.appendErrorMessage(
              getMessage(msgID, String.valueOf(entryDN)));
          skipPostOperation = true;
          break compareProcessing;
        }
        // Check for and handle a request to cancel this operation.
        if (localOp.getCancelRequest() != null)
        {
          return;
        }
        // Invoke the pre-operation compare plugins.
        PreOperationPluginResult preOpResult =
             pluginConfigManager.invokePreOperationComparePlugins(localOp);
        if (preOpResult.connectionTerminated())
        {
          // There's no point in continuing with anything.  Log the request and
          // result and return.
          localOp.setResultCode(ResultCode.CANCELED);
          int msgID = MSGID_CANCELED_BY_PREOP_DISCONNECT;
          localOp.appendErrorMessage(getMessage(msgID));
          return;
        }
        else if (preOpResult.sendResponseImmediately())
        {
          skipPostOperation = true;
          break compareProcessing;
        }
        else if (preOpResult.skipCoreProcessing())
        {
          skipPostOperation = false;
          break compareProcessing;
        }
        // Get the base attribute type and set of options.
        String          baseName;
        HashSet<String> options;
        String rawAttributeType = localOp.getRawAttributeType();
        int             semicolonPos = rawAttributeType.indexOf(';');
        if (semicolonPos > 0)
        {
          baseName = toLowerCase(rawAttributeType.substring(0, semicolonPos));
          options = new HashSet<String>();
          int nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
          while (nextPos > 0)
          {
            options.add(rawAttributeType.substring(semicolonPos+1, nextPos));
            semicolonPos = nextPos;
            nextPos = rawAttributeType.indexOf(';', semicolonPos+1);
          }
          options.add(rawAttributeType.substring(semicolonPos+1));
        }
        else
        {
          baseName = toLowerCase(rawAttributeType);
          options  = null;
        }
        // Actually perform the compare operation.
        List<Attribute> attrList = null;
        if (localOp.getAttributeType() == null)
        {
          localOp.setAttributeType(DirectoryServer.getAttributeType(baseName));
        }
        if (localOp.getAttributeType() == null)
        {
          attrList = entry.getAttribute(baseName, options);
          localOp.setAttributeType(
              DirectoryServer.getDefaultAttributeType(baseName));
        }
        else
        {
          attrList = entry.getAttribute(localOp.getAttributeType(), options);
        }
        if ((attrList == null) || attrList.isEmpty())
        {
          localOp.setResultCode(ResultCode.NO_SUCH_ATTRIBUTE);
          if (options == null)
          {
            localOp.appendErrorMessage(getMessage(MSGID_COMPARE_OP_NO_SUCH_ATTR,
                                          String.valueOf(entryDN), baseName));
          }
          else
          {
            localOp.appendErrorMessage(getMessage(
                                    MSGID_COMPARE_OP_NO_SUCH_ATTR_WITH_OPTIONS,
                                    String.valueOf(entryDN), baseName));
          }
        }
        else
        {
          AttributeValue value = new AttributeValue(
              localOp.getAttributeType(),
              localOp.getAssertionValue());
          boolean matchFound = false;
          for (Attribute a : attrList)
          {
            if (a.hasValue(value))
            {
              matchFound = true;
              break;
            }
          }
          if (matchFound)
          {
            localOp.setResultCode(ResultCode.COMPARE_TRUE);
          }
          else
          {
            localOp.setResultCode(ResultCode.COMPARE_FALSE);
          }
        }
      }
      finally
      {
        LockManager.unlock(entryDN, readLock);
      }
    }
    // Check for and handle a request to cancel this operation.
    if (localOp.getCancelRequest() != null)
    {
      return;
    }
    // Invoke the post-operation compare plugins.
    if (! skipPostOperation)
    {
      PostOperationPluginResult postOperationResult =
           pluginConfigManager.invokePostOperationComparePlugins(localOp);
      if (postOperationResult.connectionTerminated())
      {
        localOp.setResultCode(ResultCode.CANCELED);
        int msgID = MSGID_CANCELED_BY_POSTOP_DISCONNECT;
        localOp.appendErrorMessage(getMessage(msgID));
        return;
      }
    }
  }
  /**
   * Attaches the current local operation to the global operation so that
   * operation runner can execute local operation post response later on.
   *
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/CompareOperationTestCase.java
@@ -48,7 +48,6 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
import static org.testng.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
@@ -138,7 +137,8 @@
    return new Operation[]
    {
      new CompareOperation(conn, InternalClientConnection.nextOperationID(),
      new CompareOperationBasis(
                           conn, InternalClientConnection.nextOperationID(),
                           InternalClientConnection.nextMessageID(),
                           new ArrayList<Control>(),
                           new ASN1OctetString(entry.getDN().toString()),
@@ -216,8 +216,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -240,8 +241,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -263,8 +265,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString("o=nonexistent,o=test"),
@@ -285,8 +288,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString("rogasawara,o=test"),
@@ -307,8 +311,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -330,8 +335,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -352,8 +358,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -371,8 +378,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -390,8 +398,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -409,8 +418,9 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              new ArrayList<Control>(),
                              new ASN1OctetString(entry.getDN().toString()),
@@ -436,8 +446,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(assertControl);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -465,8 +476,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(assertControl);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
@@ -490,8 +502,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV1Control);
    CompareOperation compareOperation =
         new CompareOperation(proxyUserConn,
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
@@ -518,8 +531,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV1Control);
    CompareOperation compareOperation =
         new CompareOperation(proxyUserConn,
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
@@ -544,8 +558,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(proxyUserConn,
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
@@ -570,8 +585,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(proxyUserConn,
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
@@ -597,8 +613,9 @@
    List<Control> controls = new ArrayList<Control>();
    controls.add(authV2Control);
    CompareOperation compareOperation =
         new CompareOperation(proxyUserConn,
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              proxyUserConn,
                              InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
@@ -625,8 +642,9 @@
         new LDAPAssertionRequestControl("1.1.1.1.1.1", true, ldapFilter);
    List<Control> controls = new ArrayList<Control>();
    controls.add(assertControl);
    CompareOperation compareOperation =
         new CompareOperation(conn, InternalClientConnection.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(
                              conn, InternalClientConnection.nextOperationID(),
                              InternalClientConnection.nextMessageID(),
                              controls,
                              new ASN1OctetString(entry.getDN().toString()),
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/protocols/jmx/JmxPrivilegeTestCase.java
@@ -44,7 +44,6 @@
import java.util.UUID;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.ClassLoaderProvider;
import org.opends.server.backends.task.Task;
import org.opends.server.backends.task.TaskBackend;
import org.opends.server.backends.task.TaskState;
@@ -53,6 +52,7 @@
import org.opends.server.core.AddOperation;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.CompareOperationBasis;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
@@ -1260,8 +1260,8 @@
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));
@@ -1467,8 +1467,8 @@
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/types/PrivilegeTestCase.java
@@ -48,6 +48,7 @@
import org.opends.server.core.AddOperation;
import org.opends.server.core.AddOperationBasis;
import org.opends.server.core.CompareOperation;
import org.opends.server.core.CompareOperationBasis;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DeleteOperationBasis;
import org.opends.server.core.DirectoryServer;
@@ -1319,8 +1320,8 @@
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));
@@ -1524,8 +1525,8 @@
    // Test a compare operation against the PWReset Target user.
    CompareOperation compareOperation =
         new CompareOperation(conn, conn.nextOperationID(),
    CompareOperationBasis compareOperation =
         new CompareOperationBasis(conn, conn.nextOperationID(),
                              conn.nextMessageID(), controls, targetDN,
                              DirectoryServer.getAttributeType("cn", true),
                              ByteStringFactory.create("PWReset Target"));