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    }