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