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