com.unboundid.ldap.sdk.unboundidds.extensions.GetChangelogBatchExtendedRequest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unboundid-ldapsdk Show documentation
Show all versions of unboundid-ldapsdk Show documentation
The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use
Java API for communicating with LDAP directory servers and performing
related tasks like reading and writing LDIF, encoding and decoding data
using base64 and ASN.1 BER, and performing secure communication. This
package contains the Standard Edition of the LDAP SDK, which is a
complete, general-purpose library for communicating with LDAPv3 directory
servers.
/*
* Copyright 2010-2023 Ping Identity Corporation
* All Rights Reserved.
*/
/*
* Copyright 2010-2023 Ping Identity Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2010-2023 Ping Identity Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPLv2 only)
* or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
package com.unboundid.ldap.sdk.unboundidds.extensions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import com.unboundid.asn1.ASN1Boolean;
import com.unboundid.asn1.ASN1Element;
import com.unboundid.asn1.ASN1Enumerated;
import com.unboundid.asn1.ASN1Integer;
import com.unboundid.asn1.ASN1Long;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.asn1.ASN1Sequence;
import com.unboundid.asn1.ASN1Set;
import com.unboundid.ldap.sdk.ChangeType;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.ExtendedRequest;
import com.unboundid.ldap.sdk.ExtendedResult;
import com.unboundid.ldap.sdk.IntermediateResponseListener;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.Debug;
import com.unboundid.util.NotMutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;
import com.unboundid.util.Validator;
import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
/**
* This class provides an implementation of an extended request which may be
* used to retrieve a batch of changes from a Directory Server.
*
*
* NOTE: This class, and other classes within the
* {@code 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 changelog batch request value is encoded as follows:
*
* ChangelogBatchRequest ::= SEQUENCE {
* startingPoint CHOICE {
* resumeWithToken [0] OCTET STRING,
* resumeWithCSN [1] OCTET STRING,
* beginningOfChangelog [2] NULL,
* endOfChangelog [3] NULL,
* changeTime [4] OCTET STRING,
* ... },
* maxChanges INTEGER (0 .. maxInt),
* maxTimeMillis [0] INTEGER DEFAULT 0,
* waitForMaxChanges [1] BOOLEAN DEFAULT FALSE,
* includeBase [2] SEQUENCE OF LDAPDN OPTIONAL,
* excludeBase [3] SEQUENCE OF LDAPDN OPTIONAL,
* changeTypes [4] SET OF ENUMERATED {
* add (0),
* delete (1),
* modify (2),
* modifyDN (3) } OPTIONAL,
* continueOnMissingChanges [5] BOOLEAN DEFAULT FALSE,
* pareEntriesForUserDN [6] LDAPDN OPTIONAL,
* changeSelectionCriteria [7] CHOICE {
* anyAttributes [1] SEQUENCE OF LDAPString,
* allAttributes [2] SEQUENCE OF LDAPString,
* ignoreAttributes [3] SEQUENCE {
* ignoreAttributes SEQUENCE OF LDAPString
* ignoreOperationalAttributes BOOLEAN,
* ... },
* notificationDestination [4] OCTET STRING,
* ... } OPTIONAL,
* includeSoftDeletedEntryMods [8] BOOLEAN DEFAULT FALSE,
* includeSoftDeletedEntryDeletes [9] BOOLEAN DEFAULT FALSE,
* ... }
*
*
* Example
* The following example demonstrates the use of the get changelog batch to
* iterate across all entries in the changelog. It will operate in an infinite
* loop, starting at the beginning of the changelog and then reading 1000
* entries at a time until all entries have been read. Once the end of the
* changelog has been reached, it will continue looking for changes, waiting for
* up to 5 seconds for new changes to arrive.
*
* ChangelogBatchStartingPoint startingPoint =
* new BeginningOfChangelogStartingPoint();
* while (true)
* {
* GetChangelogBatchExtendedRequest request =
* new GetChangelogBatchExtendedRequest(startingPoint, 1000, 5000L);
*
* GetChangelogBatchExtendedResult result =
* (GetChangelogBatchExtendedResult)
* connection.processExtendedOperation(request);
* List<ChangelogEntryIntermediateResponse> changelogEntries =
* result.getChangelogEntries();
*
* startingPoint = new ResumeWithTokenStartingPoint(result.getResumeToken());
* }
*
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class GetChangelogBatchExtendedRequest
extends ExtendedRequest
{
/**
* The OID (1.3.6.1.4.1.30221.2.6.10) for the get changelog batch extended
* request.
*/
@NotNull public static final String GET_CHANGELOG_BATCH_REQUEST_OID =
"1.3.6.1.4.1.30221.2.6.10";
/**
* The BER type for the maxTimeMillis element.
*/
private static final byte TYPE_MAX_TIME = (byte) 0x80;
/**
* The BER type for the returnOnAvailableChanges element.
*/
private static final byte TYPE_WAIT_FOR_MAX_CHANGES = (byte) 0x81;
/**
* The BER type for the includeBase element.
*/
private static final byte TYPE_INCLUDE_BASE = (byte) 0xA2;
/**
* The BER type for the excludeBase element.
*/
private static final byte TYPE_EXCLUDE_BASE = (byte) 0xA3;
/**
* The BER type for the changeTypes element.
*/
private static final byte TYPE_CHANGE_TYPES = (byte) 0xA4;
/**
* The BER type for the continueOnMissingChanges element.
*/
private static final byte TYPE_CONTINUE_ON_MISSING_CHANGES = (byte) 0x85;
/**
* The BER type for the pareEntriesForUserDN element.
*/
private static final byte TYPE_PARE_ENTRIES_FOR_USER_DN = (byte) 0x86;
/**
* The BER type for the includeSoftDeletedEntryMods element.
*/
private static final byte TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS = (byte) 0x88;
/**
* The BER type for the includeSoftDeletedEntryDeletes element.
*/
private static final byte TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES =
(byte) 0x89;
/**
* The value for a change type of add.
*/
private static final int CHANGE_TYPE_ADD = 0;
/**
* The value for a change type of delete.
*/
private static final int CHANGE_TYPE_DELETE = 1;
/**
* The value for a change type of modify.
*/
private static final int CHANGE_TYPE_MODIFY = 2;
/**
* The value for a change type of modify DN.
*/
private static final int CHANGE_TYPE_MODIFY_DN = 3;
/**
* The serial version UID for this serializable class.
*/
private static final long serialVersionUID = 3270898150012821635L;
// Indicates whether to attempt to return changes even if the start point
// references changes which may have already been purged from the changelog.
private final boolean continueOnMissingChanges;
// Indicates whether deletes to soft-deleted entries should be included in the
// result set.
private final boolean includeSoftDeletedEntryDeletes;
// Indicates whether modifications of soft-deleted entries should be included
// in the result set.
private final boolean includeSoftDeletedEntryMods;
// Indicates whether the server should wait for up to the specified time limit
// for up to the the maximum number of changes to be returned, or whether it
// should return as soon as there are any results available.
private final boolean waitForMaxChanges;
// The change selection criteria for the request, if any.
@Nullable private final ChangelogBatchChangeSelectionCriteria
changeSelectionCriteria;
// The starting point for the batch of changes to retrieve.
@NotNull private final ChangelogBatchStartingPoint startingPoint;
// The entry listener for this request.
@Nullable private final ChangelogEntryListener entryListener;
// The maximum number of changes to retrieve in the batch.
private final int maxChanges;
// The list of base DNs for entries to exclude from the results.
@NotNull private final List excludeBaseDNs;
// The list of base DNs for entries to include in the results.
@NotNull private final List includeBaseDNs;
// The maximum length of time in milliseconds to wait for changes to become
// available.
private final long maxWaitTimeMillis;
// The set of change types for changes to include in the results.
@NotNull private final Set changeTypes;
// The DN of a user for whom to pare down the contents of changelog entries
// based on access control and sensitive attribute restrictions, if defined.
@Nullable private final String pareEntriesForUserDN;
/**
* Creates a new get changelog batch extended request with the provided
* information. It will include all changes processed anywhere in the server,
* and will request that the result be returned as soon as any changes are
* available.
*
* @param startingPoint An object which indicates the starting point for
* the batch of changes to retrieve. It must not
* be {@code null}.
* @param maxChanges The maximum number of changes that should be
* retrieved before the server should return the
* corresponding extended result. A value less
* than or equal to zero may be used to indicate
* that the server should not return any entries
* but should just return a result containing a
* token which represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in milliseconds to
* wait for changes. A value less than or equal to
* zero indicates that there should not be any wait
* and the result should be returned as soon as all
* immediately-available changes (up to the
* specified maximum count) have been returned.
* @param controls The set of controls to include in the request.
* It may be {@code null} or empty if there should
* be no controls.
*/
public GetChangelogBatchExtendedRequest(
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
@Nullable final Control... controls)
{
this(null, startingPoint, maxChanges, maxWaitTimeMillis, false, null, null,
null, false, null, null, false, false, controls);
}
/**
* Creates a new get changelog batch extended request with the provided
* information. It will include all changes processed anywhere in the server,
* and will request that the result be returned as soon as any changes are
* available.
*
* @param entryListener The listener that will be notified of any
* changelog entries (or other types of
* intermediate response) returned during the
* course of processing this request. It may be
* {@code null} if changelog entries should be
* collected and made available in the extended
* result.
* @param startingPoint An object which indicates the starting point for
* the batch of changes to retrieve. It must not
* be {@code null}.
* @param maxChanges The maximum number of changes that should be
* retrieved before the server should return the
* corresponding extended result. A value less
* than or equal to zero may be used to indicate
* that the server should not return any entries
* but should just return a result containing a
* token which represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in milliseconds to
* wait for changes. A value less than or equal to
* zero indicates that there should not be any wait
* and the result should be returned as soon as all
* immediately-available changes (up to the
* specified maximum count) have been returned.
* @param controls The set of controls to include in the request.
* It may be {@code null} or empty if there should
* be no controls.
*/
public GetChangelogBatchExtendedRequest(
@Nullable final ChangelogEntryListener entryListener,
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
@Nullable final Control... controls)
{
this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis, false,
null, null, null, false, null, null, false, false, controls);
}
/**
* Creates a new get changelog batch extended request with the provided
* information.
*
* @param startingPoint An object which indicates the starting
* point for the batch of changes to
* retrieve. It must not be {@code null}.
* @param maxChanges The maximum number of changes that should
* be retrieved before the server should
* return the corresponding extended result.
* A value less than or equal to zero may be
* used to indicate that the server should
* not return any entries but should just
* return a result containing a token which
* represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in
* milliseconds to wait for changes. A
* value less than or equal to zero
* indicates that there should not be any
* wait and the result should be returned as
* soon as all immediately-available changes
* (up to the specified maximum count) have
* been returned.
* @param waitForMaxChanges Indicates whether the server should wait
* for up to the maximum length of time for
* up to the maximum number of changes to be
* returned. If this is {@code false}, then
* the result will be returned as soon as
* any changes are available (after sending
* those changes), even if the number of
* available changes is less than
* {@code maxChanges}. Otherwise, the
* result will not be returned until either
* the maximum number of changes have been
* returned or the maximum wait time has
* elapsed.
* @param includeBaseDNs A list of base DNs for entries to include
* in the set of changes to be returned.
* @param excludeBaseDNs A list of base DNs for entries to exclude
* from the set of changes to be returned.
* @param changeTypes The types of changes that should be
* returned. If this is {@code null} or
* empty, then all change types will be
* included.
* @param continueOnMissingChanges Indicates whether the server should make
* a best-effort attempt to return changes
* even if the starting point represents a
* point that is before the first available
* change in the changelog and therefore the
* results returned may be missing changes.
* @param controls The set of controls to include in the
* request. It may be {@code null} or empty
* if there should be no controls.
*/
public GetChangelogBatchExtendedRequest(
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
final boolean waitForMaxChanges,
@Nullable final List includeBaseDNs,
@Nullable final List excludeBaseDNs,
@Nullable final Set changeTypes,
final boolean continueOnMissingChanges,
@Nullable final Control... controls)
{
this(null, startingPoint, maxChanges, maxWaitTimeMillis, waitForMaxChanges,
includeBaseDNs, excludeBaseDNs, changeTypes, continueOnMissingChanges,
null, null, false, false, controls);
}
/**
* Creates a new get changelog batch extended request with the provided
* information.
*
* @param entryListener The listener that will be notified of any
* changelog entries (or other types of
* intermediate response) returned during
* the course of processing this request.
* It may be {@code null} if changelog
* entries should be collected and made
* available in the extended result.
* @param startingPoint An object which indicates the starting
* point for the batch of changes to
* retrieve. It must not be {@code null}.
* @param maxChanges The maximum number of changes that should
* be retrieved before the server should
* return the corresponding extended result.
* A value less than or equal to zero may be
* used to indicate that the server should
* not return any entries but should just
* return a result containing a token which
* represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in
* milliseconds to wait for changes. A
* value less than or equal to zero
* indicates that there should not be any
* wait and the result should be returned as
* soon as all immediately-available changes
* (up to the specified maximum count) have
* been returned.
* @param waitForMaxChanges Indicates whether the server should wait
* for up to the maximum length of time for
* up to the maximum number of changes to be
* returned. If this is {@code false}, then
* the result will be returned as soon as
* any changes are available (after sending
* those changes), even if the number of
* available changes is less than
* {@code maxChanges}. Otherwise, the
* result will not be returned until either
* the maximum number of changes have been
* returned or the maximum wait time has
* elapsed.
* @param includeBaseDNs A list of base DNs for entries to include
* in the set of changes to be returned.
* @param excludeBaseDNs A list of base DNs for entries to exclude
* from the set of changes to be returned.
* @param changeTypes The types of changes that should be
* returned. If this is {@code null} or
* empty, then all change types will be
* included.
* @param continueOnMissingChanges Indicates whether the server should make
* a best-effort attempt to return changes
* even if the starting point represents a
* point that is before the first available
* change in the changelog and therefore the
* results returned may be missing changes.
* @param controls The set of controls to include in the
* request. It may be {@code null} or empty
* if there should be no controls.
*/
public GetChangelogBatchExtendedRequest(
@Nullable final ChangelogEntryListener entryListener,
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
final boolean waitForMaxChanges,
@Nullable final List includeBaseDNs,
@Nullable final List excludeBaseDNs,
@Nullable final Set changeTypes,
final boolean continueOnMissingChanges,
@Nullable final Control... controls)
{
this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis,
waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
continueOnMissingChanges, null, null, false, false, controls);
}
/**
* Creates a new get changelog batch extended request with the provided
* information.
*
* @param entryListener The listener that will be notified of any
* changelog entries (or other types of
* intermediate response) returned during
* the course of processing this request.
* It may be {@code null} if changelog
* entries should be collected and made
* available in the extended result.
* @param startingPoint An object which indicates the starting
* point for the batch of changes to
* retrieve. It must not be {@code null}.
* @param maxChanges The maximum number of changes that should
* be retrieved before the server should
* return the corresponding extended result.
* A value less than or equal to zero may be
* used to indicate that the server should
* not return any entries but should just
* return a result containing a token which
* represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in
* milliseconds to wait for changes. A
* value less than or equal to zero
* indicates that there should not be any
* wait and the result should be returned as
* soon as all immediately-available changes
* (up to the specified maximum count) have
* been returned.
* @param waitForMaxChanges Indicates whether the server should wait
* for up to the maximum length of time for
* up to the maximum number of changes to be
* returned. If this is {@code false}, then
* the result will be returned as soon as
* any changes are available (after sending
* those changes), even if the number of
* available changes is less than
* {@code maxChanges}. Otherwise, the
* result will not be returned until either
* the maximum number of changes have been
* returned or the maximum wait time has
* elapsed.
* @param includeBaseDNs A list of base DNs for entries to include
* in the set of changes to be returned.
* @param excludeBaseDNs A list of base DNs for entries to exclude
* from the set of changes to be returned.
* @param changeTypes The types of changes that should be
* returned. If this is {@code null} or
* empty, then all change types will be
* included.
* @param continueOnMissingChanges Indicates whether the server should make
* a best-effort attempt to return changes
* even if the starting point represents a
* point that is before the first available
* change in the changelog and therefore the
* results returned may be missing changes.
* @param pareEntriesForUserDN The DN of a user for whom to pare down
* the contents of changelog entries based
* on the access control and sensitive
* attribute restrictions defined for that
* user. It may be {@code null} if
* changelog entries should not be pared
* down for any user, an empty string if
* changelog entries should be pared down to
* what is available to anonymous users, or
* a user DN to pare down entries for the
* specified user.
* @param changeSelectionCriteria The optional criteria to use to pare down
* the changelog entries that should be
* returned. It may be {@code null} if all
* changelog entries should be returned.
* @param controls The set of controls to include in the
* request. It may be {@code null} or empty
* if there should be no controls.
*/
public GetChangelogBatchExtendedRequest(
@Nullable final ChangelogEntryListener entryListener,
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
final boolean waitForMaxChanges,
@Nullable final List includeBaseDNs,
@Nullable final List excludeBaseDNs,
@Nullable final Set changeTypes,
final boolean continueOnMissingChanges,
@Nullable final String pareEntriesForUserDN,
@Nullable final ChangelogBatchChangeSelectionCriteria
changeSelectionCriteria,
@Nullable final Control... controls)
{
this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis,
waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
continueOnMissingChanges, pareEntriesForUserDN,
changeSelectionCriteria, false, false, controls);
}
/**
* Creates a new get changelog batch extended request with the provided
* information.
*
* @param entryListener The listener that will be notified
* of any changelog entries (or other
* types of intermediate response)
* returned during the course of
* processing this request. It may be
* {@code null} if changelog entries
* should be collected and made
* available in the extended result.
* @param startingPoint An object which indicates the
* starting point for the batch of
* changes to retrieve. It must not
* be {@code null}.
* @param maxChanges The maximum number of changes that
* should be retrieved before the
* server should return the
* corresponding extended result. A
* value less than or equal to zero
* may be used to indicate that the
* server should not return any
* entries but should just return a
* result containing a token which
* represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in
* milliseconds to wait for changes.
* A value less than or equal to zero
* indicates that there should not be
* any wait and the result should be
* returned as soon as all
* immediately-available changes (up
* to the specified maximum count)
* have been returned.
* @param waitForMaxChanges Indicates whether the server should
* wait for up to the maximum length
* of time for up to the maximum
* number of changes to be returned.
* If this is {@code false}, then the
* result will be returned as soon as
* any changes are available (after
* sending those changes), even if the
* number of available changes is less
* than {@code maxChanges}.
* Otherwise, the result will not be
* returned until either the maximum
* number of changes have been
* returned or the maximum wait time
* has elapsed.
* @param includeBaseDNs A list of base DNs for entries to
* include in the set of changes to be
* returned.
* @param excludeBaseDNs A list of base DNs for entries to
* exclude from the set of changes to
* be returned.
* @param changeTypes The types of changes that should be
* returned. If this is {@code null}
* or empty, then all change types
* will be included.
* @param continueOnMissingChanges Indicates whether the server should
* make a best-effort attempt to
* return changes even if the starting
* point represents a point that is
* before the first available change
* in the changelog and therefore the
* results returned may be missing
* changes.
* @param pareEntriesForUserDN The DN of a user for whom to pare
* down the contents of changelog
* entries based on the access control
* and sensitive attribute
* restrictions defined for that user.
* It may be {@code null} if changelog
* entries should not be pared down
* for any user, an empty string if
* changelog entries should be pared
* down to what is available to
* anonymous users, or a user DN to
* pare down entries for the specified
* user.
* @param changeSelectionCriteria The optional criteria to use to
* pare down the changelog entries
* that should be returned. It may be
* {@code null} if all changelog
* entries should be returned.
* @param includeSoftDeletedEntryMods Indicates whether to include
* changelog entries that represent
* changes to soft-deleted entries.
* @param includeSoftDeletedEntryDeletes Indicates whether to include
* changelog entries that represent
* deletes of soft-deleted entries.
* @param controls The set of controls to include in
* the request. It may be
* {@code null} or empty if there
* should be no controls.
*/
public GetChangelogBatchExtendedRequest(
@Nullable final ChangelogEntryListener entryListener,
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
final boolean waitForMaxChanges,
@Nullable final List includeBaseDNs,
@Nullable final List excludeBaseDNs,
@Nullable final Set changeTypes,
final boolean continueOnMissingChanges,
@Nullable final String pareEntriesForUserDN,
@Nullable final ChangelogBatchChangeSelectionCriteria
changeSelectionCriteria,
final boolean includeSoftDeletedEntryMods,
final boolean includeSoftDeletedEntryDeletes,
@Nullable final Control... controls)
{
super(GET_CHANGELOG_BATCH_REQUEST_OID,
encodeValue(startingPoint, maxChanges, maxWaitTimeMillis,
waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
continueOnMissingChanges, pareEntriesForUserDN,
changeSelectionCriteria, includeSoftDeletedEntryMods,
includeSoftDeletedEntryDeletes),
controls);
this.entryListener = entryListener;
this.startingPoint = startingPoint;
this.maxWaitTimeMillis = maxWaitTimeMillis;
this.waitForMaxChanges = waitForMaxChanges;
this.continueOnMissingChanges = continueOnMissingChanges;
this.pareEntriesForUserDN = pareEntriesForUserDN;
this.changeSelectionCriteria = changeSelectionCriteria;
this.includeSoftDeletedEntryMods = includeSoftDeletedEntryMods;
this.includeSoftDeletedEntryDeletes = includeSoftDeletedEntryDeletes;
if (maxChanges <= 0)
{
this.maxChanges = 0;
}
else
{
this.maxChanges = maxChanges;
}
if (includeBaseDNs == null)
{
this.includeBaseDNs = Collections.emptyList();
}
else
{
this.includeBaseDNs = Collections.unmodifiableList(includeBaseDNs);
}
if (excludeBaseDNs == null)
{
this.excludeBaseDNs = Collections.emptyList();
}
else
{
this.excludeBaseDNs = Collections.unmodifiableList(excludeBaseDNs);
}
if ((changeTypes == null) || changeTypes.isEmpty())
{
this.changeTypes =
Collections.unmodifiableSet(EnumSet.allOf(ChangeType.class));
}
else
{
this.changeTypes = Collections.unmodifiableSet(changeTypes);
}
}
/**
* Creates a new get changelog batch extended request from the provided
* generic extended request.
*
* @param extendedRequest The generic extended request to be decoded as a
* get changelog batch extended request.
*
* @throws LDAPException If the provided generic request cannot be decoded
* as a get changelog batch extended request.
*/
public GetChangelogBatchExtendedRequest(
@NotNull final ExtendedRequest extendedRequest)
throws LDAPException
{
super(extendedRequest.getOID(), extendedRequest.getValue(),
extendedRequest.getControls());
final ASN1OctetString value = extendedRequest.getValue();
if (value == null)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_NO_VALUE.get());
}
final ASN1Sequence valueSequence;
try
{
valueSequence = ASN1Sequence.decodeAsSequence(value.getValue());
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_VALUE_NOT_SEQUENCE.get(
StaticUtils.getExceptionMessage(e)), e);
}
final ASN1Element[] elements = valueSequence.elements();
if (elements.length < 2)
{
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_TOO_FEW_ELEMENTS.get());
}
try
{
startingPoint = ChangelogBatchStartingPoint.decode(elements[0]);
final int mc = ASN1Integer.decodeAsInteger(elements[1]).intValue();
if (mc > 0)
{
maxChanges = mc;
}
else
{
maxChanges = 0;
}
boolean waitForMax = false;
long maxTime = 0L;
List includeBase = Collections.emptyList();
List excludeBase = Collections.emptyList();
Set types =
Collections.unmodifiableSet(EnumSet.allOf(ChangeType.class));
boolean continueOnMissing = false;
String pareForDN = null;
ChangelogBatchChangeSelectionCriteria changeCriteria = null;
boolean includeSDMods = false;
boolean includeSDDeletes = false;
for (int i=2; i < elements.length; i++)
{
switch (elements[i].getType())
{
case TYPE_MAX_TIME:
maxTime = ASN1Long.decodeAsLong(elements[i]).longValue();
if (maxTime < 0L)
{
maxTime = 0L;
}
break;
case TYPE_WAIT_FOR_MAX_CHANGES:
waitForMax =
ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
break;
case TYPE_INCLUDE_BASE:
final ASN1Element[] includeElements =
ASN1Sequence.decodeAsSequence(elements[i]).elements();
final ArrayList includeList =
new ArrayList<>(includeElements.length);
for (final ASN1Element e : includeElements)
{
includeList.add(
ASN1OctetString.decodeAsOctetString(e).stringValue());
}
includeBase = Collections.unmodifiableList(includeList);
break;
case TYPE_EXCLUDE_BASE:
final ASN1Element[] excludeElements =
ASN1Sequence.decodeAsSequence(elements[i]).elements();
final ArrayList excludeList =
new ArrayList<>(excludeElements.length);
for (final ASN1Element e : excludeElements)
{
excludeList.add(
ASN1OctetString.decodeAsOctetString(e).stringValue());
}
excludeBase = Collections.unmodifiableList(excludeList);
break;
case TYPE_CHANGE_TYPES:
final EnumSet ctSet = EnumSet.noneOf(ChangeType.class);
for (final ASN1Element e :
ASN1Set.decodeAsSet(elements[i]).elements())
{
final int v = ASN1Enumerated.decodeAsEnumerated(e).intValue();
switch (v)
{
case CHANGE_TYPE_ADD:
ctSet.add(ChangeType.ADD);
break;
case CHANGE_TYPE_DELETE:
ctSet.add(ChangeType.DELETE);
break;
case CHANGE_TYPE_MODIFY:
ctSet.add(ChangeType.MODIFY);
break;
case CHANGE_TYPE_MODIFY_DN:
ctSet.add(ChangeType.MODIFY_DN);
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_VALUE_UNRECOGNIZED_CT.get(
v));
}
}
types = Collections.unmodifiableSet(ctSet);
break;
case TYPE_CONTINUE_ON_MISSING_CHANGES:
continueOnMissing =
ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
break;
case TYPE_PARE_ENTRIES_FOR_USER_DN:
pareForDN =
ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
break;
case ChangelogBatchChangeSelectionCriteria.TYPE_SELECTION_CRITERIA:
changeCriteria =
ChangelogBatchChangeSelectionCriteria.decode(elements[i]);
break;
case TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS:
includeSDMods =
ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
break;
case TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES:
includeSDDeletes =
ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
break;
default:
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_VALUE_UNRECOGNIZED_TYPE.get(
StaticUtils.toHex(elements[i].getType())));
}
}
entryListener = null;
maxWaitTimeMillis = maxTime;
waitForMaxChanges = waitForMax;
includeBaseDNs = includeBase;
excludeBaseDNs = excludeBase;
changeTypes = types;
continueOnMissingChanges = continueOnMissing;
pareEntriesForUserDN = pareForDN;
changeSelectionCriteria = changeCriteria;
includeSoftDeletedEntryMods = includeSDMods;
includeSoftDeletedEntryDeletes = includeSDDeletes;
}
catch (final LDAPException le)
{
Debug.debugException(le);
throw le;
}
catch (final Exception e)
{
Debug.debugException(e);
throw new LDAPException(ResultCode.DECODING_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_ERROR_DECODING_VALUE.get(
StaticUtils.getExceptionMessage(e)), e);
}
}
/**
* Encodes the value for this extended request using the provided information.
*
* @param startingPoint An object which indicates the
* starting point for the batch of
* changes to retrieve. It must not
* be {@code null}.
* @param maxChanges The maximum number of changes that
* should be retrieved before the
* server should return the
* corresponding extended result. A
* value less than or equal to zero
* may be used to indicate that the
* server should not return any
* entries but should just return a
* result containing a token which
* represents the starting point.
* @param maxWaitTimeMillis The maximum length of time in
* milliseconds to wait for changes.
* A value less than or equal to zero
* indicates that there should not be
* any wait and the result should be
* returned as soon as all
* immediately-available changes (up
* to the specified maximum count)
* have been returned.
* @param waitForMaxChanges Indicates whether the server should
* wait for up to the maximum length
* of time for up to the maximum
* number of changes to be returned.
* If this is {@code false}, then the
* result will be returned as soon as
* any changes are available (after
* sending those changes), even if the
* number of available changes is less
* than {@code maxChanges}.
* Otherwise, the result will not be
* returned until either the maximum
* number of changes have been
* returned or the maximum wait time
* has elapsed.
* @param includeBaseDNs A list of base DNs for entries to
* include in the set of changes to be
* returned.
* @param excludeBaseDNs A list of base DNs for entries to
* exclude from the set of changes to
* be returned.
* @param changeTypes The types of changes that should be
* returned. If this is {@code null}
* or empty, then all change types
* will be included.
* @param continueOnMissingChanges Indicates whether the server should
* make a best-effort attempt to
* return changes even if the starting
* point represents a point that is
* before the first available change
* in the changelog and therefore the
* results returned may be missing
* changes.
* @param pareEntriesForUserDN The DN of a user for whom to pare
* down the contents of changelog
* entries based on the access control
* and sensitive attribute
* restrictions defined for that user.
* It may be {@code null} if changelog
* entries should not be pared down
* for any user, an empty string if
* changelog entries should be pared
* down to what is available to
* anonymous users, or a user DN to
* pare down entries for the specified
* user.
* @param changeSelectionCriteria The optional criteria to use to
* pare down the changelog entries
* that should be returned. It may be
* {@code null} if all changelog
* entries should be returned.
* @param includeSoftDeletedEntryMods Indicates whether to include
* changelog entries that represent
* changes to soft-deleted entries.
* @param includeSoftDeletedEntryDeletes Indicates whether to include
* changelog entries that represent
* deletes of soft-deleted entries.
*
* @return The value for the extended request.
*/
@NotNull()
private static ASN1OctetString encodeValue(
@NotNull final ChangelogBatchStartingPoint startingPoint,
final int maxChanges, final long maxWaitTimeMillis,
final boolean waitForMaxChanges,
@Nullable final List includeBaseDNs,
@Nullable final List excludeBaseDNs,
@Nullable final Set changeTypes,
final boolean continueOnMissingChanges,
@Nullable final String pareEntriesForUserDN,
@Nullable final ChangelogBatchChangeSelectionCriteria
changeSelectionCriteria,
final boolean includeSoftDeletedEntryMods,
final boolean includeSoftDeletedEntryDeletes)
{
Validator.ensureNotNull(startingPoint);
final ArrayList elements = new ArrayList<>(12);
elements.add(startingPoint.encode());
if (maxChanges > 0)
{
elements.add(new ASN1Integer(maxChanges));
}
else
{
elements.add(new ASN1Integer(0));
}
if (maxWaitTimeMillis > 0L)
{
elements.add(new ASN1Long(TYPE_MAX_TIME, maxWaitTimeMillis));
}
if (waitForMaxChanges)
{
elements.add(new ASN1Boolean(TYPE_WAIT_FOR_MAX_CHANGES, true));
}
if ((includeBaseDNs != null) && (! includeBaseDNs.isEmpty()))
{
final ArrayList l = new ArrayList<>(includeBaseDNs.size());
for (final String s : includeBaseDNs)
{
l.add(new ASN1OctetString(s));
}
elements.add(new ASN1Sequence(TYPE_INCLUDE_BASE, l));
}
if ((excludeBaseDNs != null) && (! excludeBaseDNs.isEmpty()))
{
final ArrayList l = new ArrayList<>(excludeBaseDNs.size());
for (final String s : excludeBaseDNs)
{
l.add(new ASN1OctetString(s));
}
elements.add(new ASN1Sequence(TYPE_EXCLUDE_BASE, l));
}
if ((changeTypes != null) && (! changeTypes.isEmpty()) &&
(! changeTypes.equals(EnumSet.allOf(ChangeType.class))))
{
final ArrayList l = new ArrayList<>(changeTypes.size());
for (final ChangeType t : changeTypes)
{
switch (t)
{
case ADD:
l.add(new ASN1Enumerated(CHANGE_TYPE_ADD));
break;
case DELETE:
l.add(new ASN1Enumerated(CHANGE_TYPE_DELETE));
break;
case MODIFY:
l.add(new ASN1Enumerated(CHANGE_TYPE_MODIFY));
break;
case MODIFY_DN:
l.add(new ASN1Enumerated(CHANGE_TYPE_MODIFY_DN));
break;
}
}
elements.add(new ASN1Set(TYPE_CHANGE_TYPES, l));
}
if (continueOnMissingChanges)
{
elements.add(new ASN1Boolean(TYPE_CONTINUE_ON_MISSING_CHANGES, true));
}
if (pareEntriesForUserDN != null)
{
elements.add(new ASN1OctetString(TYPE_PARE_ENTRIES_FOR_USER_DN,
pareEntriesForUserDN));
}
if (changeSelectionCriteria != null)
{
elements.add(changeSelectionCriteria.encode());
}
if (includeSoftDeletedEntryMods)
{
elements.add(new ASN1Boolean(TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS, true));
}
if (includeSoftDeletedEntryDeletes)
{
elements.add(new ASN1Boolean(TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES,
true));
}
return new ASN1OctetString(new ASN1Sequence(elements).encode());
}
/**
* Retrieves the starting point for the batch of changes to retrieve.
*
* @return The starting point for the batch of changes to retrieve.
*/
@NotNull()
public ChangelogBatchStartingPoint getStartingPoint()
{
return startingPoint;
}
/**
* Retrieves the maximum number of changes that should be returned before the
* operation completes. A value of zero indicates that the server should not
* return any entries but should just return a result containing a token which
* represents the starting point.
*
* @return The maximum number of changes that should be returned before the
* operation completes.
*/
public int getMaxChanges()
{
return maxChanges;
}
/**
* Retrieves the maximum length of time in milliseconds that the server should
* wait for changes to become available before returning the corresponding
* extended result to the client. A value of zero indicates that the server
* should return only those results which are immediately available without
* waiting.
*
* @return The maximum length of time in milliseconds that the server should
* wait for changes to become available, or 0 if the server should
* not wait at all.
*/
public long getMaxWaitTimeMillis()
{
return maxWaitTimeMillis;
}
/**
* Indicates whether the server should wait for up to the maximum length of
* time for up to the maximum number of changes to be returned before sending
* the extended result.
*
* @return {@code false} if the server should return the corresponding
* extended result as soon as any changes are available (after
* sending those available changes), or {@code true} if the result
* should not be returned until either the maximum number of changes
* have been returned or the maximum wait time has elapsed.
*/
public boolean waitForMaxChanges()
{
return waitForMaxChanges;
}
/**
* Retrieves a list of base DNs below which the server should return
* information about changes that have been processed. If any include base
* DNs are specified, then the server should return only changes to entries
* which reside at or below one of the include base DNs and not at or below
* any of the exclude base DNs. If no include or exclude base DNs are
* defined, then the server should return information about changes processed
* anywhere within the DIT.
*
* @return A list of the include base DNs for changes to retrieve, or an
* empty list if there are none.
*/
@NotNull()
public List getIncludeBaseDNs()
{
return includeBaseDNs;
}
/**
* Retrieves a list of base DNs below which the server should exclude
* information about changes processed. If any exclude base DNs are
* specified, then the server should not return changes to entries which
* reside at or below any of the exclude base DNs, even if they are also below
* an include base DN (and as such, the request should not include any exclude
* base DNs which are at or below any include base DNs). If no include or
* exclude base DNs are defined, then the server should return information
* about changes processed anywhere within the DIT.
*
* @return A list of the exclude base DNs for changes to retrieve, or an
* empty list if there are none.
*/
@NotNull()
public List getExcludeBaseDNs()
{
return excludeBaseDNs;
}
/**
* Retrieves the set of change types for changes to be returned to the client.
*
* @return The set of change types for changes to be returned to the client.
*/
@NotNull()
public Set getChangeTypes()
{
return changeTypes;
}
/**
* Indicates whether the server should make a best-effort attempt to return
* changes to the client even if the starting point represents a time before
* the start of the changelog and there may be missing changes.
*
* @return {@code true} if the server should attempt to return as many
* changes as possible even if some may be missing, or {@code false}
* if the server should return an error if there may be missing
* changes.
*/
public boolean continueOnMissingChanges()
{
return continueOnMissingChanges;
}
/**
* Retrieves the possibly-empty DN of the user for whom changelog entries
* should be pared based on access control and sensitive attribute
* restrictions, if defined.
*
* @return The possibly-empty DN of the user form whom changelog entries
* should be pared based on access control and sensitive attribute
* restrictions, or {@code null} if changelog entries should not be
* pared based for any user.
*/
@Nullable()
public String getPareEntriesForUserDN()
{
return pareEntriesForUserDN;
}
/**
* Retrieves the change selection criteria for this get changelog batch
* extended request, if defined.
*
* @return The change selection criteria for this get changelog batch
* extended request, or {@code null} if none is defined.
*/
@Nullable()
public ChangelogBatchChangeSelectionCriteria getChangeSelectionCriteria()
{
return changeSelectionCriteria;
}
/**
* Indicates whether to include changes that represent modifications to
* soft-deleted entries.
*
* @return {@code true} if the result set should include modifications to
* soft-deleted entries, or {@code false} if not.
*/
public boolean includeSoftDeletedEntryMods()
{
return includeSoftDeletedEntryMods;
}
/**
* Indicates whether to include changes that represent deletes of soft-deleted
* entries.
*
* @return {@code true} if the result set should include deletes of
* soft-deleted entries, or {@code false} if not.
*/
public boolean includeSoftDeletedEntryDeletes()
{
return includeSoftDeletedEntryDeletes;
}
/**
* Retrieves the changelog entry listener that will be used for this request,
* if applicable.
*
* @return The changelog entry listener that will be used for this request,
* or {@code null} if the entries will be made available in the
* extended result.
*/
@Nullable()
public ChangelogEntryListener getEntryListener()
{
return entryListener;
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public GetChangelogBatchExtendedResult process(
@NotNull final LDAPConnection connection, final int depth)
throws LDAPException
{
final IntermediateResponseListener l = getIntermediateResponseListener();
if (l != null)
{
throw new LDAPException(ResultCode.PARAM_ERROR,
ERR_GET_CHANGELOG_BATCH_REQ_IR_LISTENER_NOT_ALLOWED.get());
}
final GetChangelogBatchIntermediateResponseListener listener;
if (entryListener == null)
{
listener = new GetChangelogBatchIntermediateResponseListener(
new DefaultChangelogEntryListener(this));
}
else
{
listener =
new GetChangelogBatchIntermediateResponseListener(entryListener);
}
setIntermediateResponseListener(listener);
ExtendedResult r;
try
{
r = super.process(connection, depth);
}
catch (final LDAPException le)
{
Debug.debugException(le);
r = new ExtendedResult(getLastMessageID(), le.getResultCode(),
le.getDiagnosticMessage(), le.getMatchedDN(), le.getReferralURLs(),
null, null, le.getResponseControls());
}
finally
{
setIntermediateResponseListener(null);
}
if (entryListener == null)
{
final DefaultChangelogEntryListener defaultEntryListener =
(DefaultChangelogEntryListener) listener.getEntryListener();
return new GetChangelogBatchExtendedResult(r,
defaultEntryListener.getEntryList());
}
else
{
return new GetChangelogBatchExtendedResult(r, listener.getEntryCount());
}
}
/**
* {@inheritDoc}.
*/
@Override()
@NotNull()
public GetChangelogBatchExtendedRequest duplicate()
{
return duplicate(getControls());
}
/**
* {@inheritDoc}.
*/
@Override()
@NotNull()
public GetChangelogBatchExtendedRequest duplicate(
@Nullable final Control[] controls)
{
final GetChangelogBatchExtendedRequest r =
new GetChangelogBatchExtendedRequest(entryListener, startingPoint,
maxChanges, maxWaitTimeMillis, waitForMaxChanges, includeBaseDNs,
excludeBaseDNs, changeTypes, continueOnMissingChanges,
pareEntriesForUserDN, changeSelectionCriteria,
includeSoftDeletedEntryMods, includeSoftDeletedEntryDeletes,
controls);
r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
r.setIntermediateResponseListener(getIntermediateResponseListener());
r.setReferralDepth(getReferralDepth());
r.setReferralConnector(getReferralConnectorInternal());
return r;
}
/**
* {@inheritDoc}
*/
@Override()
@NotNull()
public String getExtendedRequestName()
{
return INFO_GET_CHANGELOG_BATCH_REQ_NAME.get();
}
/**
* {@inheritDoc}
*/
@Override()
public void toString(@NotNull final StringBuilder buffer)
{
buffer.append("GetChangelogBatchExtendedRequest(startingPoint=");
startingPoint.toString(buffer);
buffer.append(", maxChanges=");
buffer.append(maxChanges);
buffer.append(", maxWaitTimeMillis=");
buffer.append(maxWaitTimeMillis);
buffer.append(", waitForMaxChanges=");
buffer.append(waitForMaxChanges);
buffer.append(", includeBase={");
final Iterator includeIterator = includeBaseDNs.iterator();
while (includeIterator.hasNext())
{
buffer.append('"');
buffer.append(includeIterator.next());
buffer.append('"');
if (includeIterator.hasNext())
{
buffer.append(", ");
}
}
buffer.append("}, excludeBase={");
final Iterator excludeIterator = excludeBaseDNs.iterator();
while (excludeIterator.hasNext())
{
buffer.append('"');
buffer.append(excludeIterator.next());
buffer.append('"');
if (excludeIterator.hasNext())
{
buffer.append(", ");
}
}
buffer.append("}, changeTypes={");
final Iterator typeIterator = changeTypes.iterator();
while (typeIterator.hasNext())
{
buffer.append(typeIterator.next().getName());
if (typeIterator.hasNext())
{
buffer.append(", ");
}
}
buffer.append("}, continueOnMissingChanges=");
buffer.append(continueOnMissingChanges);
if (pareEntriesForUserDN != null)
{
buffer.append(", pareEntriesForUserDN='");
buffer.append(pareEntriesForUserDN);
buffer.append('\'');
}
if (changeSelectionCriteria != null)
{
buffer.append(", changeSelectionCriteria=");
changeSelectionCriteria.toString(buffer);
}
buffer.append(", includeSoftDeletedEntryMods=");
buffer.append(includeSoftDeletedEntryMods);
buffer.append(", includeSoftDeletedEntryDeletes=");
buffer.append(includeSoftDeletedEntryDeletes);
final Control[] controls = getControls();
if (controls.length > 0)
{
buffer.append(", controls={");
for (int i=0; i < controls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(controls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}