001/*
002 * Copyright 2010-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2010-2024 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2010-2024 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk.unboundidds.extensions;
037
038
039
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.EnumSet;
043import java.util.Iterator;
044import java.util.List;
045import java.util.Set;
046
047import com.unboundid.asn1.ASN1Boolean;
048import com.unboundid.asn1.ASN1Element;
049import com.unboundid.asn1.ASN1Enumerated;
050import com.unboundid.asn1.ASN1Integer;
051import com.unboundid.asn1.ASN1Long;
052import com.unboundid.asn1.ASN1OctetString;
053import com.unboundid.asn1.ASN1Sequence;
054import com.unboundid.asn1.ASN1Set;
055import com.unboundid.ldap.sdk.ChangeType;
056import com.unboundid.ldap.sdk.Control;
057import com.unboundid.ldap.sdk.ExtendedRequest;
058import com.unboundid.ldap.sdk.ExtendedResult;
059import com.unboundid.ldap.sdk.IntermediateResponseListener;
060import com.unboundid.ldap.sdk.LDAPConnection;
061import com.unboundid.ldap.sdk.LDAPException;
062import com.unboundid.ldap.sdk.ResultCode;
063import com.unboundid.util.Debug;
064import com.unboundid.util.NotMutable;
065import com.unboundid.util.NotNull;
066import com.unboundid.util.Nullable;
067import com.unboundid.util.StaticUtils;
068import com.unboundid.util.ThreadSafety;
069import com.unboundid.util.ThreadSafetyLevel;
070import com.unboundid.util.Validator;
071
072import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
073
074
075
076/**
077 * This class provides an implementation of an extended request which may be
078 * used to retrieve a batch of changes from a Directory Server.
079 * <BR>
080 * <BLOCKQUOTE>
081 *   <B>NOTE:</B>  This class, and other classes within the
082 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
083 *   supported for use against Ping Identity, UnboundID, and
084 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
085 *   for proprietary functionality or for external specifications that are not
086 *   considered stable or mature enough to be guaranteed to work in an
087 *   interoperable way with other types of LDAP servers.
088 * </BLOCKQUOTE>
089 * <BR>
090 * The changelog batch request value is encoded as follows:
091 * <PRE>
092 *   ChangelogBatchRequest ::= SEQUENCE {
093 *        startingPoint                      CHOICE {
094 *             resumeWithToken          [0] OCTET STRING,
095 *             resumeWithCSN            [1] OCTET STRING,
096 *             beginningOfChangelog     [2] NULL,
097 *             endOfChangelog           [3] NULL,
098 *             changeTime               [4] OCTET STRING,
099 *             ... },
100 *        maxChanges                         INTEGER (0 .. maxInt),
101 *        maxTimeMillis                      [0] INTEGER DEFAULT 0,
102 *        waitForMaxChanges                  [1] BOOLEAN DEFAULT FALSE,
103 *        includeBase                        [2] SEQUENCE OF LDAPDN OPTIONAL,
104 *        excludeBase                        [3] SEQUENCE OF LDAPDN OPTIONAL,
105 *        changeTypes                        [4] SET OF ENUMERATED {
106 *             add          (0),
107 *             delete       (1),
108 *             modify       (2),
109 *             modifyDN     (3) } OPTIONAL,
110 *        continueOnMissingChanges           [5] BOOLEAN DEFAULT FALSE,
111 *        pareEntriesForUserDN               [6] LDAPDN OPTIONAL,
112 *        changeSelectionCriteria            [7] CHOICE {
113 *             anyAttributes               [1] SEQUENCE OF LDAPString,
114 *             allAttributes               [2] SEQUENCE OF LDAPString,
115 *             ignoreAttributes            [3] SEQUENCE {
116 *                  ignoreAttributes                SEQUENCE OF LDAPString
117 *                  ignoreOperationalAttributes     BOOLEAN,
118 *                  ... },
119 *             notificationDestination     [4] OCTET STRING,
120 *             ... } OPTIONAL,
121 *        includeSoftDeletedEntryMods        [8] BOOLEAN DEFAULT FALSE,
122 *        includeSoftDeletedEntryDeletes     [9] BOOLEAN DEFAULT FALSE,
123 *        ... }
124 * </PRE>
125 * <BR><BR>
126 * <H2>Example</H2>
127 * The following example demonstrates the use of the get changelog batch to
128 * iterate across all entries in the changelog.  It will operate in an infinite
129 * loop, starting at the beginning of the changelog and then reading 1000
130 * entries at a time until all entries have been read.  Once the end of the
131 * changelog has been reached, it will continue looking for changes, waiting for
132 * up to 5 seconds for new changes to arrive.
133 * <PRE>
134 * ChangelogBatchStartingPoint startingPoint =
135 *      new BeginningOfChangelogStartingPoint();
136 * while (true)
137 * {
138 *   GetChangelogBatchExtendedRequest request =
139 *        new GetChangelogBatchExtendedRequest(startingPoint, 1000, 5000L);
140 *
141 *   GetChangelogBatchExtendedResult result =
142 *        (GetChangelogBatchExtendedResult)
143 *        connection.processExtendedOperation(request);
144 *   List&lt;ChangelogEntryIntermediateResponse&gt; changelogEntries =
145 *        result.getChangelogEntries();
146 *
147 *   startingPoint = new ResumeWithTokenStartingPoint(result.getResumeToken());
148 * }
149 * </PRE>
150 */
151@NotMutable()
152@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
153public final class GetChangelogBatchExtendedRequest
154       extends ExtendedRequest
155{
156  /**
157   * The OID (1.3.6.1.4.1.30221.2.6.10) for the get changelog batch extended
158   * request.
159   */
160  @NotNull public static final String GET_CHANGELOG_BATCH_REQUEST_OID =
161       "1.3.6.1.4.1.30221.2.6.10";
162
163
164
165  /**
166   * The BER type for the maxTimeMillis element.
167   */
168  private static final byte TYPE_MAX_TIME = (byte) 0x80;
169
170
171
172  /**
173   * The BER type for the returnOnAvailableChanges element.
174   */
175  private static final byte TYPE_WAIT_FOR_MAX_CHANGES = (byte) 0x81;
176
177
178
179  /**
180   * The BER type for the includeBase element.
181   */
182  private static final byte TYPE_INCLUDE_BASE = (byte) 0xA2;
183
184
185
186  /**
187   * The BER type for the excludeBase element.
188   */
189  private static final byte TYPE_EXCLUDE_BASE = (byte) 0xA3;
190
191
192
193  /**
194   * The BER type for the changeTypes element.
195   */
196  private static final byte TYPE_CHANGE_TYPES = (byte) 0xA4;
197
198
199
200  /**
201   * The BER type for the continueOnMissingChanges element.
202   */
203  private static final byte TYPE_CONTINUE_ON_MISSING_CHANGES = (byte) 0x85;
204
205
206
207  /**
208   * The BER type for the pareEntriesForUserDN element.
209   */
210  private static final byte TYPE_PARE_ENTRIES_FOR_USER_DN = (byte) 0x86;
211
212
213
214  /**
215   * The BER type for the includeSoftDeletedEntryMods element.
216   */
217  private static final byte TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS = (byte) 0x88;
218
219
220
221  /**
222   * The BER type for the includeSoftDeletedEntryDeletes element.
223   */
224  private static final byte TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES =
225       (byte) 0x89;
226
227
228
229  /**
230   * The value for a change type of add.
231   */
232  private static final int CHANGE_TYPE_ADD = 0;
233
234
235
236  /**
237   * The value for a change type of delete.
238   */
239  private static final int CHANGE_TYPE_DELETE = 1;
240
241
242
243  /**
244   * The value for a change type of modify.
245   */
246  private static final int CHANGE_TYPE_MODIFY = 2;
247
248
249
250  /**
251   * The value for a change type of modify DN.
252   */
253  private static final int CHANGE_TYPE_MODIFY_DN = 3;
254
255
256
257  /**
258   * The serial version UID for this serializable class.
259   */
260  private static final long serialVersionUID = 3270898150012821635L;
261
262
263
264  // Indicates whether to attempt to return changes even if the start point
265  // references changes which may have already been purged from the changelog.
266  private final boolean continueOnMissingChanges;
267
268  // Indicates whether deletes to soft-deleted entries should be included in the
269  // result set.
270  private final boolean includeSoftDeletedEntryDeletes;
271
272  // Indicates whether modifications of soft-deleted entries should be included
273  // in the result set.
274  private final boolean includeSoftDeletedEntryMods;
275
276  // Indicates whether the server should wait for up to the specified time limit
277  // for up to the the maximum number of changes to be returned, or whether it
278  // should return as soon as there are any results available.
279  private final boolean waitForMaxChanges;
280
281  // The change selection criteria for the request, if any.
282  @Nullable private final ChangelogBatchChangeSelectionCriteria
283       changeSelectionCriteria;
284
285  // The starting point for the batch of changes to retrieve.
286  @NotNull private final ChangelogBatchStartingPoint startingPoint;
287
288  // The entry listener for this request.
289  @Nullable private final ChangelogEntryListener entryListener;
290
291  // The maximum number of changes to retrieve in the batch.
292  private final int maxChanges;
293
294  // The list of base DNs for entries to exclude from the results.
295  @NotNull private final List<String> excludeBaseDNs;
296
297  // The list of base DNs for entries to include in the results.
298  @NotNull private final List<String> includeBaseDNs;
299
300  // The maximum length of time in milliseconds to wait for changes to become
301  // available.
302  private final long maxWaitTimeMillis;
303
304  // The set of change types for changes to include in the results.
305  @NotNull private final Set<ChangeType> changeTypes;
306
307  // The DN of a user for whom to pare down the contents of changelog entries
308  // based on access control and sensitive attribute restrictions, if defined.
309  @Nullable private final String pareEntriesForUserDN;
310
311
312
313  /**
314   * Creates a new get changelog batch extended request with the provided
315   * information.  It will include all changes processed anywhere in the server,
316   * and will request that the result be returned as soon as any changes are
317   * available.
318   *
319   * @param  startingPoint      An object which indicates the starting point for
320   *                            the batch of changes to retrieve.  It must not
321   *                            be {@code null}.
322   * @param  maxChanges         The maximum number of changes that should be
323   *                            retrieved before the server should return the
324   *                            corresponding extended result.  A value less
325   *                            than or equal to zero may be used to indicate
326   *                            that the server should not return any entries
327   *                            but should just return a result containing a
328   *                            token which represents the starting point.
329   * @param  maxWaitTimeMillis  The maximum length of time in milliseconds to
330   *                            wait for changes.  A value less than or equal to
331   *                            zero indicates that there should not be any wait
332   *                            and the result should be returned as soon as all
333   *                            immediately-available changes (up to the
334   *                            specified maximum count) have been returned.
335   * @param  controls           The set of controls to include in the request.
336   *                            It may be {@code null} or empty if there should
337   *                            be no controls.
338   */
339  public GetChangelogBatchExtendedRequest(
340              @NotNull final ChangelogBatchStartingPoint startingPoint,
341              final int maxChanges, final long maxWaitTimeMillis,
342              @Nullable final Control... controls)
343  {
344    this(null, startingPoint, maxChanges, maxWaitTimeMillis, false, null, null,
345         null, false, null, null, false, false, controls);
346  }
347
348
349
350  /**
351   * Creates a new get changelog batch extended request with the provided
352   * information.  It will include all changes processed anywhere in the server,
353   * and will request that the result be returned as soon as any changes are
354   * available.
355   *
356   * @param  entryListener      The listener that will be notified of any
357   *                            changelog entries (or other types of
358   *                            intermediate response) returned during the
359   *                            course of processing this request.  It may be
360   *                            {@code null} if changelog entries should be
361   *                            collected and made available in the extended
362   *                            result.
363   * @param  startingPoint      An object which indicates the starting point for
364   *                            the batch of changes to retrieve.  It must not
365   *                            be {@code null}.
366   * @param  maxChanges         The maximum number of changes that should be
367   *                            retrieved before the server should return the
368   *                            corresponding extended result.  A value less
369   *                            than or equal to zero may be used to indicate
370   *                            that the server should not return any entries
371   *                            but should just return a result containing a
372   *                            token which represents the starting point.
373   * @param  maxWaitTimeMillis  The maximum length of time in milliseconds to
374   *                            wait for changes.  A value less than or equal to
375   *                            zero indicates that there should not be any wait
376   *                            and the result should be returned as soon as all
377   *                            immediately-available changes (up to the
378   *                            specified maximum count) have been returned.
379   * @param  controls           The set of controls to include in the request.
380   *                            It may be {@code null} or empty if there should
381   *                            be no controls.
382   */
383  public GetChangelogBatchExtendedRequest(
384              @Nullable final ChangelogEntryListener entryListener,
385              @NotNull final ChangelogBatchStartingPoint startingPoint,
386              final int maxChanges, final long maxWaitTimeMillis,
387              @Nullable final Control... controls)
388  {
389    this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis, false,
390         null, null, null, false, null, null, false, false, controls);
391  }
392
393
394
395  /**
396   * Creates a new get changelog batch extended request with the provided
397   * information.
398   *
399   * @param  startingPoint             An object which indicates the starting
400   *                                   point for the batch of changes to
401   *                                   retrieve.  It must not be {@code null}.
402   * @param  maxChanges                The maximum number of changes that should
403   *                                   be retrieved before the server should
404   *                                   return the corresponding extended result.
405   *                                   A value less than or equal to zero may be
406   *                                   used to indicate that the server should
407   *                                   not return any entries but should just
408   *                                   return a result containing a token which
409   *                                   represents the starting point.
410   * @param  maxWaitTimeMillis         The maximum length of time in
411   *                                   milliseconds to wait for changes.  A
412   *                                   value less than or equal to zero
413   *                                   indicates that there should not be any
414   *                                   wait and the result should be returned as
415   *                                   soon as all immediately-available changes
416   *                                   (up to the specified maximum count) have
417   *                                   been returned.
418   * @param  waitForMaxChanges         Indicates whether the server should wait
419   *                                   for up to the maximum length of time for
420   *                                   up to the maximum number of changes to be
421   *                                   returned.  If this is {@code false}, then
422   *                                   the result will be returned as soon as
423   *                                   any changes are available (after sending
424   *                                   those changes), even if the number of
425   *                                   available changes is less than
426   *                                   {@code maxChanges}.  Otherwise, the
427   *                                   result will not be returned until either
428   *                                   the maximum number of changes have been
429   *                                   returned or the maximum wait time has
430   *                                   elapsed.
431   * @param  includeBaseDNs            A list of base DNs for entries to include
432   *                                   in the set of changes to be returned.
433   * @param  excludeBaseDNs            A list of base DNs for entries to exclude
434   *                                   from the set of changes to be returned.
435   * @param  changeTypes               The types of changes that should be
436   *                                   returned.  If this is {@code null} or
437   *                                   empty, then all change types will be
438   *                                   included.
439   * @param  continueOnMissingChanges  Indicates whether the server should make
440   *                                   a best-effort attempt to return changes
441   *                                   even if the starting point represents a
442   *                                   point that is before the first available
443   *                                   change in the changelog and therefore the
444   *                                   results returned may be missing changes.
445   * @param  controls                  The set of controls to include in the
446   *                                   request.  It may be {@code null} or empty
447   *                                   if there should be no controls.
448   */
449  public GetChangelogBatchExtendedRequest(
450              @NotNull final ChangelogBatchStartingPoint startingPoint,
451              final int maxChanges, final long maxWaitTimeMillis,
452              final boolean waitForMaxChanges,
453              @Nullable final List<String> includeBaseDNs,
454              @Nullable final List<String> excludeBaseDNs,
455              @Nullable final Set<ChangeType> changeTypes,
456              final boolean continueOnMissingChanges,
457              @Nullable final Control... controls)
458  {
459    this(null, startingPoint, maxChanges, maxWaitTimeMillis, waitForMaxChanges,
460         includeBaseDNs, excludeBaseDNs, changeTypes, continueOnMissingChanges,
461         null, null, false, false, controls);
462  }
463
464
465
466  /**
467   * Creates a new get changelog batch extended request with the provided
468   * information.
469   *
470   * @param  entryListener             The listener that will be notified of any
471   *                                   changelog entries (or other types of
472   *                                   intermediate response) returned during
473   *                                   the course of processing this request.
474   *                                   It may be {@code null} if changelog
475   *                                   entries should be collected and made
476   *                                   available in the extended result.
477   * @param  startingPoint             An object which indicates the starting
478   *                                   point for the batch of changes to
479   *                                   retrieve.  It must not be {@code null}.
480   * @param  maxChanges                The maximum number of changes that should
481   *                                   be retrieved before the server should
482   *                                   return the corresponding extended result.
483   *                                   A value less than or equal to zero may be
484   *                                   used to indicate that the server should
485   *                                   not return any entries but should just
486   *                                   return a result containing a token which
487   *                                   represents the starting point.
488   * @param  maxWaitTimeMillis         The maximum length of time in
489   *                                   milliseconds to wait for changes.  A
490   *                                   value less than or equal to zero
491   *                                   indicates that there should not be any
492   *                                   wait and the result should be returned as
493   *                                   soon as all immediately-available changes
494   *                                   (up to the specified maximum count) have
495   *                                   been returned.
496   * @param  waitForMaxChanges         Indicates whether the server should wait
497   *                                   for up to the maximum length of time for
498   *                                   up to the maximum number of changes to be
499   *                                   returned.  If this is {@code false}, then
500   *                                   the result will be returned as soon as
501   *                                   any changes are available (after sending
502   *                                   those changes), even if the number of
503   *                                   available changes is less than
504   *                                   {@code maxChanges}.  Otherwise, the
505   *                                   result will not be returned until either
506   *                                   the maximum number of changes have been
507   *                                   returned or the maximum wait time has
508   *                                   elapsed.
509   * @param  includeBaseDNs            A list of base DNs for entries to include
510   *                                   in the set of changes to be returned.
511   * @param  excludeBaseDNs            A list of base DNs for entries to exclude
512   *                                   from the set of changes to be returned.
513   * @param  changeTypes               The types of changes that should be
514   *                                   returned.  If this is {@code null} or
515   *                                   empty, then all change types will be
516   *                                   included.
517   * @param  continueOnMissingChanges  Indicates whether the server should make
518   *                                   a best-effort attempt to return changes
519   *                                   even if the starting point represents a
520   *                                   point that is before the first available
521   *                                   change in the changelog and therefore the
522   *                                   results returned may be missing changes.
523   * @param  controls                  The set of controls to include in the
524   *                                   request.  It may be {@code null} or empty
525   *                                   if there should be no controls.
526   */
527  public GetChangelogBatchExtendedRequest(
528              @Nullable final ChangelogEntryListener entryListener,
529              @NotNull final ChangelogBatchStartingPoint startingPoint,
530              final int maxChanges, final long maxWaitTimeMillis,
531              final boolean waitForMaxChanges,
532              @Nullable final List<String> includeBaseDNs,
533              @Nullable final List<String> excludeBaseDNs,
534              @Nullable final Set<ChangeType> changeTypes,
535              final boolean continueOnMissingChanges,
536              @Nullable final Control... controls)
537  {
538    this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis,
539         waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
540         continueOnMissingChanges, null, null, false, false, controls);
541  }
542
543
544
545  /**
546   * Creates a new get changelog batch extended request with the provided
547   * information.
548   *
549   * @param  entryListener             The listener that will be notified of any
550   *                                   changelog entries (or other types of
551   *                                   intermediate response) returned during
552   *                                   the course of processing this request.
553   *                                   It may be {@code null} if changelog
554   *                                   entries should be collected and made
555   *                                   available in the extended result.
556   * @param  startingPoint             An object which indicates the starting
557   *                                   point for the batch of changes to
558   *                                   retrieve.  It must not be {@code null}.
559   * @param  maxChanges                The maximum number of changes that should
560   *                                   be retrieved before the server should
561   *                                   return the corresponding extended result.
562   *                                   A value less than or equal to zero may be
563   *                                   used to indicate that the server should
564   *                                   not return any entries but should just
565   *                                   return a result containing a token which
566   *                                   represents the starting point.
567   * @param  maxWaitTimeMillis         The maximum length of time in
568   *                                   milliseconds to wait for changes.  A
569   *                                   value less than or equal to zero
570   *                                   indicates that there should not be any
571   *                                   wait and the result should be returned as
572   *                                   soon as all immediately-available changes
573   *                                   (up to the specified maximum count) have
574   *                                   been returned.
575   * @param  waitForMaxChanges         Indicates whether the server should wait
576   *                                   for up to the maximum length of time for
577   *                                   up to the maximum number of changes to be
578   *                                   returned.  If this is {@code false}, then
579   *                                   the result will be returned as soon as
580   *                                   any changes are available (after sending
581   *                                   those changes), even if the number of
582   *                                   available changes is less than
583   *                                   {@code maxChanges}.  Otherwise, the
584   *                                   result will not be returned until either
585   *                                   the maximum number of changes have been
586   *                                   returned or the maximum wait time has
587   *                                   elapsed.
588   * @param  includeBaseDNs            A list of base DNs for entries to include
589   *                                   in the set of changes to be returned.
590   * @param  excludeBaseDNs            A list of base DNs for entries to exclude
591   *                                   from the set of changes to be returned.
592   * @param  changeTypes               The types of changes that should be
593   *                                   returned.  If this is {@code null} or
594   *                                   empty, then all change types will be
595   *                                   included.
596   * @param  continueOnMissingChanges  Indicates whether the server should make
597   *                                   a best-effort attempt to return changes
598   *                                   even if the starting point represents a
599   *                                   point that is before the first available
600   *                                   change in the changelog and therefore the
601   *                                   results returned may be missing changes.
602   * @param  pareEntriesForUserDN      The DN of a user for whom to pare down
603   *                                   the contents of changelog entries based
604   *                                   on the access control and sensitive
605   *                                   attribute restrictions defined for that
606   *                                   user.  It may be {@code null} if
607   *                                   changelog entries should not be pared
608   *                                   down for any user, an empty string if
609   *                                   changelog entries should be pared down to
610   *                                   what is available to anonymous users, or
611   *                                   a user DN to pare down entries for the
612   *                                   specified user.
613   * @param  changeSelectionCriteria   The optional criteria to use to pare down
614   *                                   the changelog entries that should be
615   *                                   returned.  It may be {@code null} if all
616   *                                   changelog entries should be returned.
617   * @param  controls                  The set of controls to include in the
618   *                                   request.  It may be {@code null} or empty
619   *                                   if there should be no controls.
620   */
621  public GetChangelogBatchExtendedRequest(
622              @Nullable final ChangelogEntryListener entryListener,
623              @NotNull final ChangelogBatchStartingPoint startingPoint,
624              final int maxChanges, final long maxWaitTimeMillis,
625              final boolean waitForMaxChanges,
626              @Nullable final List<String> includeBaseDNs,
627              @Nullable final List<String> excludeBaseDNs,
628              @Nullable final Set<ChangeType> changeTypes,
629              final boolean continueOnMissingChanges,
630              @Nullable final String pareEntriesForUserDN,
631              @Nullable final ChangelogBatchChangeSelectionCriteria
632                         changeSelectionCriteria,
633              @Nullable final Control... controls)
634  {
635    this(entryListener, startingPoint, maxChanges, maxWaitTimeMillis,
636         waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
637         continueOnMissingChanges, pareEntriesForUserDN,
638         changeSelectionCriteria, false, false, controls);
639  }
640
641
642
643  /**
644   * Creates a new get changelog batch extended request with the provided
645   * information.
646   *
647   * @param  entryListener                   The listener that will be notified
648   *                                         of any changelog entries (or other
649   *                                         types of intermediate response)
650   *                                         returned during the course of
651   *                                         processing this request.  It may be
652   *                                         {@code null} if changelog entries
653   *                                         should be collected and made
654   *                                         available in the extended result.
655   * @param  startingPoint                   An object which indicates the
656   *                                         starting point for the batch of
657   *                                         changes to retrieve.  It must not
658   *                                         be {@code null}.
659   * @param  maxChanges                      The maximum number of changes that
660   *                                         should be retrieved before the
661   *                                         server should return the
662   *                                         corresponding extended result.  A
663   *                                         value less than or equal to zero
664   *                                         may be used to indicate that the
665   *                                         server should not return any
666   *                                         entries but should just return a
667   *                                         result containing a token which
668   *                                         represents the starting point.
669   * @param  maxWaitTimeMillis               The maximum length of time in
670   *                                         milliseconds to wait for changes.
671   *                                         A value less than or equal to zero
672   *                                         indicates that there should not be
673   *                                         any wait and the result should be
674   *                                         returned as soon as all
675   *                                         immediately-available changes (up
676   *                                         to the specified maximum count)
677   *                                         have been returned.
678   * @param  waitForMaxChanges               Indicates whether the server should
679   *                                         wait for up to the maximum length
680   *                                         of time for up to the maximum
681   *                                         number of changes to be returned.
682   *                                         If this is {@code false}, then the
683   *                                         result will be returned as soon as
684   *                                         any changes are available (after
685   *                                         sending those changes), even if the
686   *                                         number of available changes is less
687   *                                         than {@code maxChanges}.
688   *                                         Otherwise, the result will not be
689   *                                         returned until either the maximum
690   *                                         number of changes have been
691   *                                         returned or the maximum wait time
692   *                                         has elapsed.
693   * @param  includeBaseDNs                  A list of base DNs for entries to
694   *                                         include in the set of changes to be
695   *                                         returned.
696   * @param  excludeBaseDNs                  A list of base DNs for entries to
697   *                                         exclude from the set of changes to
698   *                                         be returned.
699   * @param  changeTypes                     The types of changes that should be
700   *                                         returned.  If this is {@code null}
701   *                                         or empty, then all change types
702   *                                         will be included.
703   * @param  continueOnMissingChanges        Indicates whether the server should
704   *                                         make a best-effort attempt to
705   *                                         return changes even if the starting
706   *                                         point represents a point that is
707   *                                         before the first available change
708   *                                         in the changelog and therefore the
709   *                                         results returned may be missing
710   *                                         changes.
711   * @param  pareEntriesForUserDN            The DN of a user for whom to pare
712   *                                         down the contents of changelog
713   *                                         entries based on the access control
714   *                                         and sensitive attribute
715   *                                         restrictions defined for that user.
716   *                                         It may be {@code null} if changelog
717   *                                         entries should not be pared down
718   *                                         for any user, an empty string if
719   *                                         changelog entries should be pared
720   *                                         down to what is available to
721   *                                         anonymous users, or a user DN to
722   *                                         pare down entries for the specified
723   *                                         user.
724   * @param  changeSelectionCriteria         The optional criteria to use to
725   *                                         pare down the changelog entries
726   *                                         that should be returned.  It may be
727   *                                         {@code null} if all changelog
728   *                                         entries should be returned.
729   * @param  includeSoftDeletedEntryMods     Indicates whether to include
730   *                                         changelog entries that represent
731   *                                         changes to soft-deleted entries.
732   * @param  includeSoftDeletedEntryDeletes  Indicates whether to include
733   *                                         changelog entries that represent
734   *                                         deletes of soft-deleted entries.
735   * @param  controls                        The set of controls to include in
736   *                                         the request.  It may be
737   *                                         {@code null} or empty if there
738   *                                         should be no controls.
739   */
740  public GetChangelogBatchExtendedRequest(
741              @Nullable final ChangelogEntryListener entryListener,
742              @NotNull final ChangelogBatchStartingPoint startingPoint,
743              final int maxChanges, final long maxWaitTimeMillis,
744              final boolean waitForMaxChanges,
745              @Nullable final List<String> includeBaseDNs,
746              @Nullable final List<String> excludeBaseDNs,
747              @Nullable final Set<ChangeType> changeTypes,
748              final boolean continueOnMissingChanges,
749              @Nullable final String pareEntriesForUserDN,
750              @Nullable final ChangelogBatchChangeSelectionCriteria
751                         changeSelectionCriteria,
752              final boolean includeSoftDeletedEntryMods,
753              final boolean includeSoftDeletedEntryDeletes,
754              @Nullable final Control... controls)
755  {
756    super(GET_CHANGELOG_BATCH_REQUEST_OID,
757         encodeValue(startingPoint, maxChanges, maxWaitTimeMillis,
758              waitForMaxChanges, includeBaseDNs, excludeBaseDNs, changeTypes,
759              continueOnMissingChanges, pareEntriesForUserDN,
760              changeSelectionCriteria, includeSoftDeletedEntryMods,
761              includeSoftDeletedEntryDeletes),
762         controls);
763
764    this.entryListener                  = entryListener;
765    this.startingPoint                  = startingPoint;
766    this.maxWaitTimeMillis              = maxWaitTimeMillis;
767    this.waitForMaxChanges              = waitForMaxChanges;
768    this.continueOnMissingChanges       = continueOnMissingChanges;
769    this.pareEntriesForUserDN           = pareEntriesForUserDN;
770    this.changeSelectionCriteria        = changeSelectionCriteria;
771    this.includeSoftDeletedEntryMods    = includeSoftDeletedEntryMods;
772    this.includeSoftDeletedEntryDeletes = includeSoftDeletedEntryDeletes;
773
774    if (maxChanges <= 0)
775    {
776      this.maxChanges = 0;
777    }
778    else
779    {
780      this.maxChanges = maxChanges;
781    }
782
783    if (includeBaseDNs == null)
784    {
785      this.includeBaseDNs = Collections.emptyList();
786    }
787    else
788    {
789      this.includeBaseDNs = Collections.unmodifiableList(includeBaseDNs);
790    }
791
792    if (excludeBaseDNs == null)
793    {
794      this.excludeBaseDNs = Collections.emptyList();
795    }
796    else
797    {
798      this.excludeBaseDNs = Collections.unmodifiableList(excludeBaseDNs);
799    }
800
801    if ((changeTypes == null) || changeTypes.isEmpty())
802    {
803      this.changeTypes =
804           Collections.unmodifiableSet(EnumSet.allOf(ChangeType.class));
805    }
806    else
807    {
808      this.changeTypes = Collections.unmodifiableSet(changeTypes);
809    }
810  }
811
812
813
814  /**
815   * Creates a new get changelog batch extended request from the provided
816   * generic extended request.
817   *
818   * @param  extendedRequest  The generic extended request to be decoded as a
819   *                          get changelog batch extended request.
820   *
821   * @throws  LDAPException  If the provided generic request cannot be decoded
822   *                         as a get changelog batch extended request.
823   */
824  public GetChangelogBatchExtendedRequest(
825              @NotNull final ExtendedRequest extendedRequest)
826         throws LDAPException
827  {
828    super(extendedRequest.getOID(), extendedRequest.getValue(),
829         extendedRequest.getControls());
830
831    final ASN1OctetString value = extendedRequest.getValue();
832    if (value == null)
833    {
834      throw new LDAPException(ResultCode.DECODING_ERROR,
835           ERR_GET_CHANGELOG_BATCH_REQ_NO_VALUE.get());
836    }
837
838    final ASN1Sequence valueSequence;
839    try
840    {
841      valueSequence = ASN1Sequence.decodeAsSequence(value.getValue());
842    }
843    catch (final Exception e)
844    {
845      Debug.debugException(e);
846      throw new LDAPException(ResultCode.DECODING_ERROR,
847           ERR_GET_CHANGELOG_BATCH_REQ_VALUE_NOT_SEQUENCE.get(
848                StaticUtils.getExceptionMessage(e)), e);
849    }
850
851    final ASN1Element[] elements = valueSequence.elements();
852    if (elements.length < 2)
853    {
854      throw new LDAPException(ResultCode.DECODING_ERROR,
855           ERR_GET_CHANGELOG_BATCH_REQ_TOO_FEW_ELEMENTS.get());
856    }
857
858    try
859    {
860      startingPoint = ChangelogBatchStartingPoint.decode(elements[0]);
861
862      final int mc = ASN1Integer.decodeAsInteger(elements[1]).intValue();
863      if (mc > 0)
864      {
865        maxChanges = mc;
866      }
867      else
868      {
869        maxChanges = 0;
870      }
871
872      boolean waitForMax = false;
873      long maxTime = 0L;
874      List<String> includeBase = Collections.emptyList();
875      List<String> excludeBase = Collections.emptyList();
876      Set<ChangeType> types =
877           Collections.unmodifiableSet(EnumSet.allOf(ChangeType.class));
878      boolean continueOnMissing = false;
879      String pareForDN = null;
880      ChangelogBatchChangeSelectionCriteria changeCriteria = null;
881      boolean includeSDMods = false;
882      boolean includeSDDeletes = false;
883
884      for (int i=2; i < elements.length; i++)
885      {
886        switch (elements[i].getType())
887        {
888          case TYPE_MAX_TIME:
889            maxTime = ASN1Long.decodeAsLong(elements[i]).longValue();
890            if (maxTime < 0L)
891            {
892              maxTime = 0L;
893            }
894            break;
895
896          case TYPE_WAIT_FOR_MAX_CHANGES:
897            waitForMax =
898                 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
899            break;
900
901          case TYPE_INCLUDE_BASE:
902            final ASN1Element[] includeElements =
903                 ASN1Sequence.decodeAsSequence(elements[i]).elements();
904            final ArrayList<String> includeList =
905                 new ArrayList<>(includeElements.length);
906            for (final ASN1Element e : includeElements)
907            {
908              includeList.add(
909                   ASN1OctetString.decodeAsOctetString(e).stringValue());
910            }
911            includeBase = Collections.unmodifiableList(includeList);
912            break;
913
914          case TYPE_EXCLUDE_BASE:
915            final ASN1Element[] excludeElements =
916                 ASN1Sequence.decodeAsSequence(elements[i]).elements();
917            final ArrayList<String> excludeList =
918                 new ArrayList<>(excludeElements.length);
919            for (final ASN1Element e : excludeElements)
920            {
921              excludeList.add(
922                   ASN1OctetString.decodeAsOctetString(e).stringValue());
923            }
924            excludeBase = Collections.unmodifiableList(excludeList);
925            break;
926
927          case TYPE_CHANGE_TYPES:
928            final EnumSet<ChangeType> ctSet = EnumSet.noneOf(ChangeType.class);
929            for (final ASN1Element e :
930                 ASN1Set.decodeAsSet(elements[i]).elements())
931            {
932              final int v = ASN1Enumerated.decodeAsEnumerated(e).intValue();
933              switch (v)
934              {
935                case CHANGE_TYPE_ADD:
936                  ctSet.add(ChangeType.ADD);
937                  break;
938                case CHANGE_TYPE_DELETE:
939                  ctSet.add(ChangeType.DELETE);
940                  break;
941                case CHANGE_TYPE_MODIFY:
942                  ctSet.add(ChangeType.MODIFY);
943                  break;
944                case CHANGE_TYPE_MODIFY_DN:
945                  ctSet.add(ChangeType.MODIFY_DN);
946                  break;
947                default:
948                  throw new LDAPException(ResultCode.DECODING_ERROR,
949                       ERR_GET_CHANGELOG_BATCH_REQ_VALUE_UNRECOGNIZED_CT.get(
950                            v));
951              }
952            }
953            types = Collections.unmodifiableSet(ctSet);
954            break;
955
956          case TYPE_CONTINUE_ON_MISSING_CHANGES:
957            continueOnMissing =
958                 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
959            break;
960
961          case TYPE_PARE_ENTRIES_FOR_USER_DN:
962            pareForDN =
963                 ASN1OctetString.decodeAsOctetString(elements[i]).stringValue();
964            break;
965
966          case ChangelogBatchChangeSelectionCriteria.TYPE_SELECTION_CRITERIA:
967            changeCriteria =
968                 ChangelogBatchChangeSelectionCriteria.decode(elements[i]);
969            break;
970
971          case TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS:
972            includeSDMods =
973                 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
974            break;
975
976          case TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES:
977            includeSDDeletes =
978                 ASN1Boolean.decodeAsBoolean(elements[i]).booleanValue();
979            break;
980
981          default:
982            throw new LDAPException(ResultCode.DECODING_ERROR,
983                 ERR_GET_CHANGELOG_BATCH_REQ_VALUE_UNRECOGNIZED_TYPE.get(
984                      StaticUtils.toHex(elements[i].getType())));
985        }
986      }
987
988      entryListener                  = null;
989      maxWaitTimeMillis              = maxTime;
990      waitForMaxChanges              = waitForMax;
991      includeBaseDNs                 = includeBase;
992      excludeBaseDNs                 = excludeBase;
993      changeTypes                    = types;
994      continueOnMissingChanges       = continueOnMissing;
995      pareEntriesForUserDN           = pareForDN;
996      changeSelectionCriteria        = changeCriteria;
997      includeSoftDeletedEntryMods    = includeSDMods;
998      includeSoftDeletedEntryDeletes = includeSDDeletes;
999    }
1000    catch (final LDAPException le)
1001    {
1002      Debug.debugException(le);
1003      throw le;
1004    }
1005    catch (final Exception e)
1006    {
1007      Debug.debugException(e);
1008      throw new LDAPException(ResultCode.DECODING_ERROR,
1009           ERR_GET_CHANGELOG_BATCH_REQ_ERROR_DECODING_VALUE.get(
1010                StaticUtils.getExceptionMessage(e)), e);
1011    }
1012  }
1013
1014
1015
1016  /**
1017   * Encodes the value for this extended request using the provided information.
1018   *
1019   * @param  startingPoint                   An object which indicates the
1020   *                                         starting point for the batch of
1021   *                                         changes to retrieve.  It must not
1022   *                                         be {@code null}.
1023   * @param  maxChanges                      The maximum number of changes that
1024   *                                         should be retrieved before the
1025   *                                         server should return the
1026   *                                         corresponding extended result.  A
1027   *                                         value less than or equal to zero
1028   *                                         may be used to indicate that the
1029   *                                         server should not return any
1030   *                                         entries but should just return a
1031   *                                         result containing a token which
1032   *                                         represents the starting point.
1033   * @param  maxWaitTimeMillis               The maximum length of time in
1034   *                                         milliseconds to wait for changes.
1035   *                                         A value less than or equal to zero
1036   *                                         indicates that there should not be
1037   *                                         any wait and the result should be
1038   *                                         returned as soon as all
1039   *                                         immediately-available changes (up
1040   *                                         to the specified maximum count)
1041   *                                         have been returned.
1042   * @param  waitForMaxChanges               Indicates whether the server should
1043   *                                         wait for up to the maximum length
1044   *                                         of time for up to the maximum
1045   *                                         number of changes to be returned.
1046   *                                         If this is {@code false}, then the
1047   *                                         result will be returned as soon as
1048   *                                         any changes are available (after
1049   *                                         sending those changes), even if the
1050   *                                         number of available changes is less
1051   *                                         than {@code maxChanges}.
1052   *                                         Otherwise, the result will not be
1053   *                                         returned until either the maximum
1054   *                                         number of changes have been
1055   *                                         returned or the maximum wait time
1056   *                                         has elapsed.
1057   * @param  includeBaseDNs                  A list of base DNs for entries to
1058   *                                         include in the set of changes to be
1059   *                                         returned.
1060   * @param  excludeBaseDNs                  A list of base DNs for entries to
1061   *                                         exclude from the set of changes to
1062   *                                         be returned.
1063   * @param  changeTypes                     The types of changes that should be
1064   *                                         returned.  If this is {@code null}
1065   *                                         or empty, then all change types
1066   *                                         will be included.
1067   * @param  continueOnMissingChanges        Indicates whether the server should
1068   *                                         make a best-effort attempt to
1069   *                                         return changes even if the starting
1070   *                                         point represents a point that is
1071   *                                         before the first available change
1072   *                                         in the changelog and therefore the
1073   *                                         results returned may be missing
1074   *                                         changes.
1075   * @param  pareEntriesForUserDN            The DN of a user for whom to pare
1076   *                                         down the contents of changelog
1077   *                                         entries based on the access control
1078   *                                         and sensitive attribute
1079   *                                         restrictions defined for that user.
1080   *                                         It may be {@code null} if changelog
1081   *                                         entries should not be pared down
1082   *                                         for any user, an empty string if
1083   *                                         changelog entries should be pared
1084   *                                         down to what is available to
1085   *                                         anonymous users, or a user DN to
1086   *                                         pare down entries for the specified
1087   *                                         user.
1088   * @param  changeSelectionCriteria         The optional criteria to use to
1089   *                                         pare down the changelog entries
1090   *                                         that should be returned.  It may be
1091   *                                         {@code null} if all changelog
1092   *                                         entries should be returned.
1093   * @param  includeSoftDeletedEntryMods     Indicates whether to include
1094   *                                         changelog entries that represent
1095   *                                         changes to soft-deleted entries.
1096   * @param  includeSoftDeletedEntryDeletes  Indicates whether to include
1097   *                                         changelog entries that represent
1098   *                                         deletes of soft-deleted entries.
1099   *
1100   * @return  The value for the extended request.
1101   */
1102  @NotNull()
1103  private static ASN1OctetString encodeValue(
1104       @NotNull final ChangelogBatchStartingPoint startingPoint,
1105       final int maxChanges, final long maxWaitTimeMillis,
1106       final boolean waitForMaxChanges,
1107       @Nullable final List<String> includeBaseDNs,
1108       @Nullable final List<String> excludeBaseDNs,
1109       @Nullable final Set<ChangeType> changeTypes,
1110       final boolean continueOnMissingChanges,
1111       @Nullable final String pareEntriesForUserDN,
1112       @Nullable final ChangelogBatchChangeSelectionCriteria
1113            changeSelectionCriteria,
1114       final boolean includeSoftDeletedEntryMods,
1115       final boolean includeSoftDeletedEntryDeletes)
1116  {
1117    Validator.ensureNotNull(startingPoint);
1118
1119    final ArrayList<ASN1Element> elements = new ArrayList<>(12);
1120
1121    elements.add(startingPoint.encode());
1122
1123    if (maxChanges > 0)
1124    {
1125      elements.add(new ASN1Integer(maxChanges));
1126    }
1127    else
1128    {
1129      elements.add(new ASN1Integer(0));
1130    }
1131
1132    if (maxWaitTimeMillis > 0L)
1133    {
1134      elements.add(new ASN1Long(TYPE_MAX_TIME, maxWaitTimeMillis));
1135    }
1136
1137    if (waitForMaxChanges)
1138    {
1139      elements.add(new ASN1Boolean(TYPE_WAIT_FOR_MAX_CHANGES, true));
1140    }
1141
1142    if ((includeBaseDNs != null) && (! includeBaseDNs.isEmpty()))
1143    {
1144      final ArrayList<ASN1Element> l = new ArrayList<>(includeBaseDNs.size());
1145      for (final String s : includeBaseDNs)
1146      {
1147        l.add(new ASN1OctetString(s));
1148      }
1149      elements.add(new ASN1Sequence(TYPE_INCLUDE_BASE, l));
1150    }
1151
1152    if ((excludeBaseDNs != null) && (! excludeBaseDNs.isEmpty()))
1153    {
1154      final ArrayList<ASN1Element> l = new ArrayList<>(excludeBaseDNs.size());
1155      for (final String s : excludeBaseDNs)
1156      {
1157        l.add(new ASN1OctetString(s));
1158      }
1159      elements.add(new ASN1Sequence(TYPE_EXCLUDE_BASE, l));
1160    }
1161
1162    if ((changeTypes != null) && (! changeTypes.isEmpty()) &&
1163        (! changeTypes.equals(EnumSet.allOf(ChangeType.class))))
1164    {
1165      final ArrayList<ASN1Element> l = new ArrayList<>(changeTypes.size());
1166      for (final ChangeType t : changeTypes)
1167      {
1168        switch (t)
1169        {
1170          case ADD:
1171            l.add(new ASN1Enumerated(CHANGE_TYPE_ADD));
1172            break;
1173          case DELETE:
1174            l.add(new ASN1Enumerated(CHANGE_TYPE_DELETE));
1175            break;
1176          case MODIFY:
1177            l.add(new ASN1Enumerated(CHANGE_TYPE_MODIFY));
1178            break;
1179          case MODIFY_DN:
1180            l.add(new ASN1Enumerated(CHANGE_TYPE_MODIFY_DN));
1181            break;
1182        }
1183      }
1184      elements.add(new ASN1Set(TYPE_CHANGE_TYPES, l));
1185    }
1186
1187    if (continueOnMissingChanges)
1188    {
1189      elements.add(new ASN1Boolean(TYPE_CONTINUE_ON_MISSING_CHANGES, true));
1190    }
1191
1192    if (pareEntriesForUserDN != null)
1193    {
1194      elements.add(new ASN1OctetString(TYPE_PARE_ENTRIES_FOR_USER_DN,
1195           pareEntriesForUserDN));
1196    }
1197
1198    if (changeSelectionCriteria != null)
1199    {
1200      elements.add(changeSelectionCriteria.encode());
1201    }
1202
1203    if (includeSoftDeletedEntryMods)
1204    {
1205      elements.add(new ASN1Boolean(TYPE_INCLUDE_SOFT_DELETED_ENTRY_MODS, true));
1206    }
1207
1208    if (includeSoftDeletedEntryDeletes)
1209    {
1210      elements.add(new ASN1Boolean(TYPE_INCLUDE_SOFT_DELETED_ENTRY_DELETES,
1211           true));
1212    }
1213
1214    return new ASN1OctetString(new ASN1Sequence(elements).encode());
1215  }
1216
1217
1218
1219  /**
1220   * Retrieves the starting point for the batch of changes to retrieve.
1221   *
1222   * @return  The starting point for the batch of changes to retrieve.
1223   */
1224  @NotNull()
1225  public ChangelogBatchStartingPoint getStartingPoint()
1226  {
1227    return startingPoint;
1228  }
1229
1230
1231
1232  /**
1233   * Retrieves the maximum number of changes that should be returned before the
1234   * operation completes.  A value of zero indicates that the server should not
1235   * return any entries but should just return a result containing a token which
1236   * represents the starting point.
1237   *
1238   * @return  The maximum number of changes that should be returned before the
1239   *          operation completes.
1240   */
1241  public int getMaxChanges()
1242  {
1243    return maxChanges;
1244  }
1245
1246
1247
1248  /**
1249   * Retrieves the maximum length of time in milliseconds that the server should
1250   * wait for changes to become available before returning the corresponding
1251   * extended result to the client.  A value of zero indicates that the server
1252   * should return only those results which are immediately available without
1253   * waiting.
1254   *
1255   * @return  The maximum length of time in milliseconds that the server should
1256   *          wait for changes to become available, or 0 if the server should
1257   *          not wait at all.
1258   */
1259  public long getMaxWaitTimeMillis()
1260  {
1261    return maxWaitTimeMillis;
1262  }
1263
1264
1265
1266  /**
1267   * Indicates whether the server should wait for up to the maximum length of
1268   * time for up to the maximum number of changes to be returned before sending
1269   * the extended result.
1270   *
1271   * @return  {@code false} if the server should return the corresponding
1272   *          extended result as soon as any changes are available (after
1273   *          sending those available changes), or {@code true} if the result
1274   *          should not be returned until either the maximum number of changes
1275   *          have been returned or the maximum wait time has elapsed.
1276   */
1277  public boolean waitForMaxChanges()
1278  {
1279    return waitForMaxChanges;
1280  }
1281
1282
1283
1284  /**
1285   * Retrieves a list of base DNs below which the server should return
1286   * information about changes that have been processed.  If any include base
1287   * DNs are specified, then the server should return only changes to entries
1288   * which reside at or below one of the include base DNs and not at or below
1289   * any of the exclude base DNs.  If no include or exclude base DNs are
1290   * defined, then the server should return information about changes processed
1291   * anywhere within the DIT.
1292   *
1293   * @return  A list of the include base DNs for changes to retrieve, or an
1294   *          empty list if there are none.
1295   */
1296  @NotNull()
1297  public List<String> getIncludeBaseDNs()
1298  {
1299    return includeBaseDNs;
1300  }
1301
1302
1303
1304  /**
1305   * Retrieves a list of base DNs below which the server should exclude
1306   * information about changes processed.  If any exclude base DNs are
1307   * specified, then the server should not return changes to entries which
1308   * reside at or below any of the exclude base DNs, even if they are also below
1309   * an include base DN (and as such, the request should not include any exclude
1310   * base DNs which are at or below any include base DNs).  If no include or
1311   * exclude base DNs are defined, then the server should return information
1312   * about changes processed anywhere within the DIT.
1313   *
1314   * @return  A list of the exclude base DNs for changes to retrieve, or an
1315   *          empty list if there are none.
1316   */
1317  @NotNull()
1318  public List<String> getExcludeBaseDNs()
1319  {
1320    return excludeBaseDNs;
1321  }
1322
1323
1324
1325  /**
1326   * Retrieves the set of change types for changes to be returned to the client.
1327   *
1328   * @return  The set of change types for changes to be returned to the client.
1329   */
1330  @NotNull()
1331  public Set<ChangeType> getChangeTypes()
1332  {
1333    return changeTypes;
1334  }
1335
1336
1337
1338  /**
1339   * Indicates whether the server should make a best-effort attempt to return
1340   * changes to the client even if the starting point represents a time before
1341   * the start of the changelog and there may be missing changes.
1342   *
1343   * @return  {@code true} if the server should attempt to return as many
1344   *          changes as possible even if some may be missing, or {@code false}
1345   *          if the server should return an error if there may be missing
1346   *          changes.
1347   */
1348  public boolean continueOnMissingChanges()
1349  {
1350    return continueOnMissingChanges;
1351  }
1352
1353
1354
1355  /**
1356   * Retrieves the possibly-empty DN of the user for whom changelog entries
1357   * should be pared based on access control and sensitive attribute
1358   * restrictions, if defined.
1359   *
1360   * @return  The possibly-empty DN of the user form whom changelog entries
1361   *          should be pared based on access control and sensitive attribute
1362   *          restrictions, or {@code null} if changelog entries should not be
1363   *          pared based for any user.
1364   */
1365  @Nullable()
1366  public String getPareEntriesForUserDN()
1367  {
1368    return pareEntriesForUserDN;
1369  }
1370
1371
1372
1373  /**
1374   * Retrieves the change selection criteria for this get changelog batch
1375   * extended request, if defined.
1376   *
1377   * @return  The change selection criteria for this get changelog batch
1378   *          extended request, or {@code null} if none is defined.
1379   */
1380  @Nullable()
1381  public ChangelogBatchChangeSelectionCriteria getChangeSelectionCriteria()
1382  {
1383    return changeSelectionCriteria;
1384  }
1385
1386
1387
1388  /**
1389   * Indicates whether to include changes that represent modifications to
1390   * soft-deleted entries.
1391   *
1392   * @return  {@code true} if the result set should include modifications to
1393   *          soft-deleted entries, or {@code false} if not.
1394   */
1395  public boolean includeSoftDeletedEntryMods()
1396  {
1397    return includeSoftDeletedEntryMods;
1398  }
1399
1400
1401
1402  /**
1403   * Indicates whether to include changes that represent deletes of soft-deleted
1404   * entries.
1405   *
1406   * @return  {@code true} if the result set should include deletes of
1407   *          soft-deleted entries, or {@code false} if not.
1408   */
1409  public boolean includeSoftDeletedEntryDeletes()
1410  {
1411    return includeSoftDeletedEntryDeletes;
1412  }
1413
1414
1415
1416  /**
1417   * Retrieves the changelog entry listener that will be used for this request,
1418   * if applicable.
1419   *
1420   * @return  The changelog entry listener that will be used for this request,
1421   *          or {@code null} if the entries will be made available in the
1422   *          extended result.
1423   */
1424  @Nullable()
1425  public ChangelogEntryListener getEntryListener()
1426  {
1427    return entryListener;
1428  }
1429
1430
1431
1432  /**
1433   * {@inheritDoc}
1434   */
1435  @Override()
1436  @NotNull()
1437  public GetChangelogBatchExtendedResult process(
1438              @NotNull final LDAPConnection connection, final int depth)
1439         throws LDAPException
1440  {
1441    final IntermediateResponseListener l = getIntermediateResponseListener();
1442    if (l != null)
1443    {
1444      throw new LDAPException(ResultCode.PARAM_ERROR,
1445           ERR_GET_CHANGELOG_BATCH_REQ_IR_LISTENER_NOT_ALLOWED.get());
1446    }
1447
1448    final GetChangelogBatchIntermediateResponseListener listener;
1449    if (entryListener == null)
1450    {
1451      listener = new GetChangelogBatchIntermediateResponseListener(
1452           new DefaultChangelogEntryListener(this));
1453    }
1454    else
1455    {
1456      listener =
1457           new GetChangelogBatchIntermediateResponseListener(entryListener);
1458    }
1459
1460    setIntermediateResponseListener(listener);
1461
1462    ExtendedResult r;
1463    try
1464    {
1465      r = super.process(connection, depth);
1466    }
1467    catch (final LDAPException le)
1468    {
1469      Debug.debugException(le);
1470
1471      r = new ExtendedResult(getLastMessageID(), le.getResultCode(),
1472           le.getDiagnosticMessage(), le.getMatchedDN(), le.getReferralURLs(),
1473           null, null, le.getResponseControls());
1474    }
1475    finally
1476    {
1477      setIntermediateResponseListener(null);
1478    }
1479
1480    if (entryListener == null)
1481    {
1482      final DefaultChangelogEntryListener defaultEntryListener =
1483           (DefaultChangelogEntryListener) listener.getEntryListener();
1484      return new GetChangelogBatchExtendedResult(r,
1485           defaultEntryListener.getEntryList());
1486    }
1487    else
1488    {
1489      return new GetChangelogBatchExtendedResult(r, listener.getEntryCount());
1490    }
1491  }
1492
1493
1494
1495  /**
1496   * {@inheritDoc}.
1497   */
1498  @Override()
1499  @NotNull()
1500  public GetChangelogBatchExtendedRequest duplicate()
1501  {
1502    return duplicate(getControls());
1503  }
1504
1505
1506
1507  /**
1508   * {@inheritDoc}.
1509   */
1510  @Override()
1511  @NotNull()
1512  public GetChangelogBatchExtendedRequest duplicate(
1513              @Nullable final Control[] controls)
1514  {
1515    final GetChangelogBatchExtendedRequest r =
1516         new GetChangelogBatchExtendedRequest(entryListener, startingPoint,
1517              maxChanges, maxWaitTimeMillis, waitForMaxChanges, includeBaseDNs,
1518              excludeBaseDNs, changeTypes, continueOnMissingChanges,
1519              pareEntriesForUserDN, changeSelectionCriteria,
1520              includeSoftDeletedEntryMods, includeSoftDeletedEntryDeletes,
1521              controls);
1522    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
1523    r.setIntermediateResponseListener(getIntermediateResponseListener());
1524    r.setReferralDepth(getReferralDepth());
1525    r.setReferralConnector(getReferralConnectorInternal());
1526    return r;
1527  }
1528
1529
1530
1531  /**
1532   * {@inheritDoc}
1533   */
1534  @Override()
1535  @NotNull()
1536  public String getExtendedRequestName()
1537  {
1538    return INFO_GET_CHANGELOG_BATCH_REQ_NAME.get();
1539  }
1540
1541
1542
1543  /**
1544   * {@inheritDoc}
1545   */
1546  @Override()
1547  public void toString(@NotNull final StringBuilder buffer)
1548  {
1549    buffer.append("GetChangelogBatchExtendedRequest(startingPoint=");
1550    startingPoint.toString(buffer);
1551
1552    buffer.append(", maxChanges=");
1553    buffer.append(maxChanges);
1554    buffer.append(", maxWaitTimeMillis=");
1555    buffer.append(maxWaitTimeMillis);
1556    buffer.append(", waitForMaxChanges=");
1557    buffer.append(waitForMaxChanges);
1558    buffer.append(", includeBase={");
1559
1560    final Iterator<String> includeIterator = includeBaseDNs.iterator();
1561    while (includeIterator.hasNext())
1562    {
1563      buffer.append('"');
1564      buffer.append(includeIterator.next());
1565      buffer.append('"');
1566      if (includeIterator.hasNext())
1567      {
1568        buffer.append(", ");
1569      }
1570    }
1571
1572    buffer.append("}, excludeBase={");
1573
1574    final Iterator<String> excludeIterator = excludeBaseDNs.iterator();
1575    while (excludeIterator.hasNext())
1576    {
1577      buffer.append('"');
1578      buffer.append(excludeIterator.next());
1579      buffer.append('"');
1580      if (excludeIterator.hasNext())
1581      {
1582        buffer.append(", ");
1583      }
1584    }
1585
1586    buffer.append("}, changeTypes={");
1587
1588    final Iterator<ChangeType> typeIterator = changeTypes.iterator();
1589    while (typeIterator.hasNext())
1590    {
1591      buffer.append(typeIterator.next().getName());
1592      if (typeIterator.hasNext())
1593      {
1594        buffer.append(", ");
1595      }
1596    }
1597
1598    buffer.append("}, continueOnMissingChanges=");
1599    buffer.append(continueOnMissingChanges);
1600
1601    if (pareEntriesForUserDN != null)
1602    {
1603      buffer.append(", pareEntriesForUserDN='");
1604      buffer.append(pareEntriesForUserDN);
1605      buffer.append('\'');
1606    }
1607
1608    if (changeSelectionCriteria != null)
1609    {
1610      buffer.append(", changeSelectionCriteria=");
1611      changeSelectionCriteria.toString(buffer);
1612    }
1613
1614    buffer.append(", includeSoftDeletedEntryMods=");
1615    buffer.append(includeSoftDeletedEntryMods);
1616    buffer.append(", includeSoftDeletedEntryDeletes=");
1617    buffer.append(includeSoftDeletedEntryDeletes);
1618
1619    final Control[] controls = getControls();
1620    if (controls.length > 0)
1621    {
1622      buffer.append(", controls={");
1623      for (int i=0; i < controls.length; i++)
1624      {
1625        if (i > 0)
1626        {
1627          buffer.append(", ");
1628        }
1629
1630        buffer.append(controls[i]);
1631      }
1632      buffer.append('}');
1633    }
1634
1635    buffer.append(')');
1636  }
1637}