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