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