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