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