Class UniquenessRequestControl

  • All Implemented Interfaces:
    java.io.Serializable

    @NotMutable
    @ThreadSafety(level=COMPLETELY_THREADSAFE)
    public final class UniquenessRequestControl
    extends Control
    This class provides a request control that may be included in an add, modify, or modify DN request to ensure that the contents of that request will not result in a uniqueness conflict with any other entry in the server. Each instance of this control should define exactly one uniqueness constraint for the associated operation. Multiple instances of this control can be included in the same request to define multiple independent uniqueness constraints that must all be satisfied. If any of the uniqueness constraints is not satisfied, then the corresponding LDAP result should have a result code of ResultCode.ASSERTION_FAILED and a UniquenessResponseControl for each uniqueness constraint that was not satisfied.
    NOTE: This class, and other classes within the com.unboundid.ldap.sdk.unboundidds package structure, are only supported for use against Ping Identity, UnboundID, and Nokia/Alcatel-Lucent 8661 server products. These classes provide support for proprietary functionality or for external specifications that are not considered stable or mature enough to be guaranteed to work in an interoperable way with other types of LDAP servers.

    The request properties must contain either one or more attribute types, a filter, or both. If only a filter is specified, then the server will use that filter to identify conflicts (for an add request, any matches at all will be considered a conflict; for a modify or modify DN request, any matches with any entry other than the one being updated will be considered a conflict). If a single attribute type is specified with no filter, then any change that would result in multiple entries having the same value for that attribute will be considered a conflict. If multiple attribute types are specified, then the multiple attribute behavior will be used to determine how to identify conflicts, as documented in the UniquenessMultipleAttributeBehavior enum. If both a set of attribute types and a filter are provided, then only entries matching both sets of criteria will be considered a conflict.

    The server can perform two different searches in an attempt to identify conflicts. In the pre-commit phase, it will attempt to identify any conflicts that already exist, and will reject the associated change if there are any. In the post-commit phase, it can see if there were any conflicts introduced by the change itself or by another change happening at the same time. If a conflict is detected in the post-commit phase, then the server won't have prevented it, but at least the control can be used to provide notification about it. The server may also raise an administrative alert to notify administrators about the conflict.

    Although post-commit validation on its own should be able to detect conflicts that arise as a result of concurrent changes in other instances, it is also possible to take additional measures to help prevent conflicts from arising in the first place. The control may indicate that the server should create a temporary conflict prevention details entry before beginning pre-commit validation processing. This entry may be found during pre-commit validation performed for any conflicting concurrent updates so that the conflicting operation is rejected. This temporary entry will be automatically removed after uniqueness processing has completed, regardless of its success or failure.

    This request control may be sent either directly to a Directory Server instance, or it may be sent to a Directory Proxy Server with or without entry balancing. If the request is sent directly to a Directory Server, then only that one server will be checked for uniqueness conflicts, and it is possible that concurrent conflicts may be introduced on other servers that have not yet been replicated by the time control processing has completed. If the request is sent to a Directory Proxy Server instance, then search may be processed in one or more backend servers based on the pre-commit and post-commit validation levels, and at the most paranoid levels, it is highly unlikely that any conflicts will go unnoticed.

    The request control has an OID of 1.3.6.1.4.1.30221.2.5.52, a criticality of either true or false, and a value with the following encoding:
       UniquenessRequestValue ::= SEQUENCE {
         uniquenessID                            [0] OCTET STRING,
         attributeTypes                          [1] SET OF OCTET STRING OPTIONAL,
         multipleAttributeBehavior               [2] ENUMERATED {
           uniqueWithinEachAttribute                      (0),
           uniqueAcrossAllAttributesIncludingInSameEntry  (1),
           uniqueAcrossAllAttributesExceptInSameEntry     (2),
           uniqueInCombination                            (3),
           ... } DEFAULT uniqueWithinEachAttribute,
         baseDN                                  [3] LDAPDN OPTIONAL,
         filter                                  [4] Filter OPTIONAL,
         preventConflictsWithSoftDeletedEntries  [5] BOOLEAN DEFAULT FALSE,
         preCommitValidationLevel                [6] ENUMERATED {
           none                        (0),
           allSubtreeViews             (1),
           allBackendSets              (2),
           allAvailableBackendServers  (3),
           ... } DEFAULT allSubtreeViews,
         postCommitValidationLevel               [7] ENUMERATED {
           none                        (0),
           allSubtreeViews             (1),
           allBackendSets              (2),
           allAvailableBackendServers  (3),
           ... } DEFAULT allSubtreeViews,
         alertOnPostCommitConflictDetection      [8] BOOLEAN DEFAULT TRUE,
         createConflictPreventionDetailsEntry    [9] BOOLEAN DEFAULT FALSE,
         ... }
     


    Example

    The following example demonstrates how to use the uniqueness request control to only process an add operation if it does not result in multiple entries that have the same uid value:

     // Create the properties to build a uniqueness request control that
     // will try to prevent an add operation from creating a new entry
     // that has the same uid as an existing entry in the server.  During
     // pre-commit processing (which happens before the server actually
     // processes the add), the server will check at least one server in
     // each entry-balancing backend set (or just one server in a
     // non-entry-balanced deployment).  During post-commit processing
     // (which happens if the add succeeds), the server will double-check
     // that no conflicting entry was added on any available server in the
     // topology.  Also ensure that the server will not allow conflicts
     // with soft-deleted entries.
     final UniquenessRequestControlProperties uniquenessProperties =
          new UniquenessRequestControlProperties("uid");
     uniquenessProperties.setPreCommitValidationLevel(
          UniquenessValidationLevel.ALL_BACKEND_SETS);
     uniquenessProperties.setPostCommitValidationLevel(
          UniquenessValidationLevel.ALL_AVAILABLE_BACKEND_SERVERS);
     uniquenessProperties.setPreventConflictsWithSoftDeletedEntries(true);
    
     // Create the request control.  It will be critical so that the
     // server will not attempt to process the add if it can't honor the
     // uniqueness request.
     final boolean isCritical = true;
     final String uniquenessID = "uid-uniqueness";
     final UniquenessRequestControl uniquenessRequestControl =
          new UniquenessRequestControl(isCritical, uniquenessID,
               uniquenessProperties);
    
     // Attach the control to an add request.
     addRequest.addControl(uniquenessRequestControl);
    
     // Send the add request to the server and read the result.
     try
     {
       final LDAPResult addResult = connection.add(addRequest);
    
       // The add operation succeeded, so the entry should have been
       // created, but there is still the possibility that a post-commit
       // conflict was discovered, indicating that another request
       // processed at about the same time as our add introduced a
       // conflicting entry.
       final Map<String,UniquenessResponseControl> uniquenessResponses;
       try
       {
         uniquenessResponses = UniquenessResponseControl.get(addResult);
       }
       catch (final LDAPException e)
       {
         throw new RuntimeException(
              "The add succeeded, but an error occurred while trying " +
                   "to decode a uniqueness response control in add " +
                   "result " + addResult + ":  " +
                   StaticUtils.getExceptionMessage(e),
              e);
       }
    
       final UniquenessResponseControl uniquenessResponseControl =
            uniquenessResponses.get(uniquenessID);
       if ((uniquenessResponseControl != null) &&
            uniquenessResponseControl.uniquenessConflictFound())
       {
         throw new RuntimeException(
              "The add succeeded, but a uniqueness conflict was found  " +
                   "Uniqueness validation message:  " +
                   uniquenessResponseControl.getValidationMessage());
       }
     }
     catch (final LDAPException e)
     {
       // The add attempt failed.  It might have been because of a
       // uniqueness problem, or it could have been for some other reason.
       // To figure out which it was, look to see if there is an
       // appropriate uniqueness response control.
       final Map<String, UniquenessResponseControl> uniquenessResponses;
       try
       {
         uniquenessResponses =
              UniquenessResponseControl.get(e.toLDAPResult());
       }
       catch (final LDAPException e2)
       {
         throw new LDAPException(e.getResultCode(),
              "The add attempt failed with result " + e.toLDAPResult() +
                   ", and an error occurred while trying to decode a " +
                   "uniqueness response control in the result:  " +
                   StaticUtils.getExceptionMessage(e2),
              e);
       }
    
       final UniquenessResponseControl uniquenessResponseControl =
            uniquenessResponses.get(uniquenessID);
       if (uniquenessResponseControl == null)
       {
         // The add result didn't include a uniqueness response control,
         // indicating that the failure was not because of a uniqueness
         // conflict.
         throw e;
       }
    
       if (uniquenessResponseControl.uniquenessConflictFound())
       {
         // The add failed, and the uniqueness response control indicates
         // that the failure was because of a uniqueness conflict.
    
         final UniquenessValidationResult preCommitResult =
              uniquenessResponseControl.getPreCommitValidationResult();
         final UniquenessValidationResult postCommitResult =
              uniquenessResponseControl.getPreCommitValidationResult();
         final String validationMessage =
              uniquenessResponseControl.getValidationMessage();
    
         throw e;
       }
       else
       {
         // The add failed, but the uniqueness response control indicates
         // that the failure was not because of a uniqueness conflict.
         throw e;
       }
     }
     
    See Also:
    Serialized Form
    • Constructor Detail

      • UniquenessRequestControl

        public UniquenessRequestControl​(boolean isCritical,
                                        @Nullable
                                        java.lang.String uniquenessID,
                                        @NotNull
                                        UniquenessRequestControlProperties properties)
                                 throws LDAPException
        Creates a new uniqueness request control with the provided information.
        Parameters:
        isCritical - Indicates whether the control should be considered critical.
        uniquenessID - A value that will be used to correlate this request control with its corresponding response control. If this is null, then a unique identifier will be automatically generated.
        properties - The set of properties for this control. It must not be null.
        Throws:
        LDAPException - If the provided properties cannot be used to create a valid uniqueness request control.
      • UniquenessRequestControl

        public UniquenessRequestControl​(@NotNull
                                        Control control)
                                 throws LDAPException
        Creates a new uniqueness request control that is decoded from the provided generic control.
        Parameters:
        control - The control to be decoded as a uniqueness request control. It must not be null.
        Throws:
        LDAPException - If the provided control cannot be decoded as a valid uniqueness request control.
    • Method Detail

      • getUniquenessID

        @NotNull
        public java.lang.String getUniquenessID()
        Retrieves the uniqueness identifier for this control, which may be used to identify the response control that corresponds to this request control. This is primarily useful for requests that contain multiple uniqueness controls, as there may be a separate response control for each.
        Returns:
        The uniqueness identifier for this control.
      • getAttributeTypes

        @NotNull
        public java.util.Set<java.lang.String> getAttributeTypes()
        Retrieves the set of attribute types that the server will check for uniqueness conflicts.
        Returns:
        The set of attribute types that the server will check for uniqueness conflicts, or an empty set if only a filter should be used to identify conflicts.
      • getBaseDN

        @Nullable
        public java.lang.String getBaseDN()
        Retrieves the base DN that will be used for searches used to identify uniqueness conflicts, if defined.
        Returns:
        The base DN that will be used for searches used to identify uniqueness conflicts, or null if the server should search below all public naming contexts.
      • getFilter

        @Nullable
        public Filter getFilter()
        Retrieves a filter that will be used to identify uniqueness conflicts, if defined.
        Returns:
        A filter that will be used to identify uniqueness conflicts, or null if no filter has been defined.
      • preventConflictsWithSoftDeletedEntries

        public boolean preventConflictsWithSoftDeletedEntries()
        Indicates whether the server should attempt to identify conflicts with soft-deleted entries.
        Returns:
        true if the server should identify conflicts with both regular entries and soft-deleted entries, or false if the server should only identify conflicts with regular entries.
      • getPostCommitValidationLevel

        @NotNull
        public UniquenessValidationLevel getPostCommitValidationLevel()
        Retrieves the post-commit validation level, which will be used to identify any conflicts that were introduced by the request with which the control is associated, or by some other concurrent changed processed in the server.
        Returns:
        The post-commit validation level.
      • alertOnPostCommitConflictDetection

        public boolean alertOnPostCommitConflictDetection()
        Indicates whether the server should raise an administrative alert if a conflict is detected during post-commit validation processing.
        Returns:
        true if the server should raise an administrative alert if a conflict is detected during post-commit validation processing, or false if not.
      • createConflictPreventionDetailsEntry

        public boolean createConflictPreventionDetailsEntry()
        Indicates whether the server should create a temporary conflict prevention details entry before beginning pre-commit validation to provide better support for preventing conflicts. If created, the entry will be removed after post-commit validation processing has completed.
        Returns:
        true if the server should create a temporary conflict prevention details entry before beginning pre-commit validation, or false if not.
      • getControlName

        @NotNull
        public java.lang.String getControlName()
        Retrieves the user-friendly name for this control, if available. If no user-friendly name has been defined, then the OID will be returned.
        Overrides:
        getControlName in class Control
        Returns:
        The user-friendly name for this control, or the OID if no user-friendly name is available.
      • toJSONControl

        @NotNull
        public JSONObject toJSONControl()
        Retrieves a representation of this uniqueness request control as a JSON object. The JSON object uses the following fields:
        • oid -- A mandatory string field whose value is the object identifier for this control. For the uniqueness request control, the OID is "1.3.6.1.4.1.30221.2.5.52".
        • control-name -- An optional string field whose value is a human-readable name for this control. This field is only intended for descriptive purposes, and when decoding a control, the oid field should be used to identify the type of control.
        • criticality -- A mandatory Boolean field used to indicate whether this control is considered critical.
        • value-base64 -- An optional string field whose value is a base64-encoded representation of the raw value for this uniqueness request control. Exactly one of the value-base64 and value-json fields must be present.
        • value-json -- An optional JSON object field whose value is a user-friendly representation of the value for this uniqueness request control. Exactly one of the value-base64 and value-json fields must be present, and if the value-json field is used, then it will use the following fields:
          • uniqueness-id -- An optional string field that holds a unique identifier for this uniqueness control instance.
          • attribute-types -- An optional array field whose values are the names of the attribute types for which to impose uniqueness. It may be empty or absent if uniqueness should only be enforced using a filter.
          • multiple-attribute-behavior -- An optional string field whose value indicates the behavior that should be used if multiple unique attribute types are requested. If present, the value should be one of "unique-within-each-attribute", "unique-across-all-attributes-including-in-the-same-entry", "unique-across-all-attributes-except-in-the-same-entry", or "unique-in-combination".
          • base-dn -- An optional string field whose value is the base DN that will be used for searches used to identify uniqueness conflicts.
          • filter -- An optional string field whose value is the string representation of a search filter that will be used to identify uniqueness conflicts.
          • prevent-conflicts-with-soft-deleted-entries -- An optional Boolean field that indicates whether the server should consider soft-deleted entries when looking for conflicts.
          • pre-commit-validation-level -- A mandatory string field whose value specifies the level of validation that the server should perform before attempting to apply the change. The value must be one of "none", "all-subtree-views", "all-backend-sets", or "all-available-backend-servers".
          • post-commit-validation-level -- A mandatory string field whose value specifies the level of validation that the server should perform after applying the change. The value must be one of "none", "all-subtree-views", "all-backend-sets", or "all-available-backend-servers".
          • alert-on-post-commit-conflict-detection -- An optional Boolean field that indicates whether the server should raise an administrative alert if a conflict was detected after the change was applied.
          • create-conflict-prevention-details-entry -- An optional Boolean field that indicates whether the server should create a temporary entry that can improve its ability to detect conflicts before they happen.
        Overrides:
        toJSONControl in class Control
        Returns:
        A JSON object that contains a representation of this control.
      • decodeJSONControl

        @NotNull
        public static UniquenessRequestControl decodeJSONControl​(@NotNull
                                                                 JSONObject controlObject,
                                                                 boolean strict)
                                                          throws LDAPException
        Attempts to decode the provided object as a JSON representation of a uniqueness request control.
        Parameters:
        controlObject - The JSON object to be decoded. It must not be null.
        strict - Indicates whether to use strict mode when decoding the provided JSON object. If this is true, then this method will throw an exception if the provided JSON object contains any unrecognized fields. If this is false, then unrecognized fields will be ignored.
        Returns:
        The uniqueness request control that was decoded from the provided JSON object.
        Throws:
        LDAPException - If the provided JSON object cannot be parsed as a valid uniqueness request control.
      • toString

        public void toString​(@NotNull
                             java.lang.StringBuilder buffer)
        Appends a string representation of this LDAP control to the provided buffer.
        Overrides:
        toString in class Control
        Parameters:
        buffer - The buffer to which to append the string representation of this buffer.