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