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