001/* 002 * Copyright 2011-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; 022 023 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.Date; 029import java.util.List; 030 031import com.unboundid.ldap.sdk.Attribute; 032import com.unboundid.ldap.sdk.ChangeLogEntry; 033import com.unboundid.ldap.sdk.ChangeType; 034import com.unboundid.ldap.sdk.Entry; 035import com.unboundid.ldap.sdk.LDAPException; 036import com.unboundid.ldap.sdk.Modification; 037import com.unboundid.ldap.sdk.ModificationType; 038import com.unboundid.ldap.sdk.ReadOnlyEntry; 039import com.unboundid.util.NotMutable; 040import com.unboundid.util.ThreadSafety; 041import com.unboundid.util.ThreadSafetyLevel; 042 043import static com.unboundid.ldap.sdk.unboundidds.UnboundIDDSMessages.*; 044 045 046 047/** 048 * This class provides an implementation of a changelog entry which provides 049 * support for all standard changelog entry attributes as well as those unique 050 * to the Ping Identity, UnboundID, and Alcatel-Lucent 8661 Directory Server. 051 * <BR> 052 * <BLOCKQUOTE> 053 * <B>NOTE:</B> This class, and other classes within the 054 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 055 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 056 * server products. These classes provide support for proprietary 057 * functionality or for external specifications that are not considered stable 058 * or mature enough to be guaranteed to work in an interoperable way with 059 * other types of LDAP servers. 060 * </BLOCKQUOTE> 061 */ 062@NotMutable() 063@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 064public final class UnboundIDChangeLogEntry 065 extends ChangeLogEntry 066{ 067 /** 068 * The name of the attribute used to hold the previous values for all 069 * attributes affected by the change. 070 */ 071 public static final String ATTR_BEFORE_VALUES = "ds-changelog-before-values"; 072 073 074 075 /** 076 * The name of the attribute used to hold the resulting values for all 077 * attributes affected by the change. 078 */ 079 public static final String ATTR_AFTER_VALUES = "ds-changelog-after-values"; 080 081 082 083 /** 084 * The name of the attribute used to indicate whether the operation represents 085 * a change to a soft-deleted entry. 086 */ 087 public static final String ATTR_CHANGE_TO_SOFT_DELETED_ENTRY = 088 "ds-change-to-soft-deleted-entry"; 089 090 091 092 /** 093 * The name of the attribute used to hold the values of key attributes from 094 * the entry after the change was applied. 095 */ 096 public static final String ATTR_KEY_VALUES = 097 "ds-changelog-entry-key-attr-values"; 098 099 100 101 /** 102 * The name of the attribute used to hold information about updated attributes 103 * which had more values (whether before the change, after the change, or 104 * both) than allowed to be shown in the before/after values attributes. 105 */ 106 public static final String ATTR_EXCEEDED_MAX_VALUES = 107 "ds-changelog-attr-exceeded-max-values-count"; 108 109 110 111 /** 112 * The name of the attribute used to hold information about the number of 113 * user attributes that may have been excluded by access control and/or 114 * sensitive attribute processing. 115 */ 116 public static final String ATTR_EXCLUDED_USER_ATTR_COUNT = 117 "ds-changelog-num-excluded-user-attributes"; 118 119 120 121 /** 122 * The name of the attribute used to hold information about the number of 123 * operational attributes that may have been excluded by access control and/or 124 * sensitive attribute processing. 125 */ 126 public static final String ATTR_EXCLUDED_OPERATIONAL_ATTR_COUNT = 127 "ds-changelog-num-excluded-operational-attributes"; 128 129 130 131 /** 132 * The name of the attribute used to hold information about the names of the 133 * user attributes that may have been excluded by access control and/or 134 * sensitive attribute processing. 135 */ 136 public static final String ATTR_EXCLUDED_USER_ATTR_NAME = 137 "ds-changelog-excluded-user-attribute"; 138 139 140 141 /** 142 * The name of the attribute used to hold information about the names of the 143 * operational attributes that may have been excluded by access control and/or 144 * sensitive attribute processing. 145 */ 146 public static final String ATTR_EXCLUDED_OPERATIONAL_ATTR_NAME = 147 "ds-changelog-excluded-operational-attribute"; 148 149 150 151 /** 152 * The name of the attribute used to hold the entryUUID value for the entry 153 * that was targeted by the change. 154 */ 155 public static final String ATTR_TARGET_UNIQUE_ID = "targetUniqueID"; 156 157 158 159 /** 160 * The name of the attribute used to hold a timestamp of the time the change 161 * was processed. 162 */ 163 public static final String ATTR_CHANGE_TIME = "changeTime"; 164 165 166 167 /** 168 * The name of the attribute used to hold the local change sequence number 169 * assigned to the change. 170 */ 171 public static final String ATTR_LOCAL_CSN = "localCSN"; 172 173 174 175 /** 176 * The name of the attribute used to hold the DN of the soft-deleted entry 177 * resulting from a soft delete operation. 178 */ 179 public static final String ATTR_SOFT_DELETE_TO_DN = "ds-soft-delete-entry-dn"; 180 181 182 183 /** 184 * The name of the attribute used to hold the names of the attributes targeted 185 * by the change. 186 */ 187 public static final String ATTR_TARGET_ATTRIBUTE = 188 "ds-changelog-target-attribute"; 189 190 191 192 /** 193 * The name of the attribute used to hold the DN of the soft-deleted entry 194 * from which the content of an undelete was obtained. 195 */ 196 public static final String ATTR_UNDELETE_FROM_DN = "ds-undelete-from-dn"; 197 198 199 200 /** 201 * The name of the attribute used to hold information about virtual values 202 * for an add or delete operation. 203 */ 204 public static final String ATTR_VIRTUAL_ATTRS = 205 "ds-changelog-virtual-attributes"; 206 207 208 209 /** 210 * The name of the attribute used to hold information about virtual values 211 * for modified attributes before the change. 212 */ 213 public static final String ATTR_BEFORE_VIRTUAL_VALUES = 214 "ds-changelog-before-virtual-values"; 215 216 217 218 /** 219 * The name of the attribute used to hold information about virtual values 220 * for modified attributes after the change. 221 */ 222 public static final String ATTR_AFTER_VIRTUAL_VALUES = 223 "ds-changelog-after-virtual-values"; 224 225 226 227 /** 228 * The name of the attribute used to hold information about virtual values 229 * for key attributes after the change. 230 */ 231 public static final String ATTR_KEY_VIRTUAL_VALUES = 232 "ds-changelog-entry-key-virtual-values"; 233 234 235 236 /** 237 * The name of the attribute used to hold information about updated attributes 238 * which had more virtual values (whether before the change, after the change, 239 * or both) than allowed to be shown in the before/after values attributes. 240 */ 241 public static final String ATTR_VIRTUAL_EXCEEDED_MAX_VALUES = 242 "ds-changelog-virtual-attr-exceeded-max-values-count"; 243 244 245 246 /** 247 * The name of the attribute used to hold the entryUUID values for the 248 * notification destinations matched by the change. 249 */ 250 public static final String ATTR_NOTIFICATION_DESTINATION_ENTRY_UUID = 251 "ds-notification-destination-entry-uuid"; 252 253 254 255 /** 256 * The name of the attribute used to hold a number of properties related to 257 * the notification matched by the change. 258 */ 259 public static final String ATTR_NOTIFICATION_PROPERTIES = 260 "ds-changelog-notification-properties"; 261 262 263 264 /** 265 * The serial version UID for this serializable class. 266 */ 267 private static final long serialVersionUID = -6127912254495185946L; 268 269 270 271 // Indicates whether the changelog record represents a change to a 272 // soft-deleted entry. 273 private final Boolean changeToSoftDeletedEntry; 274 275 // The time that the change was processed. 276 private final Date changeTime; 277 278 // The number of user attributes excluded by access control and/or sensitive 279 // attribute processing. 280 private final Integer numExcludedUserAttributes; 281 282 // The number of operational attributes excluded by access control and/or 283 // sensitive attribute processing. 284 private final Integer numExcludedOperationalAttributes; 285 286 // The names of virtual attributes as they appeared in the entry after an add 287 // or before a delete operation. 288 private final List<Attribute> entryVirtualAttributes; 289 290 // The values of key attributes as they appeared in the entry after the change 291 // was applied (or before the delete if the entry was removed). 292 private final List<Attribute> keyEntryAttributes; 293 294 // The virtual values of key attributes as they appeared in the entry after 295 // the change was applied (or before the delete if the entry was removed). 296 private final List<Attribute> keyEntryVirtualAttributes; 297 298 // The updated attributes as they appeared in the entry after the change was 299 // applied. 300 private final List<Attribute> updatedAttributesAfterChange; 301 302 // The updated attributes as they appeared in the entry before the change was 303 // applied. 304 private final List<Attribute> updatedAttributesBeforeChange; 305 306 // The virtual values of updated attributes as they appeared in the entry 307 // after the change was applied. 308 private final List<Attribute> updatedVirtualAttributesAfterChange; 309 310 // The virtual values of updated attributes as they appeared in the entry 311 // before the change was applied. 312 private final List<Attribute> updatedVirtualAttributesBeforeChange; 313 314 // Information about updated attributes that had more values than are allowed 315 // to be included in the ds-changelog-before-values or 316 // ds-changelog-after-values attributes. 317 private final List<ChangeLogEntryAttributeExceededMaxValuesCount> 318 attributesThatExceededMaxValuesCount; 319 320 // Information about updated attributes that had more virtual values than are 321 // allowed to be included in the ds-changelog-before-virtual-values or 322 // ds-changelog-after-virtual-values attributes. 323 private final List<ChangeLogEntryAttributeExceededMaxValuesCount> 324 virtualAttributesThatExceededMaxValuesCount; 325 326 // The names of user attributes excluded by access control and/or sensitive 327 // attribute processing. 328 private final List<String> excludedUserAttributeNames; 329 330 // The names of operational attributes excluded by access control and/or 331 // sensitive attribute processing. 332 private final List<String> excludedOperationalAttributeNames; 333 334 // The entryUUID values for the notification destinations matched by the 335 // change. 336 private final List<String> notificationDestinationEntryUUIDs; 337 338 // The values of any notification properties for the change. 339 private final List<String> notificationProperties; 340 341 // The names of the attributes targeted by the change. 342 private final List<String> targetAttributeNames; 343 344 // The local change sequence number for the change. 345 private final String localCSN; 346 347 // The DN of the soft-deleted entry resulting from a soft delete operation. 348 private final String softDeleteToDN; 349 350 // The entryUUID value for the target entry. 351 private final String targetUniqueID; 352 353 // The DN of the soft-deleted entry from which the content of an undelete 354 // operation was created. 355 private final String undeleteFromDN; 356 357 358 359 /** 360 * Creates a new UnboundID changelog entry object from the provided entry. 361 * 362 * @param entry The entry from which to create this changelog entry. 363 * 364 * @throws LDAPException If the provided entry cannot be parsed as a 365 * changelog entry. 366 */ 367 public UnboundIDChangeLogEntry(final Entry entry) 368 throws LDAPException 369 { 370 super(entry); 371 372 final String targetDN = entry.getAttributeValue(ATTR_TARGET_DN); 373 374 targetUniqueID = entry.getAttributeValue(ATTR_TARGET_UNIQUE_ID); 375 localCSN = entry.getAttributeValue(ATTR_LOCAL_CSN); 376 changeTime = entry.getAttributeValueAsDate(ATTR_CHANGE_TIME); 377 softDeleteToDN = entry.getAttributeValue(ATTR_SOFT_DELETE_TO_DN); 378 undeleteFromDN = entry.getAttributeValue(ATTR_UNDELETE_FROM_DN); 379 380 changeToSoftDeletedEntry = 381 entry.getAttributeValueAsBoolean(ATTR_CHANGE_TO_SOFT_DELETED_ENTRY); 382 383 if (entry.hasAttribute(ATTR_VIRTUAL_ATTRS)) 384 { 385 entryVirtualAttributes = parseAddAttributeList(entry, ATTR_VIRTUAL_ATTRS, 386 targetDN); 387 } 388 else 389 { 390 entryVirtualAttributes = Collections.emptyList(); 391 } 392 393 if (entry.hasAttribute(ATTR_BEFORE_VALUES)) 394 { 395 updatedAttributesBeforeChange = parseAddAttributeList(entry, 396 ATTR_BEFORE_VALUES, targetDN); 397 } 398 else 399 { 400 updatedAttributesBeforeChange = Collections.emptyList(); 401 } 402 403 if (entry.hasAttribute(ATTR_BEFORE_VIRTUAL_VALUES)) 404 { 405 updatedVirtualAttributesBeforeChange = parseAddAttributeList(entry, 406 ATTR_BEFORE_VIRTUAL_VALUES, targetDN); 407 } 408 else 409 { 410 updatedVirtualAttributesBeforeChange = Collections.emptyList(); 411 } 412 413 if (entry.hasAttribute(ATTR_AFTER_VALUES)) 414 { 415 updatedAttributesAfterChange = parseAddAttributeList(entry, 416 ATTR_AFTER_VALUES, targetDN); 417 } 418 else 419 { 420 updatedAttributesAfterChange = Collections.emptyList(); 421 } 422 423 if (entry.hasAttribute(ATTR_AFTER_VIRTUAL_VALUES)) 424 { 425 updatedVirtualAttributesAfterChange = parseAddAttributeList(entry, 426 ATTR_AFTER_VIRTUAL_VALUES, targetDN); 427 } 428 else 429 { 430 updatedVirtualAttributesAfterChange = Collections.emptyList(); 431 } 432 433 if (entry.hasAttribute(ATTR_KEY_VALUES)) 434 { 435 keyEntryAttributes = 436 parseAddAttributeList(entry, ATTR_KEY_VALUES, targetDN); 437 } 438 else 439 { 440 keyEntryAttributes = Collections.emptyList(); 441 } 442 443 if (entry.hasAttribute(ATTR_KEY_VIRTUAL_VALUES)) 444 { 445 keyEntryVirtualAttributes = 446 parseAddAttributeList(entry, ATTR_KEY_VIRTUAL_VALUES, targetDN); 447 } 448 else 449 { 450 keyEntryVirtualAttributes = Collections.emptyList(); 451 } 452 453 final Attribute exceededMaxValues = 454 entry.getAttribute(ATTR_EXCEEDED_MAX_VALUES); 455 if (exceededMaxValues == null) 456 { 457 attributesThatExceededMaxValuesCount = Collections.emptyList(); 458 } 459 else 460 { 461 final String[] values = exceededMaxValues.getValues(); 462 final ArrayList<ChangeLogEntryAttributeExceededMaxValuesCount> l = 463 new ArrayList<ChangeLogEntryAttributeExceededMaxValuesCount>( 464 values.length); 465 for (final String value : values) 466 { 467 l.add(new ChangeLogEntryAttributeExceededMaxValuesCount(value)); 468 } 469 attributesThatExceededMaxValuesCount = Collections.unmodifiableList(l); 470 } 471 472 final Attribute virtualExceededMaxValues = 473 entry.getAttribute(ATTR_VIRTUAL_EXCEEDED_MAX_VALUES); 474 if (virtualExceededMaxValues == null) 475 { 476 virtualAttributesThatExceededMaxValuesCount = Collections.emptyList(); 477 } 478 else 479 { 480 final String[] values = virtualExceededMaxValues.getValues(); 481 final ArrayList<ChangeLogEntryAttributeExceededMaxValuesCount> l = 482 new ArrayList<ChangeLogEntryAttributeExceededMaxValuesCount>( 483 values.length); 484 for (final String value : values) 485 { 486 l.add(new ChangeLogEntryAttributeExceededMaxValuesCount(value)); 487 } 488 virtualAttributesThatExceededMaxValuesCount = 489 Collections.unmodifiableList(l); 490 } 491 492 numExcludedUserAttributes = 493 entry.getAttributeValueAsInteger(ATTR_EXCLUDED_USER_ATTR_COUNT); 494 numExcludedOperationalAttributes = 495 entry.getAttributeValueAsInteger(ATTR_EXCLUDED_OPERATIONAL_ATTR_COUNT); 496 497 final String[] excludedUserAttrNames = 498 entry.getAttributeValues(ATTR_EXCLUDED_USER_ATTR_NAME); 499 if (excludedUserAttrNames == null) 500 { 501 excludedUserAttributeNames = Collections.emptyList(); 502 } 503 else 504 { 505 excludedUserAttributeNames = Collections.unmodifiableList( 506 new ArrayList<String>(Arrays.asList(excludedUserAttrNames))); 507 } 508 509 final String[] excludedOpAttrNames = 510 entry.getAttributeValues(ATTR_EXCLUDED_OPERATIONAL_ATTR_NAME); 511 if (excludedOpAttrNames == null) 512 { 513 excludedOperationalAttributeNames = Collections.emptyList(); 514 } 515 else 516 { 517 excludedOperationalAttributeNames = Collections.unmodifiableList( 518 new ArrayList<String>(Arrays.asList(excludedOpAttrNames))); 519 } 520 521 final String[] targetAttrNames = 522 entry.getAttributeValues(ATTR_TARGET_ATTRIBUTE); 523 if (targetAttrNames == null) 524 { 525 targetAttributeNames = Collections.emptyList(); 526 } 527 else 528 { 529 targetAttributeNames = Collections.unmodifiableList( 530 new ArrayList<String>(Arrays.asList(targetAttrNames))); 531 } 532 533 final String[] notificationUUIDValues = 534 entry.getAttributeValues(ATTR_NOTIFICATION_DESTINATION_ENTRY_UUID); 535 if (notificationUUIDValues == null) 536 { 537 notificationDestinationEntryUUIDs = Collections.emptyList(); 538 } 539 else 540 { 541 notificationDestinationEntryUUIDs = Collections.unmodifiableList( 542 new ArrayList<String>(Arrays.asList(notificationUUIDValues))); 543 } 544 545 final String[] notificationPropertyValues = 546 entry.getAttributeValues(ATTR_NOTIFICATION_PROPERTIES); 547 if (notificationPropertyValues == null) 548 { 549 notificationProperties = Collections.emptyList(); 550 } 551 else 552 { 553 notificationProperties = Collections.unmodifiableList( 554 new ArrayList<String>(Arrays.asList(notificationPropertyValues))); 555 } 556 } 557 558 559 560 /** 561 * Retrieves the entryUUID value of the entry targeted by the change, if 562 * available. 563 * 564 * @return The entryUUID value of the entry targeted by the change, or 565 * {@code null} if it was not included in the changelog entry. 566 */ 567 public String getTargetUniqueID() 568 { 569 return targetUniqueID; 570 } 571 572 573 574 /** 575 * Retrieves the local change sequence number (CSN) for the change, if 576 * available. 577 * 578 * @return The local CSN for the change, or {@code null} if it was not 579 * included in the changelog entry. 580 */ 581 public String getLocalCSN() 582 { 583 return localCSN; 584 } 585 586 587 588 /** 589 * Retrieves the time that the change was processed, if available. 590 * 591 * @return The time that the change was processed, or {@code null} if it was 592 * not included in the changelog entry. 593 */ 594 public Date getChangeTime() 595 { 596 return changeTime; 597 } 598 599 600 601 /** 602 * Retrieves the attribute list for an add changelog entry, optionally 603 * including information about virtual attributes. 604 * 605 * @param includeVirtual Indicates whether to include both real and virtual 606 * values (if {@code true}, or only real values (if 607 * {@code false}), for the attributes to be returned. 608 * 609 * @return The attribute list for an add changelog entry, optionally 610 * including virtual attributes, or {@code null} if this changelog 611 * entry does not represent an add operation. 612 */ 613 public List<Attribute> getAddAttributes(final boolean includeVirtual) 614 { 615 if (includeVirtual && (getChangeType() == ChangeType.ADD) && 616 (! entryVirtualAttributes.isEmpty())) 617 { 618 final Entry e = new Entry(getTargetDN(), getAddAttributes()); 619 for (final Attribute a : entryVirtualAttributes) 620 { 621 e.addAttribute(a); 622 } 623 624 return Collections.unmodifiableList( 625 new ArrayList<Attribute>(e.getAttributes())); 626 } 627 else 628 { 629 return getAddAttributes(); 630 } 631 } 632 633 634 635 /** 636 * Retrieves the virtual attribute list for an add changelog entry, if 637 * available. 638 * 639 * @return The virtual attribute list for an add changelog entry, or 640 * {@code null} if the changelog entry does not represent an add 641 * operation, or an empty list if it does represent an add operation 642 * but no virtual attribute information is available in the 643 * changelog entry. 644 */ 645 public List<Attribute> getAddVirtualAttributes() 646 { 647 if (getChangeType() == ChangeType.ADD) 648 { 649 return entryVirtualAttributes; 650 } 651 else 652 { 653 return null; 654 } 655 } 656 657 658 659 /** 660 * Retrieves the list of attributes contained in the target entry at the time 661 * that it was deleted, optionally including information about virtual 662 * attributes. 663 * 664 * @param includeVirtual Indicates whether to include both real and virtual 665 * values (if {@code true}, or only real values (if 666 * {@code false}), for the attributes to be returned. 667 * 668 * @return The list of attributes contained in the target entry at the time 669 * that it was deleted, optionally including virtual attributes, or 670 * {@code null} if this changelog entry does not represent a delete 671 * operation or no deleted attribute information is available. 672 */ 673 public List<Attribute> getDeletedEntryAttributes( 674 final boolean includeVirtual) 675 { 676 if (includeVirtual && (getChangeType() == ChangeType.DELETE) && 677 (! entryVirtualAttributes.isEmpty())) 678 { 679 final Entry e; 680 final List<Attribute> realAttrs = getDeletedEntryAttributes(); 681 if (realAttrs != null) 682 { 683 e = new Entry(getTargetDN(), realAttrs); 684 for (final Attribute a : entryVirtualAttributes) 685 { 686 e.addAttribute(a); 687 } 688 } 689 else 690 { 691 e = new Entry(getTargetDN(), entryVirtualAttributes); 692 } 693 694 return Collections.unmodifiableList( 695 new ArrayList<Attribute>(e.getAttributes())); 696 } 697 else 698 { 699 return getDeletedEntryAttributes(); 700 } 701 } 702 703 704 705 /** 706 * Retrieves the virtual attribute list for a delete changelog entry, if 707 * available. 708 * 709 * @return The virtual attribute list for a delete changelog entry, or 710 * {@code null} if the changelog entry does not represent a delete 711 * operation, or an empty list if it does represent a delete 712 * operation but no virtual attribute information is available in the 713 * changelog entry. 714 */ 715 public List<Attribute> getDeletedEntryVirtualAttributes() 716 { 717 if (getChangeType() == ChangeType.DELETE) 718 { 719 return entryVirtualAttributes; 720 } 721 else 722 { 723 return null; 724 } 725 } 726 727 728 729 /** 730 * Retrieves a list containing the set of attributes that were updated in the 731 * associated modify or modify DN operation as they appeared before the change 732 * was processed. Virtual attribute information will not be included. 733 * 734 * @return A list containing the set of updated attributes as they appeared 735 * in the entry before the associated modify or modify DN was 736 * processed, or an empty list if the change was not a modify or 737 * modify DN operation, none of the updated attributes previously 738 * existed in the target entry, the previous versions of the updated 739 * attributes had too many values to include, or the server is not 740 * configured to provide (or does not support providing) previous 741 * versions of updated attributes. 742 */ 743 public List<Attribute> getUpdatedAttributesBeforeChange() 744 { 745 return updatedAttributesBeforeChange; 746 } 747 748 749 750 /** 751 * Retrieves a list containing the set of attributes (optionally including 752 * both real and virtual values) that were updated in the associated modify or 753 * modify DN operation as they appeared before the change was processed. 754 * 755 * @param includeVirtual Indicates whether to include both real and virtual 756 * values (if {@code true}, or only real values (if 757 * {@code false}), for the attributes to be returned. 758 * 759 * @return A list containing the set of updated attributes as they appeared 760 * in the entry before the associated modify or modify DN was 761 * processed, or an empty list if the change was not a modify or 762 * modify DN operation, none of the updated attributes previously 763 * existed in the target entry, the previous versions of the updated 764 * attributes had too many values to include, or the server is not 765 * configured to provide (or does not support providing) previous 766 * versions of updated attributes. 767 */ 768 public List<Attribute> getUpdatedAttributesBeforeChange( 769 final boolean includeVirtual) 770 { 771 if (includeVirtual && (! updatedVirtualAttributesBeforeChange.isEmpty())) 772 { 773 final Entry e = new Entry(getTargetDN(), updatedAttributesBeforeChange); 774 for (final Attribute a : updatedVirtualAttributesBeforeChange) 775 { 776 e.addAttribute(a); 777 } 778 779 return Collections.unmodifiableList( 780 new ArrayList<Attribute>(e.getAttributes())); 781 } 782 else 783 { 784 return updatedAttributesBeforeChange; 785 } 786 } 787 788 789 790 /** 791 * Retrieves a list containing information about virtual values for attributes 792 * that were updated in the associated modify or modify DN operation, as they 793 * appeared in the entry before the change was processed. 794 * 795 * @return A list containing information about virtual values for attributes 796 * that were updated in the associated modify or modify DN operation, 797 * as they appeared in the entry before the change was processed. It 798 * may be empty if the change was not a modify or modify DN 799 * operation, or if the changelog entry did not include any 800 * information about virtual attributes as they appeared before the 801 * change. 802 */ 803 public List<Attribute> getUpdatedVirtualAttributesBeforeChange() 804 { 805 return updatedVirtualAttributesBeforeChange; 806 } 807 808 809 810 /** 811 * Retrieves a list containing the set of attributes that were updated in the 812 * associated modify or modify DN operation as they appeared after the change 813 * was processed. Virtual attribute information will not be included. 814 * 815 * @return A list containing the set of updated attributes as they appeared 816 * in the entry after the associated modify or modify DN was 817 * processed, or an empty list if the change was not a modify or 818 * modify DN operation, none of the updated attributes existed in the 819 * entry after the change was processed, the resulting versions of 820 * the updated attributes had too many values to include, or the 821 * server is not configured to provide (or does not support 822 * providing) resulting versions of updated attributes. 823 */ 824 public List<Attribute> getUpdatedAttributesAfterChange() 825 { 826 return updatedAttributesAfterChange; 827 } 828 829 830 831 /** 832 * Retrieves a list containing the set of attributes (optionally including 833 * both real and virtual values) that were updated in the associated modify or 834 * modify DN operation as they appeared after the change was processed. 835 * 836 * @param includeVirtual Indicates whether to include both real and virtual 837 * values (if {@code true}, or only real values (if 838 * {@code false}), for the attributes to be returned. 839 * 840 * @return A list containing the set of updated attributes as they appeared 841 * in the entry after the associated modify or modify DN was 842 * processed, or an empty list if the change was not a modify or 843 * modify DN operation, none of the updated attributes previously 844 * existed in the target entry, the previous versions of the updated 845 * attributes had too many values to include, or the server is not 846 * configured to provide (or does not support providing) previous 847 * versions of updated attributes. 848 */ 849 public List<Attribute> getUpdatedAttributesAfterChange( 850 final boolean includeVirtual) 851 { 852 if (includeVirtual && (! updatedVirtualAttributesAfterChange.isEmpty())) 853 { 854 final Entry e = new Entry(getTargetDN(), updatedAttributesAfterChange); 855 for (final Attribute a : updatedVirtualAttributesAfterChange) 856 { 857 e.addAttribute(a); 858 } 859 860 return Collections.unmodifiableList( 861 new ArrayList<Attribute>(e.getAttributes())); 862 } 863 else 864 { 865 return updatedAttributesAfterChange; 866 } 867 } 868 869 870 871 /** 872 * Retrieves a list containing information about virtual values for attributes 873 * that were updated in the associated modify or modify DN operation, as they 874 * appeared in the entry after the change was processed. 875 * 876 * @return A list containing information about virtual values for attributes 877 * that were updated in the associated modify or modify DN operation, 878 * as they appeared in the entry after the change was processed. It 879 * may be empty if the change was not a modify or modify DN 880 * operation, or if the changelog entry did not include any 881 * information about virtual attributes as they appeared after the 882 * change. 883 */ 884 public List<Attribute> getUpdatedVirtualAttributesAfterChange() 885 { 886 return updatedVirtualAttributesAfterChange; 887 } 888 889 890 891 /** 892 * Retrieves information about any attributes updated in the associated modify 893 * or modify DN operation that had too many values to include in the changelog 894 * entry's set of before and/or after values. 895 * 896 * @return Information about attributes updated in the associated modify or 897 * modify DN operation that had too many values to include in the 898 * changelog entry's set of before and/or after values, or an empty 899 * list if none of the updated attributes had too many values, the 900 * server is not configured to provide (or does not support 901 * providing) previous and resulting versions of updated attributes, 902 * or the change was not the result of a modify or modify DN 903 * operation. 904 */ 905 public List<ChangeLogEntryAttributeExceededMaxValuesCount> 906 getAttributesThatExceededMaxValuesCount() 907 { 908 return attributesThatExceededMaxValuesCount; 909 } 910 911 912 913 /** 914 * Retrieves information about any attributes updated in the associated modify 915 * or modify DN operation that had too many virtual values to include in the 916 * changelog entry's set of before and/or after virtual values. 917 * 918 * @return Information about attributes updated in the associated modify or 919 * modify DN operation that had too many virtual values to include in 920 * the changelog entry's set of before and/or after virtual values, 921 * or an empty list if none of the updated attributes had too many 922 * virtual values, the server is not configured to provide (or does 923 * not support providing) previous and resulting versions of updated 924 * attributes, or the change was not the result of a modify or modify 925 * DN operation. 926 */ 927 public List<ChangeLogEntryAttributeExceededMaxValuesCount> 928 getVirtualAttributesThatExceededMaxValuesCount() 929 { 930 return virtualAttributesThatExceededMaxValuesCount; 931 } 932 933 934 935 /** 936 * Retrieves a list containing key attributes from the target entry, as 937 * defined in the server configuration. For add, modify, and modify DN 938 * operations, this will include the key attributes as they appeared in the 939 * entry after the change had been processed. For delete operations, this 940 * will include the key attributes as they appeared in the entry just before 941 * it was removed. 942 * 943 * @return A list containing key attributes from the target entry, or an 944 * empty list if the associated entry did not have any key attributes 945 * or there are no key attribute types defined in the server 946 * configuration. 947 */ 948 public List<Attribute> getKeyEntryAttributes() 949 { 950 return keyEntryAttributes; 951 } 952 953 954 955 /** 956 * Retrieves a list containing key attributes from the target entry, as 957 * defined in the server configuration. For add, modify, and modify DN 958 * operations, this will include the key attributes as they appeared in the 959 * entry after the change had been processed. For delete operations, this 960 * will include the key attributes as they appeared in the entry just before 961 * it was removed. 962 * 963 * @param includeVirtual Indicates whether to include both real and virtual 964 * values (if {@code true}, or only real values (if 965 * {@code false}), for the attributes to be returned. 966 * 967 * @return A list containing key attributes from the target entry, or an 968 * empty list if the associated entry did not have any key attributes 969 * or there are no key attribute types defined in the server 970 * configuration. 971 */ 972 public List<Attribute> getKeyEntryAttributes(final boolean includeVirtual) 973 { 974 if (includeVirtual && (! keyEntryVirtualAttributes.isEmpty())) 975 { 976 final Entry e = new Entry(getTargetDN(), keyEntryAttributes); 977 for (final Attribute a : keyEntryVirtualAttributes) 978 { 979 e.addAttribute(a); 980 } 981 982 return Collections.unmodifiableList( 983 new ArrayList<Attribute>(e.getAttributes())); 984 } 985 else 986 { 987 return keyEntryAttributes; 988 } 989 } 990 991 992 993 /** 994 * Retrieves a list containing virtual values for key attributes from the 995 * target entry, as defined in the server configuration. For add, modify, and 996 * modify DN operations, this will include the virtual values for key 997 * attributes as they appeared in the entry after the change had been 998 * processed. For delete operations, this will include the virtual values for 999 * key attributes as they appeared in the entry just before it was removed. 1000 * 1001 * @return A list containing virtual values for key attributes from the 1002 * target entry, or an empty list if the associated entry did not 1003 * have any virtual values for key attributes or there are no key 1004 * attribute types defined in the server configuration. 1005 */ 1006 public List<Attribute> getKeyEntryVirtualAttributes() 1007 { 1008 return keyEntryVirtualAttributes; 1009 } 1010 1011 1012 1013 /** 1014 * Retrieves the number of user attributes for which information was excluded 1015 * from the changelog entry by access control and/or sensitive attribute 1016 * processing, if available. 1017 * 1018 * @return The number of user attributes for which information was excluded 1019 * from the changelog entry by access control and/or sensitive 1020 * attribute processing, or -1 if that information was not included 1021 * in the changelog entry. 1022 */ 1023 public int getNumExcludedUserAttributes() 1024 { 1025 if (numExcludedUserAttributes == null) 1026 { 1027 return -1; 1028 } 1029 else 1030 { 1031 return numExcludedUserAttributes; 1032 } 1033 } 1034 1035 1036 1037 /** 1038 * Retrieves the number of operational attributes for which information was 1039 * excluded from the changelog entry by access control and/or sensitive 1040 * attribute processing, if available. 1041 * 1042 * @return The number of operational attributes for which information was 1043 * excluded from the changelog entry by access control and/or 1044 * sensitive attribute processing, or -1 if that information was not 1045 * included in the changelog entry. 1046 */ 1047 public int getNumExcludedOperationalAttributes() 1048 { 1049 if (numExcludedOperationalAttributes == null) 1050 { 1051 return -1; 1052 } 1053 else 1054 { 1055 return numExcludedOperationalAttributes; 1056 } 1057 } 1058 1059 1060 1061 /** 1062 * Retrieves the names of any user attributes for which information was 1063 * excluded from the changelog entry by access control and/or sensitive 1064 * attribute processing, if available. 1065 * 1066 * @return The names of any user attributes for which information was 1067 * excluded from the changelog entry by access control and/or 1068 * sensitive attribute processing, or an empty list if that 1069 * information was not included in the changelog entry. 1070 */ 1071 public List<String> getExcludedUserAttributeNames() 1072 { 1073 return excludedUserAttributeNames; 1074 } 1075 1076 1077 1078 /** 1079 * Retrieves the names of any operational attributes for which information was 1080 * excluded from the changelog entry by access control and/or sensitive 1081 * attribute processing, if available. 1082 * 1083 * @return The names of any operational attributes for which information was 1084 * excluded from the changelog entry by access control and/or 1085 * sensitive processing, or an empty list if that information was not 1086 * included in the changelog entry. 1087 */ 1088 public List<String> getExcludedOperationalAttributeNames() 1089 { 1090 return excludedOperationalAttributeNames; 1091 } 1092 1093 1094 1095 /** 1096 * Indicates whether the associated modify or delete operation targeted a 1097 * soft-deleted entry. 1098 * 1099 * @return {@code true} if the modify or delete operation targeted a 1100 * soft-deleted entry, {@code false} if not, or {@code null} if that 1101 * information was not included in the changelog entry (which likely 1102 * indicates that the operation did not target a soft-deleted 1103 * entry). 1104 */ 1105 public Boolean getChangeToSoftDeletedEntry() 1106 { 1107 return changeToSoftDeletedEntry; 1108 } 1109 1110 1111 1112 /** 1113 * Retrieves the DN of the soft-deleted entry that resulted from the 1114 * associated soft delete operation. 1115 * 1116 * @return The DN of the soft-deleted entry that resulted from the associated 1117 * soft delete operation, or {@code null} if that information was not 1118 * included in the changelog entry (e.g., because it does not 1119 * represent a soft delete operation). 1120 */ 1121 public String getSoftDeleteToDN() 1122 { 1123 return softDeleteToDN; 1124 } 1125 1126 1127 1128 /** 1129 * Retrieves the DN of the soft-deleted entry from which the content of an add 1130 * operation was obtained, if that operation represents an undelete rather 1131 * than a normal add. 1132 * 1133 * @return The DN of the soft-deleted entry from which the content of an add 1134 * operation was obtained, or {@code null} if that information was 1135 * not included in the changelog entry (e.g., because it does not 1136 * represent an undelete operation). 1137 */ 1138 public String getUndeleteFromDN() 1139 { 1140 return undeleteFromDN; 1141 } 1142 1143 1144 1145 /** 1146 * Retrieves the names of any attributes targeted by the change, if available. 1147 * For an add operation, this may include the attributes in the entry that 1148 * was added. For a delete operation, this may include the attributes in the 1149 * entry that was deleted. For a modify operation, this may include the 1150 * attributes targeted by modifications. For a modify DN operation, this may 1151 * include attributes used in the new RDN and potentially any other attributes 1152 * altered during the change. 1153 * <BR><BR> 1154 * Note that this information may not be available in all changelog entries or 1155 * Directory Server versions, and complete information about some changes may 1156 * only be available in some changelog configurations (e.g., information about 1157 * attributes included in delete operations may only be available if 1158 * changelog-deleted-entry-include-attribute is configured, and information 1159 * about changes to non-RDN attributes for modify DN operations may only be 1160 * available if changelog-max-before-after-values is configured). 1161 * 1162 * @return The names of any attributes targeted by the change, or an empty 1163 * list if that information was not included in the changelog entry. 1164 */ 1165 public List<String> getTargetAttributeNames() 1166 { 1167 return targetAttributeNames; 1168 } 1169 1170 1171 1172 /** 1173 * Retrieves a list of the entryUUID values for any notification destinations 1174 * for which the change matches one or more subscriptions. 1175 * 1176 * @return A list of the entryUUID values for any notification destinations 1177 * for which the change matches one or more subscriptions, or an 1178 * empty list if that information was not included in the changelog 1179 * entry. 1180 */ 1181 public List<String> getNotificationDestinationEntryUUIDs() 1182 { 1183 return notificationDestinationEntryUUIDs; 1184 } 1185 1186 1187 1188 /** 1189 * Retrieves a list of any notification properties included in the changelog 1190 * entry. 1191 * 1192 * @return A list of any notification properties included in the changelog 1193 * entry, or an empty list if that information was not included in 1194 * the changelog entry. 1195 */ 1196 public List<String> getNotificationProperties() 1197 { 1198 return notificationProperties; 1199 } 1200 1201 1202 1203 /** 1204 * Retrieves the specified attribute as it appeared in the target entry before 1205 * the change was processed, if available. It will not include any virtual 1206 * values. 1207 * 1208 * @param name The name of the attribute to retrieve as it appeared before 1209 * the change. 1210 * 1211 * @return The requested attribute as it appeared in the target entry before 1212 * the change was processed, or {@code null} if it was not available 1213 * in the changelog entry. 1214 * 1215 * @throws ChangeLogEntryAttributeExceededMaxValuesException If the 1216 * specified attribute had more values before the change than 1217 * may be included in a changelog entry. 1218 */ 1219 public Attribute getAttributeBeforeChange(final String name) 1220 throws ChangeLogEntryAttributeExceededMaxValuesException 1221 { 1222 return getAttributeBeforeChange(name, false); 1223 } 1224 1225 1226 1227 /** 1228 * Retrieves the specified attribute as it appeared in the target entry before 1229 * the change was processed, if available. It may optionally include virtual 1230 * values. 1231 * 1232 * @param name The name of the attribute to retrieve as it 1233 * appeared before the change. 1234 * @param includeVirtual Indicates whether to include both real and virtual 1235 * values (if {@code true}, or only real values (if 1236 * {@code false}), for the attribute to be returned. 1237 * 1238 * @return The requested attribute as it appeared in the target entry before 1239 * the change was processed, or {@code null} if it was not available 1240 * in the changelog entry. 1241 * 1242 * @throws ChangeLogEntryAttributeExceededMaxValuesException If the 1243 * specified attribute had more values before the change than 1244 * may be included in a changelog entry. 1245 */ 1246 public Attribute getAttributeBeforeChange(final String name, 1247 final boolean includeVirtual) 1248 throws ChangeLogEntryAttributeExceededMaxValuesException 1249 { 1250 if (getChangeType() == ChangeType.ADD) 1251 { 1252 return null; 1253 } 1254 1255 for (final Attribute a : getUpdatedAttributesBeforeChange(includeVirtual)) 1256 { 1257 if (a.getName().equalsIgnoreCase(name)) 1258 { 1259 return a; 1260 } 1261 } 1262 1263 for (final ChangeLogEntryAttributeExceededMaxValuesCount a : 1264 attributesThatExceededMaxValuesCount) 1265 { 1266 if (a.getAttributeName().equalsIgnoreCase(name)) 1267 { 1268 // TODO: In the event that the before count was exceeded but the after 1269 // count was not, then we may be able to reconstruct the before values 1270 // if the changes included deleting specific values for the attribute. 1271 throw new ChangeLogEntryAttributeExceededMaxValuesException( 1272 ERR_CHANGELOG_EXCEEDED_BEFORE_VALUE_COUNT.get(name, getTargetDN(), 1273 a.getBeforeCount()), 1274 a); 1275 } 1276 } 1277 1278 if (includeVirtual) 1279 { 1280 for (final ChangeLogEntryAttributeExceededMaxValuesCount a : 1281 virtualAttributesThatExceededMaxValuesCount) 1282 { 1283 if (a.getAttributeName().equalsIgnoreCase(name)) 1284 { 1285 // TODO: In the event that the before count was exceeded but the 1286 // after count was not, then we may be able to reconstruct the before 1287 // values if the changes included deleting specific values for the 1288 // attribute. 1289 throw new ChangeLogEntryAttributeExceededMaxValuesException( 1290 ERR_CHANGELOG_EXCEEDED_VIRTUAL_BEFORE_VALUE_COUNT.get(name, 1291 getTargetDN(), a.getBeforeCount()), 1292 a); 1293 } 1294 } 1295 } 1296 1297 for (final Attribute a : getKeyEntryAttributes(includeVirtual)) 1298 { 1299 if (a.getName().equalsIgnoreCase(name)) 1300 { 1301 return a; 1302 } 1303 } 1304 1305 final List<Attribute> deletedAttrs = 1306 getDeletedEntryAttributes(includeVirtual); 1307 if (deletedAttrs != null) 1308 { 1309 for (final Attribute a : deletedAttrs) 1310 { 1311 if (a.getName().equalsIgnoreCase(name)) 1312 { 1313 return a; 1314 } 1315 } 1316 } 1317 1318 return null; 1319 } 1320 1321 1322 1323 /** 1324 * Retrieves the specified attribute as it appeared in the target entry after 1325 * the change was processed, if available. It will not include any virtual 1326 * values. 1327 * 1328 * @param name The name of the attribute to retrieve as it appeared after 1329 * the change. 1330 * 1331 * @return The requested attribute as it appeared in the target entry after 1332 * the change was processed, or {@code null} if it was not available 1333 * in the changelog entry. 1334 * 1335 * @throws ChangeLogEntryAttributeExceededMaxValuesException If the 1336 * specified attribute had more values before the change than 1337 * may be included in a changelog entry. 1338 */ 1339 public Attribute getAttributeAfterChange(final String name) 1340 throws ChangeLogEntryAttributeExceededMaxValuesException 1341 { 1342 return getAttributeAfterChange(name, false); 1343 } 1344 1345 1346 1347 /** 1348 * Retrieves the specified attribute as it appeared in the target entry after 1349 * the change was processed, if available. It may optionally include virtual 1350 * values. 1351 * 1352 * @param name The name of the attribute to retrieve as it 1353 * appeared after the change. 1354 * @param includeVirtual Indicates whether to include both real and virtual 1355 * values (if {@code true}, or only real values (if 1356 * {@code false}), for the attributes to be returned. 1357 * 1358 * @return The requested attribute as it appeared in the target entry after 1359 * the change was processed, or {@code null} if it was not available 1360 * in the changelog entry. 1361 * 1362 * @throws ChangeLogEntryAttributeExceededMaxValuesException If the 1363 * specified attribute had more values before the change than 1364 * may be included in a changelog entry. 1365 */ 1366 public Attribute getAttributeAfterChange(final String name, 1367 final boolean includeVirtual) 1368 throws ChangeLogEntryAttributeExceededMaxValuesException 1369 { 1370 if (getChangeType() == ChangeType.DELETE) 1371 { 1372 return null; 1373 } 1374 1375 for (final Attribute a : getUpdatedAttributesAfterChange(includeVirtual)) 1376 { 1377 if (a.getName().equalsIgnoreCase(name)) 1378 { 1379 return a; 1380 } 1381 } 1382 1383 for (final Attribute a : getKeyEntryAttributes(includeVirtual)) 1384 { 1385 if (a.getName().equalsIgnoreCase(name)) 1386 { 1387 return a; 1388 } 1389 } 1390 1391 for (final ChangeLogEntryAttributeExceededMaxValuesCount a : 1392 attributesThatExceededMaxValuesCount) 1393 { 1394 if (a.getAttributeName().equalsIgnoreCase(name)) 1395 { 1396 // TODO: In the event that the after count was exceeded but the before 1397 // count was not, then we may be able to reconstruct the after values 1398 // if the changes included adding specific values for the attribute. 1399 throw new ChangeLogEntryAttributeExceededMaxValuesException( 1400 ERR_CHANGELOG_EXCEEDED_AFTER_VALUE_COUNT.get(name, getTargetDN(), 1401 a.getAfterCount()), 1402 a); 1403 } 1404 } 1405 1406 if (includeVirtual) 1407 { 1408 for (final ChangeLogEntryAttributeExceededMaxValuesCount a : 1409 virtualAttributesThatExceededMaxValuesCount) 1410 { 1411 if (a.getAttributeName().equalsIgnoreCase(name)) 1412 { 1413 // TODO: In the event that the after count was exceeded but the 1414 // before count was not, then we may be able to reconstruct the after 1415 // values if the changes included adding specific values for the 1416 // attribute. 1417 throw new ChangeLogEntryAttributeExceededMaxValuesException( 1418 ERR_CHANGELOG_EXCEEDED_VIRTUAL_AFTER_VALUE_COUNT.get(name, 1419 getTargetDN(), a.getAfterCount()), 1420 a); 1421 } 1422 } 1423 } 1424 1425 final List<Attribute> addAttrs = getAddAttributes(includeVirtual); 1426 if (addAttrs != null) 1427 { 1428 for (final Attribute a : addAttrs) 1429 { 1430 if (a.getName().equalsIgnoreCase(name)) 1431 { 1432 return a; 1433 } 1434 } 1435 } 1436 1437 final List<Modification> mods = getModifications(); 1438 if (mods != null) 1439 { 1440 for (final Modification m : mods) 1441 { 1442 if (m.getAttributeName().equalsIgnoreCase(name)) 1443 { 1444 final byte[][] values = m.getValueByteArrays(); 1445 if ((m.getModificationType() == ModificationType.REPLACE) && 1446 (values.length > 0)) 1447 { 1448 return new Attribute(name, values); 1449 } 1450 } 1451 } 1452 } 1453 1454 return null; 1455 } 1456 1457 1458 1459 /** 1460 * Attempts to construct a partial representation of the target entry as it 1461 * appeared before the change was processed. The information contained in the 1462 * constructed entry will be based solely on information contained in the 1463 * changelog entry, including information provided in the deletedEntryAttrs, 1464 * ds-changelog-before-values, ds-changelog-after-values, 1465 * ds-changelog-entry-key-attr-values, and 1466 * ds-changelog-attr-exceeded-max-values-count attributes. It will not 1467 * include any virtual attribute information. 1468 * 1469 * @return A partial representation of the target entry as it appeared before 1470 * the change was processed, or {@code null} if the change was an 1471 * add operation and therefore the entry did not exist before the 1472 * change. 1473 */ 1474 public ReadOnlyEntry constructPartialEntryBeforeChange() 1475 { 1476 return constructPartialEntryBeforeChange(false); 1477 } 1478 1479 1480 1481 /** 1482 * Attempts to construct a partial representation of the target entry as it 1483 * appeared before the change was processed. The information contained in the 1484 * constructed entry will be based solely on information contained in the 1485 * changelog entry, including information provided in the deletedEntryAttrs, 1486 * ds-changelog-before-values, ds-changelog-after-values, 1487 * ds-changelog-entry-key-attr-values, and 1488 * ds-changelog-attr-exceeded-max-values-count attributes, and optionally 1489 * virtual versions of all of those elements. 1490 * 1491 * @param includeVirtual Indicates whether to include both real and virtual 1492 * values (if {@code true}, or only real values (if 1493 * {@code false}), for the attributes to be returned. 1494 * 1495 * @return A partial representation of the target entry as it appeared before 1496 * the change was processed, or {@code null} if the change was an 1497 * add operation and therefore the entry did not exist before the 1498 * change. 1499 */ 1500 public ReadOnlyEntry constructPartialEntryBeforeChange( 1501 final boolean includeVirtual) 1502 { 1503 if (getChangeType() == ChangeType.ADD) 1504 { 1505 return null; 1506 } 1507 1508 final Entry e = new Entry(getTargetDN()); 1509 1510 // If there is a set of deleted entry attributes available, then use them. 1511 final List<Attribute> deletedEntryAttrs = 1512 getDeletedEntryAttributes(includeVirtual); 1513 if (deletedEntryAttrs != null) 1514 { 1515 for (final Attribute a : deletedEntryAttrs) 1516 { 1517 e.addAttribute(a); 1518 } 1519 } 1520 1521 // If there is a set of before attributes, then use them. 1522 for (final Attribute a : getUpdatedAttributesBeforeChange(includeVirtual)) 1523 { 1524 e.addAttribute(a); 1525 } 1526 1527 // If there is a set of key attributes, then only use them if the 1528 // associated attributes aren't already in the entry and aren't in either 1529 // the after values and exceeded max values count. 1530 for (final Attribute a : getKeyEntryAttributes(includeVirtual)) 1531 { 1532 boolean shouldExclude = e.hasAttribute(a.getName()); 1533 1534 for (final Attribute ba : getUpdatedAttributesAfterChange(includeVirtual)) 1535 { 1536 if (ba.getName().equalsIgnoreCase(a.getName())) 1537 { 1538 shouldExclude = true; 1539 } 1540 } 1541 1542 for (final ChangeLogEntryAttributeExceededMaxValuesCount ea : 1543 attributesThatExceededMaxValuesCount) 1544 { 1545 if (ea.getAttributeName().equalsIgnoreCase(a.getName())) 1546 { 1547 // TODO: In the event that the before count was exceeded but the 1548 // after count was not, then we may be able to reconstruct the before 1549 // values if the changes included deleting specific values for the 1550 // attribute. 1551 shouldExclude = true; 1552 } 1553 } 1554 1555 if (includeVirtual) 1556 { 1557 for (final ChangeLogEntryAttributeExceededMaxValuesCount ea : 1558 virtualAttributesThatExceededMaxValuesCount) 1559 { 1560 if (ea.getAttributeName().equalsIgnoreCase(a.getName())) 1561 { 1562 // TODO: In the event that the before count was exceeded but the 1563 // after count was not, then we may be able to reconstruct the 1564 // before values if the changes included deleting specific values 1565 // for the attribute. 1566 shouldExclude = true; 1567 } 1568 } 1569 } 1570 1571 if (! shouldExclude) 1572 { 1573 e.addAttribute(a); 1574 } 1575 } 1576 1577 // NOTE: Although we could possibly get additional attribute values from 1578 // the entry's RDN, that can't be considered authoritative because those 1579 // same attributes may have additional values that aren't in the RDN, and we 1580 // don't want to include an attribute without the entire set of values. 1581 1582 return new ReadOnlyEntry(e); 1583 } 1584 1585 1586 1587 /** 1588 * Attempts to construct a partial representation of the target entry as it 1589 * appeared after the change was processed. The information contained in the 1590 * constructed entry will be based solely on information contained in the 1591 * changelog entry, including information provided in the changes, 1592 * ds-changelog-after-values, and ds-changelog-entry-key-attr-values 1593 * attributes. It will not include any virtual attribute information. 1594 * 1595 * @return A partial representation of the target entry as it appeared after 1596 * the change was processed, or {@code null} if the change was a 1597 * delete operation and therefore did not exist after the change. 1598 */ 1599 public ReadOnlyEntry constructPartialEntryAfterChange() 1600 { 1601 return constructPartialEntryAfterChange(false); 1602 } 1603 1604 1605 1606 /** 1607 * Attempts to construct a partial representation of the target entry as it 1608 * appeared after the change was processed. The information contained in the 1609 * constructed entry will be based solely on information contained in the 1610 * changelog entry, including information provided in the changes, 1611 * ds-changelog-after-values, and ds-changelog-entry-key-attr-values 1612 * attributes, and optionally virtual versions of all of those elements. 1613 * 1614 * @param includeVirtual Indicates whether to include both real and virtual 1615 * values (if {@code true}, or only real values (if 1616 * {@code false}), for the attributes to be returned. 1617 * 1618 * @return A partial representation of the target entry as it appeared after 1619 * the change was processed, or {@code null} if the change was a 1620 * delete operation and therefore did not exist after the change. 1621 */ 1622 public ReadOnlyEntry constructPartialEntryAfterChange( 1623 final boolean includeVirtual) 1624 { 1625 final Entry e; 1626 switch (getChangeType()) 1627 { 1628 case ADD: 1629 case MODIFY: 1630 e = new Entry(getTargetDN()); 1631 break; 1632 1633 case MODIFY_DN: 1634 e = new Entry(getNewDN()); 1635 break; 1636 1637 case DELETE: 1638 default: 1639 return null; 1640 } 1641 1642 1643 // If there is a set of add attributes, then use them. 1644 final List<Attribute> addAttrs = getAddAttributes(includeVirtual); 1645 if (addAttrs != null) 1646 { 1647 for (final Attribute a : addAttrs) 1648 { 1649 e.addAttribute(a); 1650 } 1651 } 1652 1653 // If there is a set of modifications and any of them are replace 1654 // modifications with a set of values, then we can use them to determine 1655 // the new values of those attributes. 1656 final List<Modification> mods = getModifications(); 1657 if (mods != null) 1658 { 1659 for (final Modification m : mods) 1660 { 1661 final byte[][] values = m.getValueByteArrays(); 1662 if ((m.getModificationType() == ModificationType.REPLACE) && 1663 (values.length > 0)) 1664 { 1665 e.addAttribute(m.getAttributeName(), values); 1666 } 1667 } 1668 } 1669 1670 // If there is a set of after attributes, then use them. 1671 for (final Attribute a : getUpdatedAttributesAfterChange(includeVirtual)) 1672 { 1673 e.addAttribute(a); 1674 } 1675 1676 // If there is a set of key attributes, then use them. 1677 for (final Attribute a : getKeyEntryAttributes(includeVirtual)) 1678 { 1679 e.addAttribute(a); 1680 } 1681 1682 // TODO: In the event that the after count was exceeded but the before 1683 // count was not, then we may be able to reconstruct the after values if the 1684 // changes included adding specific values for the attribute. 1685 1686 // NOTE: Although we could possibly get additional attribute values from 1687 // the entry's RDN, that can't be considered authoritative because those 1688 // same attributes may have additional values that aren't in the RDN, and we 1689 // don't want to include an attribute without the entire set of values. 1690 1691 return new ReadOnlyEntry(e); 1692 } 1693}