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