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

neil_a_wilson
25.54.2007 459b0d746ffd89bdf8fcd47fa3a14e76be87136f
Further split up the local backend modify operation to allow it to be
better optimized, and do the same for SearchFilter.matchesEntryInternal and
Entry.conformsToSchema.

Also, fix a problem in the local backend operations where cancel requests
were not being handled correctly.
8 files modified
807 ■■■■ changed files
opends/src/server/org/opends/server/types/Entry.java 150 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/SearchFilter.java 294 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java 31 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java 29 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java 27 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java 31 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java 218 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java 27 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Entry.java
@@ -2438,6 +2438,70 @@
    }
    if (! checkAttributesAndObjectClasses(ditContentRule,
               structuralPolicy, invalidReason))
    {
      return false;
    }
    // If there is a name form for this entry, then make sure that the
    // RDN for the entry is in compliance with it.
    if (nameForm != null)
    {
      if (! checkNameForm(nameForm, structuralPolicy, invalidReason))
      {
        return false;
      }
    }
    // If there is a DIT content rule for this entry, then make sure
    // that the entry is in compliance with it.
    if (ditContentRule != null)
    {
      if (! checkDITContentRule(ditContentRule, structuralPolicy,
                                invalidReason))
      {
        return false;
      }
    }
    if (! checkDITStructureRule(ditStructureRule, structuralClass,
               parentEntry, parentProvided, validateStructureRules,
               structuralPolicy, invalidReason))
    {
      return false;
    }
    // If we've gotten here, then the entry is acceptable.
    return true;
  }
  /**
   * Checks the attributes and object classes contained in this entry
   * to determine whether they conform to the server schema
   * requirements.
   *
   * @param  ditContentRule    The DIT content rule for this entry, if
   *                           any.
   * @param  structuralPolicy  The policy that should be used for
   *                           structural object class compliance.
   * @param  invalidReason     A buffer into which an invalid reason
   *                           may be added.
   *
   * @return {@code true} if this entry passes all of the checks, or
   *         {@code false} if there are any failures.
   */
  private boolean checkAttributesAndObjectClasses(
                       DITContentRule ditContentRule,
                       AcceptRejectWarn structuralPolicy,
                       MessageBuilder invalidReason)
  {
    // Make sure that we recognize all of the objectclasses, that all
    // auxiliary classes are allowed by the DIT content rule, and that
    // all attributes required by the object classes are present.
@@ -2579,9 +2643,28 @@
    }
    // If there is a name form for this entry, then make sure that the
    // RDN for the entry is in compliance with it.
    if (nameForm != null)
    // If we've gotten here, then things are OK.
    return true;
  }
  /**
   * Performs any processing needed for name form validation.
   *
   * @param  nameForm          The name form to validate against this
   *                           entry.
   * @param  structuralPolicy  The policy that should be used for
   *                           structural object class compliance.
   * @param  invalidReason     A buffer into which an invalid reason
   *                           may be added.
   *
   * @return {@code true} if this entry passes all of the checks, or
   *         {@code false} if there are any failures.
   */
  private boolean checkNameForm(NameForm nameForm,
                       AcceptRejectWarn structuralPolicy,
                       MessageBuilder invalidReason)
    {
      RDN rdn = dn.getRDN();
      if (rdn != null)
@@ -2634,12 +2717,29 @@
          }
        }
      }
    // If we've gotten here, then things are OK.
    return true;
    }
    // If there is a DIT content rule for this entry, then make sure
    // that the entry is in compliance with it.
    if (ditContentRule != null)
  /**
   * Performs any processing needed for DIT content rule validation.
   *
   * @param  ditContentRule    The DIT content rule to validate
   *                           against this entry.
   * @param  structuralPolicy  The policy that should be used for
   *                           structural object class compliance.
   * @param  invalidReason     A buffer into which an invalid reason
   *                           may be added.
   *
   * @return {@code true} if this entry passes all of the checks, or
   *         {@code false} if there are any failures.
   */
  private boolean checkDITContentRule(DITContentRule ditContentRule,
                       AcceptRejectWarn structuralPolicy,
                       MessageBuilder invalidReason)
    {
      // Make sure that all of the required attributes are present.
      for (AttributeType t : ditContentRule.getRequiredAttributes())
@@ -2689,9 +2789,44 @@
          }
        }
      }
    // If we've gotten here, then things are OK.
    return true;
    }
  /**
   * Performs any processing needed for DIT structure rule validation.
   *
   * @param  ditStructureRule        The DIT structure rule for this
   *                                 entry.
   * @param  structuralClass         The structural object class for
   *                                 this entry.
   * @param  parentEntry             The parent entry, if available
   *                                 and applicable.
   * @param  parentProvided          Indicates whether the parent
   *                                 entry was provided.
   * @param  validateStructureRules  Indicates whether to check to see
   *                                 if this entry violates a DIT
   *                                 structure rule for its parent.
   * @param  structuralPolicy        The policy that should be used
   *                                 for structural object class
   *                                 compliance.
   * @param  invalidReason           A buffer into which an invalid
   *                                 reason may be added.
   *
   * @return {@code true} if this entry passes all of the checks, or
   *         {@code false} if there are any failures.
   */
  private boolean checkDITStructureRule(
                       DITStructureRule ditStructureRule,
                       ObjectClass structuralClass,
                       Entry parentEntry, boolean parentProvided,
                       boolean validateStructureRules,
                       AcceptRejectWarn structuralPolicy,
                       MessageBuilder invalidReason)
  {
    // If there is a DIT structure rule for this entry, then make sure
    // that the entry is in compliance with it.
    if ((ditStructureRule != null) &&
@@ -2965,8 +3100,7 @@
      }
    }
    // If we've gotten here, then the entry is acceptable.
    // If we've gotten here, then things are OK.
    return true;
  }
opends/src/server/org/opends/server/types/SearchFilter.java
@@ -2331,6 +2331,72 @@
    switch (filterType)
    {
      case AND:
        return processAND(completeFilter, entry, depth);
      case OR:
        return processOR(completeFilter, entry, depth);
      case NOT:
        return processNOT(completeFilter, entry, depth);
      case EQUALITY:
        return processEquality(completeFilter, entry);
      case SUBSTRING:
        return processSubstring(completeFilter, entry);
      case GREATER_OR_EQUAL:
        return processGreaterOrEqual(completeFilter, entry);
      case LESS_OR_EQUAL:
        return processLessOrEqual(completeFilter, entry);
      case PRESENT:
        return processPresent(completeFilter, entry);
      case APPROXIMATE_MATCH:
        return processApproximate(completeFilter, entry);
      case EXTENSIBLE_MATCH:
        return processExtensibleMatch(completeFilter, entry);
      default:
        // This is an invalid filter type.
        Message message = ERR_SEARCH_FILTER_INVALID_FILTER_TYPE.
            get(String.valueOf(entry.getDN()), toString(),
                filterType.toString());
        throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
                                     message);
    }
  }
  /**
   * Indicates whether the this AND filter matches the provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   * @param  depth           The current depth of the evaluation,
   *                         which is used to prevent infinite
   *                         recursion due to highly nested filters
   *                         and eventually running out of stack
   *                         space.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processAND(SearchFilter completeFilter,
                                     Entry entry, int depth)
          throws DirectoryException
  {
        if (filterComponents == null)
        {
          // The set of subcomponents was null.  This is not allowed.
@@ -2420,9 +2486,34 @@
          }
          return ConditionResult.TRUE;
        }
  }
      case OR:
  /**
   * Indicates whether the this OR filter matches the provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   * @param  depth           The current depth of the evaluation,
   *                         which is used to prevent infinite
   *                         recursion due to highly nested filters
   *                         and eventually running out of stack
   *                         space.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processOR(SearchFilter completeFilter,
                                    Entry entry, int depth)
          throws DirectoryException
  {
        if (filterComponents == null)
        {
          // The set of subcomponents was null.  This is not allowed.
@@ -2513,9 +2604,34 @@
          }
          return result;
        }
  }
      case NOT:
  /**
   * Indicates whether the this NOT filter matches the provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   * @param  depth           The current depth of the evaluation,
   *                         which is used to prevent infinite
   *                         recursion due to highly nested filters
   *                         and eventually running out of stack
   *                         space.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processNOT(SearchFilter completeFilter,
                                     Entry entry, int depth)
          throws DirectoryException
  {
        if (notComponent == null)
        {
          // The NOT subcomponent was null.  This is not allowed.
@@ -2584,9 +2700,30 @@
                        message);
          }
        }
  }
      case EQUALITY:
  /**
   * Indicates whether the this equality filter matches the provided
   * entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processEquality(SearchFilter completeFilter,
                                          Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2653,9 +2790,31 @@
                       assertionValue.getStringValue());
        }
        return ConditionResult.FALSE;
  }
      case SUBSTRING:
  /**
   * Indicates whether the this substring filter matches the provided
   * entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processSubstring(
                                SearchFilter completeFilter,
                                Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2681,7 +2840,8 @@
        }
        // See if the entry has an attribute with the requested type.
        attrs = entry.getAttribute(attributeType, attributeOptions);
    List<Attribute> attrs =
         entry.getAttribute(attributeType, attributeOptions);
        if ((attrs == null) || (attrs.isEmpty()))
        {
          if (debugEnabled())
@@ -2738,9 +2898,31 @@
              result, this, completeFilter, entry.getDN());
        }
        return result;
  }
      case GREATER_OR_EQUAL:
  /**
   * Indicates whether the this greater-or-equal filter matches the
   * provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processGreaterOrEqual(
                                SearchFilter completeFilter,
                                Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2763,7 +2945,8 @@
        }
        // See if the entry has an attribute with the requested type.
        attrs = entry.getAttribute(attributeType, attributeOptions);
    List<Attribute> attrs =
         entry.getAttribute(attributeType, attributeOptions);
        if ((attrs == null) || (attrs.isEmpty()))
        {
          if (debugEnabled())
@@ -2779,7 +2962,7 @@
        // Iterate through all the attributes and see if we can find a
        // match.
        result = ConditionResult.FALSE;
    ConditionResult result = ConditionResult.FALSE;
        for (Attribute a : attrs)
        {
          switch (a.greaterThanOrEqualTo(assertionValue))
@@ -2818,9 +3001,31 @@
                       result, this, completeFilter, entry.getDN());
        }
        return result;
  }
      case LESS_OR_EQUAL:
  /**
   * Indicates whether the this less-or-equal filter matches the
   * provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processLessOrEqual(
                                SearchFilter completeFilter,
                                Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2843,7 +3048,8 @@
        }
        // See if the entry has an attribute with the requested type.
        attrs = entry.getAttribute(attributeType, attributeOptions);
    List<Attribute> attrs =
         entry.getAttribute(attributeType, attributeOptions);
        if ((attrs == null) || (attrs.isEmpty()))
        {
          if (debugEnabled())
@@ -2859,7 +3065,7 @@
        // Iterate through all the attributes and see if we can find a
        // match.
        result = ConditionResult.FALSE;
    ConditionResult result = ConditionResult.FALSE;
        for (Attribute a : attrs)
        {
          switch (a.lessThanOrEqualTo(assertionValue))
@@ -2898,9 +3104,30 @@
                       result, this, completeFilter, entry.getDN());
        }
        return result;
  }
      case PRESENT:
  /**
   * Indicates whether the this present filter matches the provided
   * entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processPresent(SearchFilter completeFilter,
                                         Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2936,9 +3163,31 @@
          }
          return ConditionResult.FALSE;
        }
  }
      case APPROXIMATE_MATCH:
  /**
   * Indicates whether the this approximate filter matches the
   * provided entry.
   *
   * @param  completeFilter  The complete filter being checked, of
   *                         which this filter may be a subset.
   * @param  entry           The entry for which to make the
   *                         determination.
   *
   * @return  <CODE>TRUE</CODE> if this filter matches the provided
   *          entry, <CODE>FALSE</CODE> if it does not, or
   *          <CODE>UNDEFINED</CODE> if the result is undefined.
   *
   * @throws  DirectoryException  If a problem is encountered during
   *                              processing.
   */
  private ConditionResult processApproximate(
                                SearchFilter completeFilter,
                                Entry entry)
          throws DirectoryException
  {
        // Make sure that an attribute type has been defined.
        if (attributeType == null)
        {
@@ -2961,7 +3210,8 @@
        }
        // See if the entry has an attribute with the requested type.
        attrs = entry.getAttribute(attributeType, attributeOptions);
    List<Attribute> attrs =
         entry.getAttribute(attributeType, attributeOptions);
        if ((attrs == null) || (attrs.isEmpty()))
        {
          if (debugEnabled())
@@ -2977,7 +3227,7 @@
        // Iterate through all the attributes and see if we can find a
        // match.
        result = ConditionResult.FALSE;
    ConditionResult result = ConditionResult.FALSE;
        for (Attribute a : attrs)
        {
          switch (a.approximatelyEqualTo(assertionValue))
@@ -3015,20 +3265,6 @@
              result, this, completeFilter, entry.getDN());
        }
        return result;
      case EXTENSIBLE_MATCH:
        return processExtensibleMatch(completeFilter, entry);
      default:
        // This is an invalid filter type.
        Message message = ERR_SEARCH_FILTER_INVALID_FILTER_TYPE.
            get(String.valueOf(entry.getDN()), toString(),
                filterType.toString());
        throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
                                     message);
    }
  }
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendAddOperation.java
@@ -193,7 +193,7 @@
    skipPostOperation = false;
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -222,7 +222,7 @@
      }
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -254,7 +254,7 @@
      try
      {
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -596,7 +596,7 @@
        }
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -631,7 +631,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -855,6 +855,27 @@
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Acquire a read lock on the parent of the entry to add.
   *
   * @return  The acquired read lock.
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendCompareOperation.java
@@ -152,7 +152,7 @@
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -185,7 +185,7 @@
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -302,7 +302,7 @@
        }
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -415,7 +415,7 @@
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -438,6 +438,27 @@
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Performs any processing required for the controls included in the request.
   *
   * @throws  DirectoryException  If a problem occurs that should prevent the
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendDeleteOperation.java
@@ -163,7 +163,7 @@
    skipPostOperation = false;
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -314,7 +314,7 @@
        }
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -345,7 +345,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -590,6 +590,27 @@
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Performs any request control processing needed for this operation.
   *
   * @throws  DirectoryException  If a problem occurs that should cause the
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyDNOperation.java
@@ -203,7 +203,7 @@
    skipPostOperation = false;
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -283,7 +283,7 @@
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -359,7 +359,7 @@
      try
      {
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -514,7 +514,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -575,7 +575,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -789,6 +789,27 @@
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Processes the set of controls included in the request.
   *
   * @throws  DirectoryException  If a problem occurs that should cause the
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendModifyOperation.java
@@ -366,7 +366,7 @@
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -395,86 +395,26 @@
      try
      {
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
        try
        {
        // Get the entry to modify.  If it does not exist, then fail.
        try
        {
          currentEntry = backend.getEntry(entryDN);
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResponseData(de);
          break modifyProcessing;
        }
        if (currentEntry == null)
        {
          setResultCode(ResultCode.NO_SUCH_OBJECT);
          appendErrorMessage(ERR_MODIFY_NO_SUCH_ENTRY.get(
                                  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 modifyProcessing;
        }
          getEntryToModify();
        // Check to see if there are any controls in the request.  If so, then
        // see if there is any special processing required.
        try
        {
          processRequestControls();
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResponseData(de);
          break modifyProcessing;
        }
        // Get the password policy state object for the entry that can be used
        // to perform any appropriate password policy processing.  Also, see if
        // the entry is being updated by the end user or an administrator.
          // to perform any appropriate password policy processing.  Also, see
          // if the entry is being updated by the end user or an administrator.
        selfChange = entryDN.equals(getAuthorizationDN());
        try
        {
          // FIXME -- Need a way to enable debug mode.
          pwPolicyState = new PasswordPolicyState(currentEntry, false, false);
        }
@@ -485,8 +425,7 @@
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResultCode(de.getResultCode());
          appendErrorMessage(de.getMessageObject());
          setResponseData(de);
          break modifyProcessing;
        }
@@ -529,28 +468,13 @@
        try
        {
          handleInitialPasswordPolicyAndSchemaProcessing();
        }
        catch (DirectoryException de)
        {
          if (debugEnabled())
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, de);
          }
          setResponseData(de);
          break modifyProcessing;
        }
        // If there was a password change, then perform any additional checks
        // that may be necessary.
        wasLocked = false;
        if (passwordChanged)
        {
          try
          {
            performAdditionalPasswordChangedProcessing();
          }
        }
          catch (DirectoryException de)
          {
            if (debugEnabled())
@@ -561,7 +485,6 @@
            setResponseData(de);
            break modifyProcessing;
          }
        }
        // Check to see if the client has permission to perform the modify.
@@ -614,7 +537,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -648,7 +571,7 @@
        // Check for a request to cancel this operation.
        if (getCancelRequest() != null)
        if (cancelIfRequested())
        {
          return;
        }
@@ -761,7 +684,7 @@
          setResultCode(cancelResult.getResultCode());
          Message message = coe.getMessageObject();
          if ((message != null) && (message.length() > 0))
          if (message != null)
          {
            appendErrorMessage(message);
          }
@@ -832,17 +755,68 @@
      }
    }
    // Notify any change notification listeners that might be registered with
    // the server.
    if (getResultCode() == ResultCode.SUCCESS)
    {
      for (ChangeNotificationListener changeListener :
           DirectoryServer.getChangeNotificationListeners())
      notifyChangeListeners();
    }
    // Stop the processing timer.
    setProcessingStopTime();
  }
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Gets the entry to modify.
   *
   * @return  The entry retrieved from the backend.
   *
   * @throws  DirectoryException  If a problem occurs while trying to get the
   *                              entry, or if the entry doesn't exist.
   */
  private void getEntryToModify()
          throws DirectoryException
  {
    currentEntry = backend.getEntry(entryDN);
    if (currentEntry == null)
    {
      // See if one of the entry's ancestors exists.
      DN matchedDN = null;
      DN parentDN = entryDN.getParentDNInSuffix();
      while (parentDN != null)
      {
        try
        {
          changeListener.handleModifyOperation(this, currentEntry,
                                               modifiedEntry);
          if (DirectoryServer.entryExists(parentDN))
          {
            matchedDN = parentDN;
            break;
          }
        }
        catch (Exception e)
        {
@@ -850,18 +824,16 @@
          {
            TRACER.debugCaught(DebugLogLevel.ERROR, e);
          }
          Message message = ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER.get(
              getExceptionMessage(e));
          logError(message);
        }
      }
          break;
    }
        parentDN = parentDN.getParentDNInSuffix();
      }
    // Stop the processing timer.
    setProcessingStopTime();
      throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
                     ERR_MODIFY_NO_SUCH_ENTRY.get(String.valueOf(entryDN)),
                     matchedDN, null);
    }
  }
@@ -1584,7 +1556,8 @@
  /**
   * Performs the initial schema processing for an add modification.
   * Performs the initial schema processing for an add modification and updates
   * the entry appropriately.
   *
   * @param  attr  The attribute being added.
   *
@@ -1676,7 +1649,8 @@
  /**
   * Performs the initial schema processing for a delete modification.
   * Performs the initial schema processing for a delete modification and
   * updates the entry appropriately.
   *
   * @param  attr  The attribute being deleted.
   *
@@ -1736,7 +1710,8 @@
  /**
   * Performs the initial schema processing for a replace modification.
   * Performs the initial schema processing for a replace modification and
   * updates the entry appropriately.
   *
   * @param  attr  The attribute being replaced.
   *
@@ -1897,7 +1872,8 @@
  /**
   * Performs the initial schema processing for an increment modification.
   * Performs the initial schema processing for an increment modification and
   * updates the entry appropriately.
   *
   * @param  attr  The attribute being incremented.
   *
@@ -2408,5 +2384,33 @@
      getResponseControls().add(responseControl);
    }
  }
  /**
   * Notify any registered change listeners about this update.
   */
  private void notifyChangeListeners()
  {
    for (ChangeNotificationListener changeListener :
         DirectoryServer.getChangeNotificationListeners())
    {
      try
      {
        changeListener.handleModifyOperation(this, currentEntry, modifiedEntry);
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_MODIFY_ERROR_NOTIFYING_CHANGE_LISTENER.get(
            getExceptionMessage(e));
        logError(message);
      }
    }
  }
}
opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendSearchOperation.java
@@ -191,7 +191,7 @@
      }
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -222,7 +222,7 @@
      // Check for a request to cancel this operation.
      if (getCancelRequest() != null)
      if (cancelIfRequested())
      {
        return;
      }
@@ -328,7 +328,7 @@
    // Check for a request to cancel this operation.
    if (getCancelRequest() != null)
    if (cancelIfRequested())
    {
      return;
    }
@@ -352,6 +352,27 @@
  /**
   * Checks to determine whether there has been a request to cancel this
   * operation.  If so, then set the cancel result and processing stop time.
   *
   * @return  {@code true} if there was a cancel request, or {@code false} if
   *          not.
   */
  private boolean cancelIfRequested()
  {
    if (getCancelRequest() == null)
    {
      return false;
    }
    indicateCancelled(getCancelRequest());
    setProcessingStopTime();
    return true;
  }
  /**
   * Handles any controls contained in the request.
   *
   * @throws  DirectoryException  If there is a problem with any of the request