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