001 /*
002 * Copyright 2009-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2009-2013 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;
022
023
024
025 import java.io.Serializable;
026 import java.util.ArrayList;
027 import java.util.Collection;
028 import java.util.Collections;
029 import java.util.Date;
030 import java.util.Iterator;
031 import java.util.List;
032 import java.util.Set;
033
034 import com.unboundid.util.ByteStringBuffer;
035 import com.unboundid.util.NotMutable;
036 import com.unboundid.util.ThreadSafety;
037 import com.unboundid.util.ThreadSafetyLevel;
038
039 import static com.unboundid.util.Validator.*;
040
041
042
043 /**
044 * This class provides a data structure that represents a compact version of an
045 * entry. This is basically the same as an {@code Entry} object, except that
046 * it stores the information in a more compact form that requires less space in
047 * memory. This may be useful in applications that need to hold a large number
048 * of entries in memory. Note that performance of some methods in this class
049 * may be significantly worse than the performance of the corresponding methods
050 * in the {@code Entry} class.
051 *
052 * @see Entry
053 */
054 @NotMutable()
055 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
056 public final class CompactEntry
057 implements Serializable
058 {
059 /**
060 * The serial version UID for this serializable class.
061 */
062 private static final long serialVersionUID = 8067151651120794058L;
063
064
065
066 // The set of attributes for this entry.
067 private final CompactAttribute[] attributes;
068
069 // The hash code for this entry, if it has been calculated.
070 private int hashCode;
071
072 // The DN for this entry.
073 private final String dn;
074
075
076
077 /**
078 * Creates a new compact entry from the provided entry.
079 *
080 * @param entry The entry to use to create this compact entry. It must not
081 * be {@code null}.
082 */
083 public CompactEntry(final Entry entry)
084 {
085 ensureNotNull(entry);
086
087 dn = entry.getDN();
088 hashCode = -1;
089
090 final Collection<Attribute> attrs = entry.getAttributes();
091 attributes = new CompactAttribute[attrs.size()];
092 final Iterator<Attribute> iterator = attrs.iterator();
093 for (int i=0; i < attributes.length; i++)
094 {
095 attributes[i] = new CompactAttribute(iterator.next());
096 }
097 }
098
099
100
101 /**
102 * Retrieves the DN for this entry.
103 *
104 * @return The DN for this entry.
105 */
106 public String getDN()
107 {
108 return dn;
109 }
110
111
112
113 /**
114 * Retrieves the parsed DN for this entry.
115 *
116 * @return The parsed DN for this entry.
117 *
118 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
119 */
120 public DN getParsedDN()
121 throws LDAPException
122 {
123 return new DN(dn);
124 }
125
126
127
128 /**
129 * Retrieves the RDN for this entry.
130 *
131 * @return The RDN for this entry, or {@code null} if the DN is the null DN.
132 *
133 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
134 */
135 public RDN getRDN()
136 throws LDAPException
137 {
138 return getParsedDN().getRDN();
139 }
140
141
142
143 /**
144 * Retrieves the parent DN for this entry.
145 *
146 * @return The parent DN for this entry, or {@code null} if there is no
147 * parent.
148 *
149 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
150 */
151 public DN getParentDN()
152 throws LDAPException
153 {
154 return getParsedDN().getParent();
155 }
156
157
158
159 /**
160 * Retrieves the parent DN for this entry as a string.
161 *
162 * @return The parent DN for this entry as a string, or {@code null} if there
163 * is no parent.
164 *
165 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
166 */
167 public String getParentDNString()
168 throws LDAPException
169 {
170 return getParsedDN().getParentString();
171 }
172
173
174
175 /**
176 * Indicates whether this entry contains the specified attribute.
177 *
178 * @param attributeName The name of the attribute for which to make the
179 * determination. It must not be {@code null}.
180 *
181 * @return {@code true} if this entry contains the specified attribute, or
182 * {@code false} if not.
183 */
184 public boolean hasAttribute(final String attributeName)
185 {
186 ensureNotNull(attributeName);
187
188 for (final CompactAttribute a : attributes)
189 {
190 if (a.getName().equalsIgnoreCase(attributeName))
191 {
192 return true;
193 }
194 }
195
196 return false;
197 }
198
199
200
201 /**
202 * Indicates whether this entry contains the specified attribute. It will
203 * only return {@code true} if this entry contains an attribute with the same
204 * name and exact set of values.
205 *
206 * @param attribute The attribute for which to make the determination. It
207 * must not be {@code null}.
208 *
209 * @return {@code true} if this entry contains the specified attribute, or
210 * {@code false}.
211 */
212 public boolean hasAttribute(final Attribute attribute)
213 {
214 ensureNotNull(attribute);
215
216 for (final CompactAttribute a : attributes)
217 {
218 if (a.toAttribute().equals(attribute))
219 {
220 return true;
221 }
222 }
223
224 return false;
225 }
226
227
228
229 /**
230 * Indicates whether this entry contains an attribute with the given name and
231 * value.
232 *
233 * @param attributeName The name of the attribute for which to make the
234 * determination. It must not be {@code null}.
235 * @param attributeValue The value for which to make the determination. It
236 * must not be {@code null}.
237 *
238 * @return {@code true} if this entry contains an attribute with the
239 * specified name and value, or {@code false} if not.
240 */
241 public boolean hasAttributeValue(final String attributeName,
242 final String attributeValue)
243 {
244 ensureNotNull(attributeName, attributeValue);
245
246 for (final CompactAttribute a : attributes)
247 {
248 if (a.getName().equalsIgnoreCase(attributeName) &&
249 a.toAttribute().hasValue(attributeValue))
250 {
251 return true;
252 }
253 }
254
255 return false;
256 }
257
258
259
260 /**
261 * Indicates whether this entry contains an attribute with the given name and
262 * value.
263 *
264 * @param attributeName The name of the attribute for which to make the
265 * determination. It must not be {@code null}.
266 * @param attributeValue The value for which to make the determination. It
267 * must not be {@code null}.
268 *
269 * @return {@code true} if this entry contains an attribute with the
270 * specified name and value, or {@code false} if not.
271 */
272 public boolean hasAttributeValue(final String attributeName,
273 final byte[] attributeValue)
274 {
275 ensureNotNull(attributeName, attributeValue);
276
277 for (final CompactAttribute a : attributes)
278 {
279 if (a.getName().equalsIgnoreCase(attributeName) &&
280 a.toAttribute().hasValue(attributeValue))
281 {
282 return true;
283 }
284 }
285
286 return false;
287 }
288
289
290
291 /**
292 * Indicates whether this entry contains the specified object class.
293 *
294 * @param objectClassName The name of the object class for which to make the
295 * determination. It must not be {@code null}.
296 *
297 * @return {@code true} if this entry contains the specified object class, or
298 * {@code false} if not.
299 */
300 public boolean hasObjectClass(final String objectClassName)
301 {
302 return hasAttributeValue("objectClass", objectClassName);
303 }
304
305
306
307 /**
308 * Retrieves the set of attributes contained in this entry.
309 *
310 * @return The set of attributes contained in this entry.
311 */
312 public Collection<Attribute> getAttributes()
313 {
314 final ArrayList<Attribute> attrList =
315 new ArrayList<Attribute>(attributes.length);
316 for (final CompactAttribute a : attributes)
317 {
318 attrList.add(a.toAttribute());
319 }
320
321 return Collections.unmodifiableCollection(attrList);
322 }
323
324
325
326 /**
327 * Retrieves the attribute with the specified name.
328 *
329 * @param attributeName The name of the attribute to retrieve. It must not
330 * be {@code null}.
331 *
332 * @return The requested attribute from this entry, or {@code null} if the
333 * specified attribute is not present in this entry.
334 */
335 public Attribute getAttribute(final String attributeName)
336 {
337 ensureNotNull(attributeName);
338
339 for (final CompactAttribute a : attributes)
340 {
341 if (a.getName().equalsIgnoreCase(attributeName))
342 {
343 return a.toAttribute();
344 }
345 }
346
347 return null;
348 }
349
350
351
352 /**
353 * Retrieves the list of attributes with the given base name and all of the
354 * specified options.
355 *
356 * @param baseName The base name (without any options) for the attribute to
357 * retrieve. It must not be {@code null}.
358 * @param options The set of options that should be included in the
359 * attributes that are returned. It may be empty or
360 * {@code null} if all attributes with the specified base
361 * name should be returned, regardless of the options that
362 * they contain (if any).
363 *
364 * @return The list of attributes with the given base name and all of the
365 * specified options. It may be empty if there are no attributes
366 * with the specified base name and set of options.
367 */
368 public List<Attribute> getAttributesWithOptions(final String baseName,
369 final Set<String> options)
370 {
371 return toEntry().getAttributesWithOptions(baseName, options);
372 }
373
374
375
376 /**
377 * Retrieves the value for the specified attribute, if available. If the
378 * attribute has more than one value, then the first value will be returned.
379 *
380 * @param attributeName The name of the attribute for which to retrieve the
381 * value. It must not be {@code null}.
382 *
383 * @return The value for the specified attribute, or {@code null} if that
384 * attribute is not available.
385 */
386 public String getAttributeValue(final String attributeName)
387 {
388 ensureNotNull(attributeName);
389
390 for (final CompactAttribute a : attributes)
391 {
392 if (a.getName().equalsIgnoreCase(attributeName))
393 {
394 final String[] values = a.getStringValues();
395 if (values.length > 0)
396 {
397 return values[0];
398 }
399 else
400 {
401 return null;
402 }
403 }
404 }
405
406 return null;
407 }
408
409
410
411 /**
412 * Retrieves the value for the specified attribute as a byte array, if
413 * available. If the attribute has more than one value, then the first value
414 * will be returned.
415 *
416 * @param attributeName The name of the attribute for which to retrieve the
417 * value. It must not be {@code null}.
418 *
419 * @return The value for the specified attribute as a byte array, or
420 * {@code null} if that attribute is not available.
421 */
422 public byte[] getAttributeValueBytes(final String attributeName)
423 {
424 ensureNotNull(attributeName);
425
426 for (final CompactAttribute a : attributes)
427 {
428 if (a.getName().equalsIgnoreCase(attributeName))
429 {
430 final byte[][] values = a.getByteValues();
431 if (values.length > 0)
432 {
433 return values[0];
434 }
435 else
436 {
437 return null;
438 }
439 }
440 }
441
442 return null;
443 }
444
445
446
447 /**
448 * Retrieves the value for the specified attribute as a Boolean, if available.
449 * If the attribute has more than one value, then the first value will be
450 * returned. Values of "true", "t", "yes", "y", "on", and "1" will be
451 * interpreted as {@code TRUE}. Values of "false", "f", "no", "n", "off", and
452 * "0" will be interpreted as {@code FALSE}.
453 *
454 * @param attributeName The name of the attribute for which to retrieve the
455 * value. It must not be {@code null}.
456 *
457 * @return The Boolean value parsed from the specified attribute, or
458 * {@code null} if that attribute is not available or the value
459 * cannot be parsed as a Boolean.
460 */
461 public Boolean getAttributeValueAsBoolean(final String attributeName)
462 {
463 ensureNotNull(attributeName);
464
465 final Attribute a = getAttribute(attributeName);
466 if (a == null)
467 {
468 return null;
469 }
470 else
471 {
472 return a.getValueAsBoolean();
473 }
474 }
475
476
477
478 /**
479 * Retrieves the value for the specified attribute as a Date, formatted using
480 * the generalized time syntax, if available. If the attribute has more than
481 * one value, then the first value will be returned.
482 *
483 * @param attributeName The name of the attribute for which to retrieve the
484 * value. It must not be {@code null}.
485 *
486 * @return The Date value parsed from the specified attribute, or
487 * {@code null} if that attribute is not available or the value
488 * cannot be parsed as a Date.
489 */
490 public Date getAttributeValueAsDate(final String attributeName)
491 {
492 ensureNotNull(attributeName);
493
494 final Attribute a = getAttribute(attributeName);
495 if (a == null)
496 {
497 return null;
498 }
499 else
500 {
501 return a.getValueAsDate();
502 }
503 }
504
505
506
507 /**
508 * Retrieves the value for the specified attribute as a DN, if available. If
509 * the attribute has more than one value, then the first value will be
510 * returned.
511 *
512 * @param attributeName The name of the attribute for which to retrieve the
513 * value. It must not be {@code null}.
514 *
515 * @return The Date value parsed from the specified attribute, or
516 * {@code null} if that attribute is not available or the value
517 * cannot be parsed as a DN.
518 */
519 public DN getAttributeValueAsDN(final String attributeName)
520 {
521 ensureNotNull(attributeName);
522
523 final Attribute a = getAttribute(attributeName);
524 if (a == null)
525 {
526 return null;
527 }
528 else
529 {
530 return a.getValueAsDN();
531 }
532 }
533
534
535
536 /**
537 * Retrieves the value for the specified attribute as an Integer, if
538 * available. If the attribute has more than one value, then the first value
539 * will be returned.
540 *
541 * @param attributeName The name of the attribute for which to retrieve the
542 * value. It must not be {@code null}.
543 *
544 * @return The Integer value parsed from the specified attribute, or
545 * {@code null} if that attribute is not available or the value
546 * cannot be parsed as an Integer.
547 */
548 public Integer getAttributeValueAsInteger(final String attributeName)
549 {
550 ensureNotNull(attributeName);
551
552 final Attribute a = getAttribute(attributeName);
553 if (a == null)
554 {
555 return null;
556 }
557 else
558 {
559 return a.getValueAsInteger();
560 }
561 }
562
563
564
565 /**
566 * Retrieves the value for the specified attribute as a Long, if available.
567 * If the attribute has more than one value, then the first value will be
568 * returned.
569 *
570 * @param attributeName The name of the attribute for which to retrieve the
571 * value. It must not be {@code null}.
572 *
573 * @return The Long value parsed from the specified attribute, or
574 * {@code null} if that attribute is not available or the value
575 * cannot be parsed as a Long.
576 */
577 public Long getAttributeValueAsLong(final String attributeName)
578 {
579 ensureNotNull(attributeName);
580
581 final Attribute a = getAttribute(attributeName);
582 if (a == null)
583 {
584 return null;
585 }
586 else
587 {
588 return a.getValueAsLong();
589 }
590 }
591
592
593
594 /**
595 * Retrieves the set of values for the specified attribute, if available.
596 *
597 * @param attributeName The name of the attribute for which to retrieve the
598 * values. It must not be {@code null}.
599 *
600 * @return The set of values for the specified attribute, or {@code null} if
601 * that attribute is not available.
602 */
603 public String[] getAttributeValues(final String attributeName)
604 {
605 ensureNotNull(attributeName);
606
607 for (final CompactAttribute a : attributes)
608 {
609 if (a.getName().equalsIgnoreCase(attributeName))
610 {
611 return a.getStringValues();
612 }
613 }
614
615 return null;
616 }
617
618
619
620 /**
621 * Retrieves the set of values for the specified attribute as byte arrays, if
622 * available.
623 *
624 * @param attributeName The name of the attribute for which to retrieve the
625 * values. It must not be {@code null}.
626 *
627 * @return The set of values for the specified attribute as byte arrays, or
628 * {@code null} if that attribute is not available.
629 */
630 public byte[][] getAttributeValueByteArrays(final String attributeName)
631 {
632 ensureNotNull(attributeName);
633
634 for (final CompactAttribute a : attributes)
635 {
636 if (a.getName().equalsIgnoreCase(attributeName))
637 {
638 return a.getByteValues();
639 }
640 }
641
642 return null;
643 }
644
645
646
647 /**
648 * Retrieves the "objectClass" attribute from the entry, if available.
649 *
650 * @return The "objectClass" attribute from the entry, or {@code null} if
651 * that attribute not available.
652 */
653 public Attribute getObjectClassAttribute()
654 {
655 return getAttribute("objectClass");
656 }
657
658
659
660 /**
661 * Retrieves the values of the "objectClass" attribute from the entry, if
662 * available.
663 *
664 * @return The values of the "objectClass" attribute from the entry, or
665 * {@code null} if that attribute is not available.
666 */
667 public String[] getObjectClassValues()
668 {
669 return getAttributeValues("objectClass");
670 }
671
672
673
674 /**
675 * Converts this compact entry to a full entry.
676 *
677 * @return The entry created from this compact entry.
678 */
679 public Entry toEntry()
680 {
681 final Attribute[] attrs = new Attribute[attributes.length];
682 for (int i=0; i < attributes.length; i++)
683 {
684 attrs[i] = attributes[i].toAttribute();
685 }
686
687 return new Entry(dn, attrs);
688 }
689
690
691
692 /**
693 * Generates a hash code for this entry.
694 *
695 * @return The generated hash code for this entry.
696 */
697 @Override()
698 public int hashCode()
699 {
700 if (hashCode == -1)
701 {
702 hashCode = toEntry().hashCode();
703 }
704
705 return hashCode;
706 }
707
708
709
710 /**
711 * Indicates whether the provided object is equal to this entry. The provided
712 * object will only be considered equal to this entry if it is an entry with
713 * the same DN and set of attributes.
714 *
715 * @param o The object for which to make the determination.
716 *
717 * @return {@code true} if the provided object is considered equal to this
718 * entry, or {@code false} if not.
719 */
720 @Override()
721 public boolean equals(final Object o)
722 {
723 if ((o == null) || (! (o instanceof CompactEntry)))
724 {
725 return false;
726 }
727
728 return toEntry().equals(((CompactEntry) o).toEntry());
729 }
730
731
732
733 /**
734 * Retrieves an LDIF representation of this entry, with each attribute value
735 * on a separate line. Long lines will not be wrapped.
736 *
737 * @return An LDIF representation of this entry.
738 */
739 public String[] toLDIF()
740 {
741 return toLDIF(0);
742 }
743
744
745
746 /**
747 * Retrieves an LDIF representation of this entry, with each attribute value
748 * on a separate line. Long lines will be wrapped at the specified column.
749 *
750 * @param wrapColumn The column at which long lines should be wrapped. A
751 * value less than or equal to two indicates that no
752 * wrapping should be performed.
753 *
754 * @return An LDIF representation of this entry.
755 */
756 public String[] toLDIF(final int wrapColumn)
757 {
758 return toEntry().toLDIF(wrapColumn);
759 }
760
761
762
763 /**
764 * Appends an LDIF representation of this entry to the provided buffer. Long
765 * lines will not be wrapped.
766 *
767 * @param buffer The buffer to which the LDIF representation of this entry
768 * should be written.
769 */
770 public void toLDIF(final ByteStringBuffer buffer)
771 {
772 toLDIF(buffer, 0);
773 }
774
775
776
777 /**
778 * Appends an LDIF representation of this entry to the provided buffer.
779 *
780 * @param buffer The buffer to which the LDIF representation of this
781 * entry should be written.
782 * @param wrapColumn The column at which long lines should be wrapped. A
783 * value less than or equal to two indicates that no
784 * wrapping should be performed.
785 */
786 public void toLDIF(final ByteStringBuffer buffer, final int wrapColumn)
787 {
788 toEntry().toLDIF(buffer, wrapColumn);
789 }
790
791
792
793 /**
794 * Retrieves an LDIF-formatted string representation of this entry. No
795 * wrapping will be performed, and no extra blank lines will be added.
796 *
797 * @return An LDIF-formatted string representation of this entry.
798 */
799 public String toLDIFString()
800 {
801 final StringBuilder buffer = new StringBuilder();
802 toLDIFString(buffer, 0);
803 return buffer.toString();
804 }
805
806
807
808 /**
809 * Retrieves an LDIF-formatted string representation of this entry. No
810 * extra blank lines will be added.
811 *
812 * @param wrapColumn The column at which long lines should be wrapped. A
813 * value less than or equal to two indicates that no
814 * wrapping should be performed.
815 *
816 * @return An LDIF-formatted string representation of this entry.
817 */
818 public String toLDIFString(final int wrapColumn)
819 {
820 final StringBuilder buffer = new StringBuilder();
821 toLDIFString(buffer, wrapColumn);
822 return buffer.toString();
823 }
824
825
826
827 /**
828 * Appends an LDIF-formatted string representation of this entry to the
829 * provided buffer. No wrapping will be performed, and no extra blank lines
830 * will be added.
831 *
832 * @param buffer The buffer to which to append the LDIF representation of
833 * this entry.
834 */
835 public void toLDIFString(final StringBuilder buffer)
836 {
837 toLDIFString(buffer, 0);
838 }
839
840
841
842 /**
843 * Appends an LDIF-formatted string representation of this entry to the
844 * provided buffer. No extra blank lines will be added.
845 *
846 * @param buffer The buffer to which to append the LDIF representation
847 * of this entry.
848 * @param wrapColumn The column at which long lines should be wrapped. A
849 * value less than or equal to two indicates that no
850 * wrapping should be performed.
851 */
852 public void toLDIFString(final StringBuilder buffer,
853 final int wrapColumn)
854 {
855 toEntry().toLDIFString(buffer, wrapColumn);
856 }
857
858
859
860 /**
861 * Retrieves a string representation of this entry.
862 *
863 * @return A string representation of this entry.
864 */
865 @Override()
866 public String toString()
867 {
868 final StringBuilder buffer = new StringBuilder();
869 toString(buffer);
870 return buffer.toString();
871 }
872
873
874
875 /**
876 * Appends a string representation of this entry to the provided buffer.
877 *
878 * @param buffer The buffer to which to append the string representation of
879 * this entry.
880 */
881 public void toString(final StringBuilder buffer)
882 {
883 buffer.append("Entry(dn='");
884 buffer.append(dn);
885 buffer.append("', attributes={");
886
887 for (int i=0; i < attributes.length; i++)
888 {
889 if (i > 0)
890 {
891 buffer.append(", ");
892 }
893 attributes[i].toAttribute().toString(buffer);
894 }
895
896 buffer.append("})");
897 }
898 }