001 /*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-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.math.BigInteger;
026 import java.util.ArrayList;
027 import java.util.Arrays;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.Date;
031 import java.util.HashSet;
032 import java.util.Iterator;
033 import java.util.LinkedHashMap;
034 import java.util.List;
035 import java.util.Map;
036 import java.util.Set;
037
038 import com.unboundid.asn1.ASN1OctetString;
039 import com.unboundid.ldap.matchingrules.MatchingRule;
040 import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition;
041 import com.unboundid.ldap.sdk.schema.Schema;
042 import com.unboundid.ldif.LDIFException;
043 import com.unboundid.ldif.LDIFReader;
044 import com.unboundid.ldif.LDIFRecord;
045 import com.unboundid.ldif.LDIFWriter;
046 import com.unboundid.util.ByteStringBuffer;
047
048 import static com.unboundid.ldap.sdk.LDAPMessages.*;
049 import static com.unboundid.util.Debug.*;
050 import static com.unboundid.util.StaticUtils.*;
051 import static com.unboundid.util.Validator.*;
052
053
054
055 /**
056 * This class provides a data structure for holding information about an LDAP
057 * entry. An entry contains a distinguished name (DN) and a set of attributes.
058 * An entry can be created from these components, and it can also be created
059 * from its LDIF representation as described in
060 * <A HREF="http://www.ietf.org/rfc/rfc2849.txt">RFC 2849</A>. For example:
061 * <BR><BR>
062 * <PRE>
063 * Entry entry = new Entry(
064 * "dn: dc=example,dc=com",
065 * "objectClass: top",
066 * "objectClass: domain",
067 * "dc: example");
068 * </PRE>
069 * <BR><BR>
070 * This class also provides methods for retrieving the LDIF representation of
071 * an entry, either as a single string or as an array of strings that make up
072 * the LDIF lines.
073 * <BR><BR>
074 * The {@code Entry#diff} method may be used to obtain the set of differences
075 * between two entries, and to retrieve a list of {@code Modification} objects
076 * that can be used to modify one entry so that it contains the same set of
077 * data as another. The {@code Entry#applyModifications} method may be used to
078 * apply a set of modifications to an entry.
079 * <BR><BR>
080 * Entry objects are mutable, and the DN, set of attributes, and individual
081 * attribute values can be altered.
082 */
083 public class Entry
084 implements LDIFRecord
085 {
086 /**
087 * The serial version UID for this serializable class.
088 */
089 private static final long serialVersionUID = -4438809025903729197L;
090
091
092
093 // The parsed DN for this entry.
094 private volatile DN parsedDN;
095
096 // The set of attributes for this entry.
097 private final LinkedHashMap<String,Attribute> attributes;
098
099 // The schema to use for this entry.
100 private final Schema schema;
101
102 // The DN for this entry.
103 private String dn;
104
105
106
107 /**
108 * Creates a new entry with the provided DN and no attributes.
109 *
110 * @param dn The DN for this entry. It must not be {@code null}.
111 */
112 public Entry(final String dn)
113 {
114 this(dn, (Schema) null);
115 }
116
117
118
119 /**
120 * Creates a new entry with the provided DN and no attributes.
121 *
122 * @param dn The DN for this entry. It must not be {@code null}.
123 * @param schema The schema to use for operations involving this entry. It
124 * may be {@code null} if no schema is available.
125 */
126 public Entry(final String dn, final Schema schema)
127 {
128 ensureNotNull(dn);
129
130 this.dn = dn;
131 this.schema = schema;
132
133 attributes = new LinkedHashMap<String,Attribute>();
134 }
135
136
137
138 /**
139 * Creates a new entry with the provided DN and no attributes.
140 *
141 * @param dn The DN for this entry. It must not be {@code null}.
142 */
143 public Entry(final DN dn)
144 {
145 this(dn, (Schema) null);
146 }
147
148
149
150 /**
151 * Creates a new entry with the provided DN and no attributes.
152 *
153 * @param dn The DN for this entry. It must not be {@code null}.
154 * @param schema The schema to use for operations involving this entry. It
155 * may be {@code null} if no schema is available.
156 */
157 public Entry(final DN dn, final Schema schema)
158 {
159 ensureNotNull(dn);
160
161 parsedDN = dn;
162 this.dn = parsedDN.toString();
163 this.schema = schema;
164
165 attributes = new LinkedHashMap<String,Attribute>();
166 }
167
168
169
170 /**
171 * Creates a new entry with the provided DN and set of attributes.
172 *
173 * @param dn The DN for this entry. It must not be {@code null}.
174 * @param attributes The set of attributes for this entry. It must not be
175 * {@code null}.
176 */
177 public Entry(final String dn, final Attribute... attributes)
178 {
179 this(dn, null, attributes);
180 }
181
182
183
184 /**
185 * Creates a new entry with the provided DN and set of attributes.
186 *
187 * @param dn The DN for this entry. It must not be {@code null}.
188 * @param schema The schema to use for operations involving this entry.
189 * It may be {@code null} if no schema is available.
190 * @param attributes The set of attributes for this entry. It must not be
191 * {@code null}.
192 */
193 public Entry(final String dn, final Schema schema,
194 final Attribute... attributes)
195 {
196 ensureNotNull(dn, attributes);
197
198 this.dn = dn;
199 this.schema = schema;
200
201 this.attributes = new LinkedHashMap<String,Attribute>(attributes.length);
202 for (final Attribute a : attributes)
203 {
204 final String name = toLowerCase(a.getName());
205 final Attribute attr = this.attributes.get(name);
206 if (attr == null)
207 {
208 this.attributes.put(name, a);
209 }
210 else
211 {
212 this.attributes.put(name, Attribute.mergeAttributes(attr, a));
213 }
214 }
215 }
216
217
218
219 /**
220 * Creates a new entry with the provided DN and set of attributes.
221 *
222 * @param dn The DN for this entry. It must not be {@code null}.
223 * @param attributes The set of attributes for this entry. It must not be
224 * {@code null}.
225 */
226 public Entry(final DN dn, final Attribute... attributes)
227 {
228 this(dn, null, attributes);
229 }
230
231
232
233 /**
234 * Creates a new entry with the provided DN and set of attributes.
235 *
236 * @param dn The DN for this entry. It must not be {@code null}.
237 * @param schema The schema to use for operations involving this entry.
238 * It may be {@code null} if no schema is available.
239 * @param attributes The set of attributes for this entry. It must not be
240 * {@code null}.
241 */
242 public Entry(final DN dn, final Schema schema, final Attribute... attributes)
243 {
244 ensureNotNull(dn, attributes);
245
246 parsedDN = dn;
247 this.dn = parsedDN.toString();
248 this.schema = schema;
249
250 this.attributes = new LinkedHashMap<String,Attribute>(attributes.length);
251 for (final Attribute a : attributes)
252 {
253 final String name = toLowerCase(a.getName());
254 final Attribute attr = this.attributes.get(name);
255 if (attr == null)
256 {
257 this.attributes.put(name, a);
258 }
259 else
260 {
261 this.attributes.put(name, Attribute.mergeAttributes(attr, a));
262 }
263 }
264 }
265
266
267
268 /**
269 * Creates a new entry with the provided DN and set of attributes.
270 *
271 * @param dn The DN for this entry. It must not be {@code null}.
272 * @param attributes The set of attributes for this entry. It must not be
273 * {@code null}.
274 */
275 public Entry(final String dn, final Collection<Attribute> attributes)
276 {
277 this(dn, null, attributes);
278 }
279
280
281
282 /**
283 * Creates a new entry with the provided DN and set of attributes.
284 *
285 * @param dn The DN for this entry. It must not be {@code null}.
286 * @param schema The schema to use for operations involving this entry.
287 * It may be {@code null} if no schema is available.
288 * @param attributes The set of attributes for this entry. It must not be
289 * {@code null}.
290 */
291 public Entry(final String dn, final Schema schema,
292 final Collection<Attribute> attributes)
293 {
294 ensureNotNull(dn, attributes);
295
296 this.dn = dn;
297 this.schema = schema;
298
299 this.attributes = new LinkedHashMap<String,Attribute>(attributes.size());
300 for (final Attribute a : attributes)
301 {
302 final String name = toLowerCase(a.getName());
303 final Attribute attr = this.attributes.get(name);
304 if (attr == null)
305 {
306 this.attributes.put(name, a);
307 }
308 else
309 {
310 this.attributes.put(name, Attribute.mergeAttributes(attr, a));
311 }
312 }
313 }
314
315
316
317 /**
318 * Creates a new entry with the provided DN and set of attributes.
319 *
320 * @param dn The DN for this entry. It must not be {@code null}.
321 * @param attributes The set of attributes for this entry. It must not be
322 * {@code null}.
323 */
324 public Entry(final DN dn, final Collection<Attribute> attributes)
325 {
326 this(dn, null, attributes);
327 }
328
329
330
331 /**
332 * Creates a new entry with the provided DN and set of attributes.
333 *
334 * @param dn The DN for this entry. It must not be {@code null}.
335 * @param schema The schema to use for operations involving this entry.
336 * It may be {@code null} if no schema is available.
337 * @param attributes The set of attributes for this entry. It must not be
338 * {@code null}.
339 */
340 public Entry(final DN dn, final Schema schema,
341 final Collection<Attribute> attributes)
342 {
343 ensureNotNull(dn, attributes);
344
345 parsedDN = dn;
346 this.dn = parsedDN.toString();
347 this.schema = schema;
348
349 this.attributes = new LinkedHashMap<String,Attribute>(attributes.size());
350 for (final Attribute a : attributes)
351 {
352 final String name = toLowerCase(a.getName());
353 final Attribute attr = this.attributes.get(name);
354 if (attr == null)
355 {
356 this.attributes.put(name, a);
357 }
358 else
359 {
360 this.attributes.put(name, Attribute.mergeAttributes(attr, a));
361 }
362 }
363 }
364
365
366
367 /**
368 * Creates a new entry from the provided LDIF representation.
369 *
370 * @param entryLines The set of lines that comprise an LDIF representation
371 * of the entry. It must not be {@code null} or empty.
372 *
373 * @throws LDIFException If the provided lines cannot be decoded as an entry
374 * in LDIF format.
375 */
376 public Entry(final String... entryLines)
377 throws LDIFException
378 {
379 this(null, entryLines);
380 }
381
382
383
384 /**
385 * Creates a new entry from the provided LDIF representation.
386 *
387 * @param schema The schema to use for operations involving this entry.
388 * It may be {@code null} if no schema is available.
389 * @param entryLines The set of lines that comprise an LDIF representation
390 * of the entry. It must not be {@code null} or empty.
391 *
392 * @throws LDIFException If the provided lines cannot be decoded as an entry
393 * in LDIF format.
394 */
395 public Entry(final Schema schema, final String... entryLines)
396 throws LDIFException
397 {
398 final Entry e = LDIFReader.decodeEntry(entryLines);
399
400 this.schema = schema;
401
402 dn = e.dn;
403 parsedDN = e.parsedDN;
404 attributes = e.attributes;
405 }
406
407
408
409 /**
410 * Retrieves the DN for this entry.
411 *
412 * @return The DN for this entry.
413 */
414 public final String getDN()
415 {
416 return dn;
417 }
418
419
420
421 /**
422 * Specifies the DN for this entry.
423 *
424 * @param dn The DN for this entry. It must not be {@code null}.
425 */
426 public void setDN(final String dn)
427 {
428 ensureNotNull(dn);
429
430 this.dn = dn;
431 parsedDN = null;
432 }
433
434
435
436 /**
437 * Specifies the DN for this entry.
438 *
439 * @param dn The DN for this entry. It must not be {@code null}.
440 */
441 public void setDN(final DN dn)
442 {
443 ensureNotNull(dn);
444
445 parsedDN = dn;
446 this.dn = parsedDN.toString();
447 }
448
449
450
451 /**
452 * Retrieves the parsed DN for this entry.
453 *
454 * @return The parsed DN for this entry.
455 *
456 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
457 */
458 public final DN getParsedDN()
459 throws LDAPException
460 {
461 if (parsedDN == null)
462 {
463 parsedDN = new DN(dn, schema);
464 }
465
466 return parsedDN;
467 }
468
469
470
471 /**
472 * Retrieves the RDN for this entry.
473 *
474 * @return The RDN for this entry, or {@code null} if the DN is the null DN.
475 *
476 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
477 */
478 public final RDN getRDN()
479 throws LDAPException
480 {
481 return getParsedDN().getRDN();
482 }
483
484
485
486 /**
487 * Retrieves the parent DN for this entry.
488 *
489 * @return The parent DN for this entry, or {@code null} if there is no
490 * parent.
491 *
492 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
493 */
494 public final DN getParentDN()
495 throws LDAPException
496 {
497 if (parsedDN == null)
498 {
499 parsedDN = new DN(dn, schema);
500 }
501
502 return parsedDN.getParent();
503 }
504
505
506
507 /**
508 * Retrieves the parent DN for this entry as a string.
509 *
510 * @return The parent DN for this entry as a string, or {@code null} if there
511 * is no parent.
512 *
513 * @throws LDAPException If the DN string cannot be parsed as a valid DN.
514 */
515 public final String getParentDNString()
516 throws LDAPException
517 {
518 if (parsedDN == null)
519 {
520 parsedDN = new DN(dn, schema);
521 }
522
523 final DN parentDN = parsedDN.getParent();
524 if (parentDN == null)
525 {
526 return null;
527 }
528 else
529 {
530 return parentDN.toString();
531 }
532 }
533
534
535
536 /**
537 * Retrieves the schema that will be used for this entry, if any.
538 *
539 * @return The schema that will be used for this entry, or {@code null} if
540 * no schema was provided.
541 */
542 protected Schema getSchema()
543 {
544 return schema;
545 }
546
547
548
549 /**
550 * Indicates whether this entry contains the specified attribute.
551 *
552 * @param attributeName The name of the attribute for which to make the
553 * determination. It must not be {@code null}.
554 *
555 * @return {@code true} if this entry contains the specified attribute, or
556 * {@code false} if not.
557 */
558 public final boolean hasAttribute(final String attributeName)
559 {
560 return hasAttribute(attributeName, schema);
561 }
562
563
564
565 /**
566 * Indicates whether this entry contains the specified attribute.
567 *
568 * @param attributeName The name of the attribute for which to make the
569 * determination. It must not be {@code null}.
570 * @param schema The schema to use to determine whether there may be
571 * alternate names for the specified attribute. It may
572 * be {@code null} if no schema is available.
573 *
574 * @return {@code true} if this entry contains the specified attribute, or
575 * {@code false} if not.
576 */
577 public final boolean hasAttribute(final String attributeName,
578 final Schema schema)
579 {
580 ensureNotNull(attributeName);
581
582 if (attributes.containsKey(toLowerCase(attributeName)))
583 {
584 return true;
585 }
586
587 if (schema != null)
588 {
589 final String baseName;
590 final String options;
591 final int semicolonPos = attributeName.indexOf(';');
592 if (semicolonPos > 0)
593 {
594 baseName = attributeName.substring(0, semicolonPos);
595 options = toLowerCase(attributeName.substring(semicolonPos));
596 }
597 else
598 {
599 baseName = attributeName;
600 options = "";
601 }
602
603 final AttributeTypeDefinition at = schema.getAttributeType(baseName);
604 if (at != null)
605 {
606 if (attributes.containsKey(toLowerCase(at.getOID()) + options))
607 {
608 return true;
609 }
610
611 for (final String name : at.getNames())
612 {
613 if (attributes.containsKey(toLowerCase(name) + options))
614 {
615 return true;
616 }
617 }
618 }
619 }
620
621 return false;
622 }
623
624
625
626 /**
627 * Indicates whether this entry contains the specified attribute. It will
628 * only return {@code true} if this entry contains an attribute with the same
629 * name and exact set of values.
630 *
631 * @param attribute The attribute for which to make the determination. It
632 * must not be {@code null}.
633 *
634 * @return {@code true} if this entry contains the specified attribute, or
635 * {@code false} if not.
636 */
637 public final boolean hasAttribute(final Attribute attribute)
638 {
639 ensureNotNull(attribute);
640
641 final String lowerName = toLowerCase(attribute.getName());
642 final Attribute attr = attributes.get(lowerName);
643 return ((attr != null) && attr.equals(attribute));
644 }
645
646
647
648 /**
649 * Indicates whether this entry contains an attribute with the given name and
650 * value.
651 *
652 * @param attributeName The name of the attribute for which to make the
653 * determination. It must not be {@code null}.
654 * @param attributeValue The value for which to make the determination. It
655 * must not be {@code null}.
656 *
657 * @return {@code true} if this entry contains an attribute with the
658 * specified name and value, or {@code false} if not.
659 */
660 public final boolean hasAttributeValue(final String attributeName,
661 final String attributeValue)
662 {
663 ensureNotNull(attributeName, attributeValue);
664
665 final Attribute attr = attributes.get(toLowerCase(attributeName));
666 return ((attr != null) && attr.hasValue(attributeValue));
667 }
668
669
670
671 /**
672 * Indicates whether this entry contains an attribute with the given name and
673 * value.
674 *
675 * @param attributeName The name of the attribute for which to make the
676 * determination. It must not be {@code null}.
677 * @param attributeValue The value for which to make the determination. It
678 * must not be {@code null}.
679 * @param matchingRule The matching rule to use to make the determination.
680 * It must not be {@code null}.
681 *
682 * @return {@code true} if this entry contains an attribute with the
683 * specified name and value, or {@code false} if not.
684 */
685 public final boolean hasAttributeValue(final String attributeName,
686 final String attributeValue,
687 final MatchingRule matchingRule)
688 {
689 ensureNotNull(attributeName, attributeValue);
690
691 final Attribute attr = attributes.get(toLowerCase(attributeName));
692 return ((attr != null) && attr.hasValue(attributeValue, matchingRule));
693 }
694
695
696
697 /**
698 * Indicates whether this entry contains an attribute with the given name and
699 * value.
700 *
701 * @param attributeName The name of the attribute for which to make the
702 * determination. It must not be {@code null}.
703 * @param attributeValue The value for which to make the determination. It
704 * must not be {@code null}.
705 *
706 * @return {@code true} if this entry contains an attribute with the
707 * specified name and value, or {@code false} if not.
708 */
709 public final boolean hasAttributeValue(final String attributeName,
710 final byte[] attributeValue)
711 {
712 ensureNotNull(attributeName, attributeValue);
713
714 final Attribute attr = attributes.get(toLowerCase(attributeName));
715 return ((attr != null) && attr.hasValue(attributeValue));
716 }
717
718
719
720 /**
721 * Indicates whether this entry contains an attribute with the given name and
722 * value.
723 *
724 * @param attributeName The name of the attribute for which to make the
725 * determination. It must not be {@code null}.
726 * @param attributeValue The value for which to make the determination. It
727 * must not be {@code null}.
728 * @param matchingRule The matching rule to use to make the determination.
729 * It must not be {@code null}.
730 *
731 * @return {@code true} if this entry contains an attribute with the
732 * specified name and value, or {@code false} if not.
733 */
734 public final boolean hasAttributeValue(final String attributeName,
735 final byte[] attributeValue,
736 final MatchingRule matchingRule)
737 {
738 ensureNotNull(attributeName, attributeValue);
739
740 final Attribute attr = attributes.get(toLowerCase(attributeName));
741 return ((attr != null) && attr.hasValue(attributeValue, matchingRule));
742 }
743
744
745
746 /**
747 * Indicates whether this entry contains the specified object class.
748 *
749 * @param objectClassName The name of the object class for which to make the
750 * determination. It must not be {@code null}.
751 *
752 * @return {@code true} if this entry contains the specified object class, or
753 * {@code false} if not.
754 */
755 public final boolean hasObjectClass(final String objectClassName)
756 {
757 return hasAttributeValue("objectClass", objectClassName);
758 }
759
760
761
762 /**
763 * Retrieves the set of attributes contained in this entry.
764 *
765 * @return The set of attributes contained in this entry.
766 */
767 public final Collection<Attribute> getAttributes()
768 {
769 return Collections.unmodifiableCollection(attributes.values());
770 }
771
772
773
774 /**
775 * Retrieves the attribute with the specified name.
776 *
777 * @param attributeName The name of the attribute to retrieve. It must not
778 * be {@code null}.
779 *
780 * @return The requested attribute from this entry, or {@code null} if the
781 * specified attribute is not present in this entry.
782 */
783 public final Attribute getAttribute(final String attributeName)
784 {
785 return getAttribute(attributeName, schema);
786 }
787
788
789
790 /**
791 * Retrieves the attribute with the specified name.
792 *
793 * @param attributeName The name of the attribute to retrieve. It must not
794 * be {@code null}.
795 * @param schema The schema to use to determine whether there may be
796 * alternate names for the specified attribute. It may
797 * be {@code null} if no schema is available.
798 *
799 * @return The requested attribute from this entry, or {@code null} if the
800 * specified attribute is not present in this entry.
801 */
802 public final Attribute getAttribute(final String attributeName,
803 final Schema schema)
804 {
805 ensureNotNull(attributeName);
806
807 Attribute a = attributes.get(toLowerCase(attributeName));
808 if ((a == null) && (schema != null))
809 {
810 final String baseName;
811 final String options;
812 final int semicolonPos = attributeName.indexOf(';');
813 if (semicolonPos > 0)
814 {
815 baseName = attributeName.substring(0, semicolonPos);
816 options = toLowerCase(attributeName.substring(semicolonPos));
817 }
818 else
819 {
820 baseName = attributeName;
821 options = "";
822 }
823
824 final AttributeTypeDefinition at = schema.getAttributeType(baseName);
825 if (at == null)
826 {
827 return null;
828 }
829
830 a = attributes.get(toLowerCase(at.getOID() + options));
831 if (a == null)
832 {
833 for (final String name : at.getNames())
834 {
835 a = attributes.get(toLowerCase(name) + options);
836 if (a != null)
837 {
838 return a;
839 }
840 }
841 }
842
843 return a;
844 }
845 else
846 {
847 return a;
848 }
849 }
850
851
852
853 /**
854 * Retrieves the list of attributes with the given base name and all of the
855 * specified options.
856 *
857 * @param baseName The base name (without any options) for the attribute to
858 * retrieve. It must not be {@code null}.
859 * @param options The set of options that should be included in the
860 * attributes that are returned. It may be empty or
861 * {@code null} if all attributes with the specified base
862 * name should be returned, regardless of the options that
863 * they contain (if any).
864 *
865 * @return The list of attributes with the given base name and all of the
866 * specified options. It may be empty if there are no attributes
867 * with the specified base name and set of options.
868 */
869 public final List<Attribute> getAttributesWithOptions(final String baseName,
870 final Set<String> options)
871 {
872 ensureNotNull(baseName);
873
874 final ArrayList<Attribute> attrList = new ArrayList<Attribute>(10);
875
876 for (final Attribute a : attributes.values())
877 {
878 if (a.getBaseName().equalsIgnoreCase(baseName))
879 {
880 if ((options == null) || options.isEmpty())
881 {
882 attrList.add(a);
883 }
884 else
885 {
886 boolean allFound = true;
887 for (final String option : options)
888 {
889 if (! a.hasOption(option))
890 {
891 allFound = false;
892 break;
893 }
894 }
895
896 if (allFound)
897 {
898 attrList.add(a);
899 }
900 }
901 }
902 }
903
904 return Collections.unmodifiableList(attrList);
905 }
906
907
908
909 /**
910 * Retrieves the value for the specified attribute, if available. If the
911 * attribute has more than one value, then the first value will be returned.
912 *
913 * @param attributeName The name of the attribute for which to retrieve the
914 * value. It must not be {@code null}.
915 *
916 * @return The value for the specified attribute, or {@code null} if that
917 * attribute is not available.
918 */
919 public String getAttributeValue(final String attributeName)
920 {
921 ensureNotNull(attributeName);
922
923 final Attribute a = attributes.get(toLowerCase(attributeName));
924 if (a == null)
925 {
926 return null;
927 }
928 else
929 {
930 return a.getValue();
931 }
932 }
933
934
935
936 /**
937 * Retrieves the value for the specified attribute as a byte array, if
938 * available. If the attribute has more than one value, then the first value
939 * will be returned.
940 *
941 * @param attributeName The name of the attribute for which to retrieve the
942 * value. It must not be {@code null}.
943 *
944 * @return The value for the specified attribute as a byte array, or
945 * {@code null} if that attribute is not available.
946 */
947 public byte[] getAttributeValueBytes(final String attributeName)
948 {
949 ensureNotNull(attributeName);
950
951 final Attribute a = attributes.get(toLowerCase(attributeName));
952 if (a == null)
953 {
954 return null;
955 }
956 else
957 {
958 return a.getValueByteArray();
959 }
960 }
961
962
963
964 /**
965 * Retrieves the value for the specified attribute as a Boolean, if available.
966 * If the attribute has more than one value, then the first value will be
967 * returned. Values of "true", "t", "yes", "y", "on", and "1" will be
968 * interpreted as {@code TRUE}. Values of "false", "f", "no", "n", "off", and
969 * "0" will be interpreted as {@code FALSE}.
970 *
971 * @param attributeName The name of the attribute for which to retrieve the
972 * value. It must not be {@code null}.
973 *
974 * @return The Boolean value parsed from the specified attribute, or
975 * {@code null} if that attribute is not available or the value
976 * cannot be parsed as a Boolean.
977 */
978 public Boolean getAttributeValueAsBoolean(final String attributeName)
979 {
980 ensureNotNull(attributeName);
981
982 final Attribute a = attributes.get(toLowerCase(attributeName));
983 if (a == null)
984 {
985 return null;
986 }
987 else
988 {
989 return a.getValueAsBoolean();
990 }
991 }
992
993
994
995 /**
996 * Retrieves the value for the specified attribute as a Date, formatted using
997 * the generalized time syntax, if available. If the attribute has more than
998 * one value, then the first value will be returned.
999 *
1000 * @param attributeName The name of the attribute for which to retrieve the
1001 * value. It must not be {@code null}.
1002 *
1003 * @return The Date value parsed from the specified attribute, or
1004 * {@code null} if that attribute is not available or the value
1005 * cannot be parsed as a Date.
1006 */
1007 public Date getAttributeValueAsDate(final String attributeName)
1008 {
1009 ensureNotNull(attributeName);
1010
1011 final Attribute a = attributes.get(toLowerCase(attributeName));
1012 if (a == null)
1013 {
1014 return null;
1015 }
1016 else
1017 {
1018 return a.getValueAsDate();
1019 }
1020 }
1021
1022
1023
1024 /**
1025 * Retrieves the value for the specified attribute as a DN, if available. If
1026 * the attribute has more than one value, then the first value will be
1027 * returned.
1028 *
1029 * @param attributeName The name of the attribute for which to retrieve the
1030 * value. It must not be {@code null}.
1031 *
1032 * @return The DN value parsed from the specified attribute, or {@code null}
1033 * if that attribute is not available or the value cannot be parsed
1034 * as a DN.
1035 */
1036 public DN getAttributeValueAsDN(final String attributeName)
1037 {
1038 ensureNotNull(attributeName);
1039
1040 final Attribute a = attributes.get(toLowerCase(attributeName));
1041 if (a == null)
1042 {
1043 return null;
1044 }
1045 else
1046 {
1047 return a.getValueAsDN();
1048 }
1049 }
1050
1051
1052
1053 /**
1054 * Retrieves the value for the specified attribute as an Integer, if
1055 * available. If the attribute has more than one value, then the first value
1056 * will be returned.
1057 *
1058 * @param attributeName The name of the attribute for which to retrieve the
1059 * value. It must not be {@code null}.
1060 *
1061 * @return The Integer value parsed from the specified attribute, or
1062 * {@code null} if that attribute is not available or the value
1063 * cannot be parsed as an Integer.
1064 */
1065 public Integer getAttributeValueAsInteger(final String attributeName)
1066 {
1067 ensureNotNull(attributeName);
1068
1069 final Attribute a = attributes.get(toLowerCase(attributeName));
1070 if (a == null)
1071 {
1072 return null;
1073 }
1074 else
1075 {
1076 return a.getValueAsInteger();
1077 }
1078 }
1079
1080
1081
1082 /**
1083 * Retrieves the value for the specified attribute as a Long, if available.
1084 * If the attribute has more than one value, then the first value will be
1085 * returned.
1086 *
1087 * @param attributeName The name of the attribute for which to retrieve the
1088 * value. It must not be {@code null}.
1089 *
1090 * @return The Long value parsed from the specified attribute, or
1091 * {@code null} if that attribute is not available or the value
1092 * cannot be parsed as a Long.
1093 */
1094 public Long getAttributeValueAsLong(final String attributeName)
1095 {
1096 ensureNotNull(attributeName);
1097
1098 final Attribute a = attributes.get(toLowerCase(attributeName));
1099 if (a == null)
1100 {
1101 return null;
1102 }
1103 else
1104 {
1105 return a.getValueAsLong();
1106 }
1107 }
1108
1109
1110
1111 /**
1112 * Retrieves the set of values for the specified attribute, if available.
1113 *
1114 * @param attributeName The name of the attribute for which to retrieve the
1115 * values. It must not be {@code null}.
1116 *
1117 * @return The set of values for the specified attribute, or {@code null} if
1118 * that attribute is not available.
1119 */
1120 public String[] getAttributeValues(final String attributeName)
1121 {
1122 ensureNotNull(attributeName);
1123
1124 final Attribute a = attributes.get(toLowerCase(attributeName));
1125 if (a == null)
1126 {
1127 return null;
1128 }
1129 else
1130 {
1131 return a.getValues();
1132 }
1133 }
1134
1135
1136
1137 /**
1138 * Retrieves the set of values for the specified attribute as byte arrays, if
1139 * available.
1140 *
1141 * @param attributeName The name of the attribute for which to retrieve the
1142 * values. It must not be {@code null}.
1143 *
1144 * @return The set of values for the specified attribute as byte arrays, or
1145 * {@code null} if that attribute is not available.
1146 */
1147 public byte[][] getAttributeValueByteArrays(final String attributeName)
1148 {
1149 ensureNotNull(attributeName);
1150
1151 final Attribute a = attributes.get(toLowerCase(attributeName));
1152 if (a == null)
1153 {
1154 return null;
1155 }
1156 else
1157 {
1158 return a.getValueByteArrays();
1159 }
1160 }
1161
1162
1163
1164 /**
1165 * Retrieves the "objectClass" attribute from the entry, if available.
1166 *
1167 * @return The "objectClass" attribute from the entry, or {@code null} if
1168 * that attribute not available.
1169 */
1170 public final Attribute getObjectClassAttribute()
1171 {
1172 return getAttribute("objectClass");
1173 }
1174
1175
1176
1177 /**
1178 * Retrieves the values of the "objectClass" attribute from the entry, if
1179 * available.
1180 *
1181 * @return The values of the "objectClass" attribute from the entry, or
1182 * {@code null} if that attribute is not available.
1183 */
1184 public final String[] getObjectClassValues()
1185 {
1186 return getAttributeValues("objectClass");
1187 }
1188
1189
1190
1191 /**
1192 * Adds the provided attribute to this entry. If this entry already contains
1193 * an attribute with the same name, then their values will be merged.
1194 *
1195 * @param attribute The attribute to be added. It must not be {@code null}.
1196 *
1197 * @return {@code true} if the entry was updated, or {@code false} because
1198 * the specified attribute already existed with all provided values.
1199 */
1200 public boolean addAttribute(final Attribute attribute)
1201 {
1202 ensureNotNull(attribute);
1203
1204 final String lowerName = toLowerCase(attribute.getName());
1205 final Attribute attr = attributes.get(lowerName);
1206 if (attr == null)
1207 {
1208 attributes.put(lowerName, attribute);
1209 return true;
1210 }
1211 else
1212 {
1213 final Attribute newAttr = Attribute.mergeAttributes(attr, attribute);
1214 attributes.put(lowerName, newAttr);
1215 return (attr.getRawValues().length != newAttr.getRawValues().length);
1216 }
1217 }
1218
1219
1220
1221 /**
1222 * Adds the specified attribute value to this entry, if it is not already
1223 * present.
1224 *
1225 * @param attributeName The name for the attribute to be added. It must
1226 * not be {@code null}.
1227 * @param attributeValue The value for the attribute to be added. It must
1228 * not be {@code null}.
1229 *
1230 * @return {@code true} if the entry was updated, or {@code false} because
1231 * the specified attribute already existed with the given value.
1232 */
1233 public boolean addAttribute(final String attributeName,
1234 final String attributeValue)
1235 {
1236 ensureNotNull(attributeName, attributeValue);
1237 return addAttribute(new Attribute(attributeName, schema, attributeValue));
1238 }
1239
1240
1241
1242 /**
1243 * Adds the specified attribute value to this entry, if it is not already
1244 * present.
1245 *
1246 * @param attributeName The name for the attribute to be added. It must
1247 * not be {@code null}.
1248 * @param attributeValue The value for the attribute to be added. It must
1249 * not be {@code null}.
1250 *
1251 * @return {@code true} if the entry was updated, or {@code false} because
1252 * the specified attribute already existed with the given value.
1253 */
1254 public boolean addAttribute(final String attributeName,
1255 final byte[] attributeValue)
1256 {
1257 ensureNotNull(attributeName, attributeValue);
1258 return addAttribute(new Attribute(attributeName, schema, attributeValue));
1259 }
1260
1261
1262
1263 /**
1264 * Adds the provided attribute to this entry. If this entry already contains
1265 * an attribute with the same name, then their values will be merged.
1266 *
1267 * @param attributeName The name for the attribute to be added. It must
1268 * not be {@code null}.
1269 * @param attributeValues The value for the attribute to be added. It must
1270 * not be {@code null}.
1271 *
1272 * @return {@code true} if the entry was updated, or {@code false} because
1273 * the specified attribute already existed with all provided values.
1274 */
1275 public boolean addAttribute(final String attributeName,
1276 final String... attributeValues)
1277 {
1278 ensureNotNull(attributeName, attributeValues);
1279 return addAttribute(new Attribute(attributeName, schema, attributeValues));
1280 }
1281
1282
1283
1284 /**
1285 * Adds the provided attribute to this entry. If this entry already contains
1286 * an attribute with the same name, then their values will be merged.
1287 *
1288 * @param attributeName The name for the attribute to be added. It must
1289 * not be {@code null}.
1290 * @param attributeValues The value for the attribute to be added. It must
1291 * not be {@code null}.
1292 *
1293 * @return {@code true} if the entry was updated, or {@code false} because
1294 * the specified attribute already existed with all provided values.
1295 */
1296 public boolean addAttribute(final String attributeName,
1297 final byte[]... attributeValues)
1298 {
1299 ensureNotNull(attributeName, attributeValues);
1300 return addAttribute(new Attribute(attributeName, schema, attributeValues));
1301 }
1302
1303
1304
1305 /**
1306 * Adds the provided attribute to this entry. If this entry already contains
1307 * an attribute with the same name, then their values will be merged.
1308 *
1309 * @param attributeName The name for the attribute to be added. It must
1310 * not be {@code null}.
1311 * @param attributeValues The value for the attribute to be added. It must
1312 * not be {@code null}.
1313 *
1314 * @return {@code true} if the entry was updated, or {@code false} because
1315 * the specified attribute already existed with all provided values.
1316 */
1317 public boolean addAttribute(final String attributeName,
1318 final Collection<String> attributeValues)
1319 {
1320 ensureNotNull(attributeName, attributeValues);
1321 return addAttribute(new Attribute(attributeName, schema, attributeValues));
1322 }
1323
1324
1325
1326 /**
1327 * Removes the specified attribute from this entry.
1328 *
1329 * @param attributeName The name of the attribute to remove. It must not be
1330 * {@code null}.
1331 *
1332 * @return {@code true} if the attribute was removed from the entry, or
1333 * {@code false} if it was not present.
1334 */
1335 public boolean removeAttribute(final String attributeName)
1336 {
1337 ensureNotNull(attributeName);
1338
1339 if (schema == null)
1340 {
1341 return (attributes.remove(toLowerCase(attributeName)) != null);
1342 }
1343 else
1344 {
1345 final Attribute a = getAttribute(attributeName, schema);
1346 if (a == null)
1347 {
1348 return false;
1349 }
1350 else
1351 {
1352 attributes.remove(toLowerCase(a.getName()));
1353 return true;
1354 }
1355 }
1356 }
1357
1358
1359
1360 /**
1361 * Removes the specified attribute value from this entry if it is present. If
1362 * it is the last value for the attribute, then the entire attribute will be
1363 * removed. If the specified value is not present, then no change will be
1364 * made.
1365 *
1366 * @param attributeName The name of the attribute from which to remove the
1367 * value. It must not be {@code null}.
1368 * @param attributeValue The value to remove from the attribute. It must
1369 * not be {@code null}.
1370 *
1371 * @return {@code true} if the attribute value was removed from the entry, or
1372 * {@code false} if it was not present.
1373 */
1374 public boolean removeAttributeValue(final String attributeName,
1375 final String attributeValue)
1376 {
1377 return removeAttributeValue(attributeName, attributeValue, null);
1378 }
1379
1380
1381
1382 /**
1383 * Removes the specified attribute value from this entry if it is present. If
1384 * it is the last value for the attribute, then the entire attribute will be
1385 * removed. If the specified value is not present, then no change will be
1386 * made.
1387 *
1388 * @param attributeName The name of the attribute from which to remove the
1389 * value. It must not be {@code null}.
1390 * @param attributeValue The value to remove from the attribute. It must
1391 * not be {@code null}.
1392 * @param matchingRule The matching rule to use for the attribute. It may
1393 * be {@code null} to use the matching rule associated
1394 * with the attribute.
1395 *
1396 * @return {@code true} if the attribute value was removed from the entry, or
1397 * {@code false} if it was not present.
1398 */
1399 public boolean removeAttributeValue(final String attributeName,
1400 final String attributeValue,
1401 final MatchingRule matchingRule)
1402 {
1403 ensureNotNull(attributeName, attributeValue);
1404
1405 final Attribute attr = getAttribute(attributeName, schema);
1406 if (attr == null)
1407 {
1408 return false;
1409 }
1410 else
1411 {
1412 final String lowerName = toLowerCase(attr.getName());
1413 final Attribute newAttr = Attribute.removeValues(attr,
1414 new Attribute(attributeName, attributeValue), matchingRule);
1415 if (newAttr.hasValue())
1416 {
1417 attributes.put(lowerName, newAttr);
1418 }
1419 else
1420 {
1421 attributes.remove(lowerName);
1422 }
1423
1424 return (attr.getRawValues().length != newAttr.getRawValues().length);
1425 }
1426 }
1427
1428
1429
1430 /**
1431 * Removes the specified attribute value from this entry if it is present. If
1432 * it is the last value for the attribute, then the entire attribute will be
1433 * removed. If the specified value is not present, then no change will be
1434 * made.
1435 *
1436 * @param attributeName The name of the attribute from which to remove the
1437 * value. It must not be {@code null}.
1438 * @param attributeValue The value to remove from the attribute. It must
1439 * not be {@code null}.
1440 *
1441 * @return {@code true} if the attribute value was removed from the entry, or
1442 * {@code false} if it was not present.
1443 */
1444 public boolean removeAttributeValue(final String attributeName,
1445 final byte[] attributeValue)
1446 {
1447 return removeAttributeValue(attributeName, attributeValue, null);
1448 }
1449
1450
1451
1452 /**
1453 * Removes the specified attribute value from this entry if it is present. If
1454 * it is the last value for the attribute, then the entire attribute will be
1455 * removed. If the specified value is not present, then no change will be
1456 * made.
1457 *
1458 * @param attributeName The name of the attribute from which to remove the
1459 * value. It must not be {@code null}.
1460 * @param attributeValue The value to remove from the attribute. It must
1461 * not be {@code null}.
1462 * @param matchingRule The matching rule to use for the attribute. It may
1463 * be {@code null} to use the matching rule associated
1464 * with the attribute.
1465 *
1466 * @return {@code true} if the attribute value was removed from the entry, or
1467 * {@code false} if it was not present.
1468 */
1469 public boolean removeAttributeValue(final String attributeName,
1470 final byte[] attributeValue,
1471 final MatchingRule matchingRule)
1472 {
1473 ensureNotNull(attributeName, attributeValue);
1474
1475 final Attribute attr = getAttribute(attributeName, schema);
1476 if (attr == null)
1477 {
1478 return false;
1479 }
1480 else
1481 {
1482 final String lowerName = toLowerCase(attr.getName());
1483 final Attribute newAttr = Attribute.removeValues(attr,
1484 new Attribute(attributeName, attributeValue), matchingRule);
1485 if (newAttr.hasValue())
1486 {
1487 attributes.put(lowerName, newAttr);
1488 }
1489 else
1490 {
1491 attributes.remove(lowerName);
1492 }
1493
1494 return (attr.getRawValues().length != newAttr.getRawValues().length);
1495 }
1496 }
1497
1498
1499
1500 /**
1501 * Removes the specified attribute values from this entry if they are present.
1502 * If the attribute does not have any remaining values, then the entire
1503 * attribute will be removed. If any of the provided values are not present,
1504 * then they will be ignored.
1505 *
1506 * @param attributeName The name of the attribute from which to remove the
1507 * values. It must not be {@code null}.
1508 * @param attributeValues The set of values to remove from the attribute.
1509 * It must not be {@code null}.
1510 *
1511 * @return {@code true} if any attribute values were removed from the entry,
1512 * or {@code false} none of them were present.
1513 */
1514 public boolean removeAttributeValues(final String attributeName,
1515 final String... attributeValues)
1516 {
1517 ensureNotNull(attributeName, attributeValues);
1518
1519 final Attribute attr = getAttribute(attributeName, schema);
1520 if (attr == null)
1521 {
1522 return false;
1523 }
1524 else
1525 {
1526 final String lowerName = toLowerCase(attr.getName());
1527 final Attribute newAttr = Attribute.removeValues(attr,
1528 new Attribute(attributeName, attributeValues));
1529 if (newAttr.hasValue())
1530 {
1531 attributes.put(lowerName, newAttr);
1532 }
1533 else
1534 {
1535 attributes.remove(lowerName);
1536 }
1537
1538 return (attr.getRawValues().length != newAttr.getRawValues().length);
1539 }
1540 }
1541
1542
1543
1544 /**
1545 * Removes the specified attribute values from this entry if they are present.
1546 * If the attribute does not have any remaining values, then the entire
1547 * attribute will be removed. If any of the provided values are not present,
1548 * then they will be ignored.
1549 *
1550 * @param attributeName The name of the attribute from which to remove the
1551 * values. It must not be {@code null}.
1552 * @param attributeValues The set of values to remove from the attribute.
1553 * It must not be {@code null}.
1554 *
1555 * @return {@code true} if any attribute values were removed from the entry,
1556 * or {@code false} none of them were present.
1557 */
1558 public boolean removeAttributeValues(final String attributeName,
1559 final byte[]... attributeValues)
1560 {
1561 ensureNotNull(attributeName, attributeValues);
1562
1563 final Attribute attr = getAttribute(attributeName, schema);
1564 if (attr == null)
1565 {
1566 return false;
1567 }
1568 else
1569 {
1570 final String lowerName = toLowerCase(attr.getName());
1571 final Attribute newAttr = Attribute.removeValues(attr,
1572 new Attribute(attributeName, attributeValues));
1573 if (newAttr.hasValue())
1574 {
1575 attributes.put(lowerName, newAttr);
1576 }
1577 else
1578 {
1579 attributes.remove(lowerName);
1580 }
1581
1582 return (attr.getRawValues().length != newAttr.getRawValues().length);
1583 }
1584 }
1585
1586
1587
1588 /**
1589 * Adds the provided attribute to this entry, replacing any existing set of
1590 * values for the associated attribute.
1591 *
1592 * @param attribute The attribute to be included in this entry. It must not
1593 * be {@code null}.
1594 */
1595 public void setAttribute(final Attribute attribute)
1596 {
1597 ensureNotNull(attribute);
1598
1599 final String lowerName;
1600 final Attribute a = getAttribute(attribute.getName(), schema);
1601 if (a == null)
1602 {
1603 lowerName = toLowerCase(attribute.getName());
1604 }
1605 else
1606 {
1607 lowerName = toLowerCase(a.getName());
1608 }
1609
1610 attributes.put(lowerName, attribute);
1611 }
1612
1613
1614
1615 /**
1616 * Adds the provided attribute to this entry, replacing any existing set of
1617 * values for the associated attribute.
1618 *
1619 * @param attributeName The name to use for the attribute. It must not be
1620 * {@code null}.
1621 * @param attributeValue The value to use for the attribute. It must not be
1622 * {@code null}.
1623 */
1624 public void setAttribute(final String attributeName,
1625 final String attributeValue)
1626 {
1627 ensureNotNull(attributeName, attributeValue);
1628 setAttribute(new Attribute(attributeName, schema, attributeValue));
1629 }
1630
1631
1632
1633 /**
1634 * Adds the provided attribute to this entry, replacing any existing set of
1635 * values for the associated attribute.
1636 *
1637 * @param attributeName The name to use for the attribute. It must not be
1638 * {@code null}.
1639 * @param attributeValue The value to use for the attribute. It must not be
1640 * {@code null}.
1641 */
1642 public void setAttribute(final String attributeName,
1643 final byte[] attributeValue)
1644 {
1645 ensureNotNull(attributeName, attributeValue);
1646 setAttribute(new Attribute(attributeName, schema, attributeValue));
1647 }
1648
1649
1650
1651 /**
1652 * Adds the provided attribute to this entry, replacing any existing set of
1653 * values for the associated attribute.
1654 *
1655 * @param attributeName The name to use for the attribute. It must not be
1656 * {@code null}.
1657 * @param attributeValues The set of values to use for the attribute. It
1658 * must not be {@code null}.
1659 */
1660 public void setAttribute(final String attributeName,
1661 final String... attributeValues)
1662 {
1663 ensureNotNull(attributeName, attributeValues);
1664 setAttribute(new Attribute(attributeName, schema, attributeValues));
1665 }
1666
1667
1668
1669 /**
1670 * Adds the provided attribute to this entry, replacing any existing set of
1671 * values for the associated attribute.
1672 *
1673 * @param attributeName The name to use for the attribute. It must not be
1674 * {@code null}.
1675 * @param attributeValues The set of values to use for the attribute. It
1676 * must not be {@code null}.
1677 */
1678 public void setAttribute(final String attributeName,
1679 final byte[]... attributeValues)
1680 {
1681 ensureNotNull(attributeName, attributeValues);
1682 setAttribute(new Attribute(attributeName, schema, attributeValues));
1683 }
1684
1685
1686
1687 /**
1688 * Adds the provided attribute to this entry, replacing any existing set of
1689 * values for the associated attribute.
1690 *
1691 * @param attributeName The name to use for the attribute. It must not be
1692 * {@code null}.
1693 * @param attributeValues The set of values to use for the attribute. It
1694 * must not be {@code null}.
1695 */
1696 public void setAttribute(final String attributeName,
1697 final Collection<String> attributeValues)
1698 {
1699 ensureNotNull(attributeName, attributeValues);
1700 setAttribute(new Attribute(attributeName, schema, attributeValues));
1701 }
1702
1703
1704
1705 /**
1706 * Indicates whether this entry falls within the range of the provided search
1707 * base DN and scope.
1708 *
1709 * @param baseDN The base DN for which to make the determination. It must
1710 * not be {@code null}.
1711 * @param scope The scope for which to make the determination. It must not
1712 * be {@code null}.
1713 *
1714 * @return {@code true} if this entry is within the range of the provided
1715 * base and scope, or {@code false} if not.
1716 *
1717 * @throws LDAPException If a problem occurs while making the determination.
1718 */
1719 public boolean matchesBaseAndScope(final String baseDN,
1720 final SearchScope scope)
1721 throws LDAPException
1722 {
1723 return getParsedDN().matchesBaseAndScope(new DN(baseDN), scope);
1724 }
1725
1726
1727
1728 /**
1729 * Indicates whether this entry falls within the range of the provided search
1730 * base DN and scope.
1731 *
1732 * @param baseDN The base DN for which to make the determination. It must
1733 * not be {@code null}.
1734 * @param scope The scope for which to make the determination. It must not
1735 * be {@code null}.
1736 *
1737 * @return {@code true} if this entry is within the range of the provided
1738 * base and scope, or {@code false} if not.
1739 *
1740 * @throws LDAPException If a problem occurs while making the determination.
1741 */
1742 public boolean matchesBaseAndScope(final DN baseDN, final SearchScope scope)
1743 throws LDAPException
1744 {
1745 return getParsedDN().matchesBaseAndScope(baseDN, scope);
1746 }
1747
1748
1749
1750 /**
1751 * Retrieves a set of modifications that can be applied to the source entry in
1752 * order to make it match the target entry. The diff will be generated in
1753 * reversible form (i.e., the same as calling
1754 * {@code diff(sourceEntry, targetEntry, ignoreRDN, true, attributes)}.
1755 *
1756 * @param sourceEntry The source entry for which the set of modifications
1757 * should be generated.
1758 * @param targetEntry The target entry, which is what the source entry
1759 * should look like if the returned modifications are
1760 * applied.
1761 * @param ignoreRDN Indicates whether to ignore differences in the RDNs
1762 * of the provided entries. If this is {@code false},
1763 * then the resulting set of modifications may include
1764 * changes to the RDN attribute. If it is {@code true},
1765 * then differences in the entry DNs will be ignored.
1766 * @param attributes The set of attributes to be compared. If this is
1767 * {@code null} or empty, then all attributes will be
1768 * compared. Note that if a list of attributes is
1769 * specified, then matching will be performed only
1770 * against the attribute base name and any differences in
1771 * attribute options will be ignored.
1772 *
1773 * @return A set of modifications that can be applied to the source entry in
1774 * order to make it match the target entry.
1775 */
1776 public static List<Modification> diff(final Entry sourceEntry,
1777 final Entry targetEntry,
1778 final boolean ignoreRDN,
1779 final String... attributes)
1780 {
1781 return diff(sourceEntry, targetEntry, ignoreRDN, true, attributes);
1782 }
1783
1784
1785
1786 /**
1787 * Retrieves a set of modifications that can be applied to the source entry in
1788 * order to make it match the target entry.
1789 *
1790 * @param sourceEntry The source entry for which the set of modifications
1791 * should be generated.
1792 * @param targetEntry The target entry, which is what the source entry
1793 * should look like if the returned modifications are
1794 * applied.
1795 * @param ignoreRDN Indicates whether to ignore differences in the RDNs
1796 * of the provided entries. If this is {@code false},
1797 * then the resulting set of modifications may include
1798 * changes to the RDN attribute. If it is {@code true},
1799 * then differences in the entry DNs will be ignored.
1800 * @param reversible Indicates whether to generate the diff in reversible
1801 * form. In reversible form, only the ADD or DELETE
1802 * modification types will be used so that source entry
1803 * could be reconstructed from the target and the
1804 * resulting modifications. In non-reversible form, only
1805 * the REPLACE modification type will be used. Attempts
1806 * to apply the modifications obtained when using
1807 * reversible form are more likely to fail if the entry
1808 * has been modified since the source and target forms
1809 * were obtained.
1810 * @param attributes The set of attributes to be compared. If this is
1811 * {@code null} or empty, then all attributes will be
1812 * compared. Note that if a list of attributes is
1813 * specified, then matching will be performed only
1814 * against the attribute base name and any differences in
1815 * attribute options will be ignored.
1816 *
1817 * @return A set of modifications that can be applied to the source entry in
1818 * order to make it match the target entry.
1819 */
1820 public static List<Modification> diff(final Entry sourceEntry,
1821 final Entry targetEntry,
1822 final boolean ignoreRDN,
1823 final boolean reversible,
1824 final String... attributes)
1825 {
1826 HashSet<String> compareAttrs = null;
1827 if ((attributes != null) && (attributes.length > 0))
1828 {
1829 compareAttrs = new HashSet<String>(attributes.length);
1830 for (final String s : attributes)
1831 {
1832 compareAttrs.add(toLowerCase(Attribute.getBaseName(s)));
1833 }
1834 }
1835
1836 final LinkedHashMap<String,Attribute> sourceOnlyAttrs =
1837 new LinkedHashMap<String,Attribute>();
1838 final LinkedHashMap<String,Attribute> targetOnlyAttrs =
1839 new LinkedHashMap<String,Attribute>();
1840 final LinkedHashMap<String,Attribute> commonAttrs =
1841 new LinkedHashMap<String,Attribute>();
1842
1843 for (final Map.Entry<String,Attribute> e :
1844 sourceEntry.attributes.entrySet())
1845 {
1846 final String lowerName = toLowerCase(e.getKey());
1847 if ((compareAttrs != null) &&
1848 (! compareAttrs.contains(Attribute.getBaseName(lowerName))))
1849 {
1850 continue;
1851 }
1852
1853 sourceOnlyAttrs.put(lowerName, e.getValue());
1854 commonAttrs.put(lowerName, e.getValue());
1855 }
1856
1857 for (final Map.Entry<String,Attribute> e :
1858 targetEntry.attributes.entrySet())
1859 {
1860 final String lowerName = toLowerCase(e.getKey());
1861 if ((compareAttrs != null) &&
1862 (! compareAttrs.contains(Attribute.getBaseName(lowerName))))
1863 {
1864 continue;
1865 }
1866
1867
1868 if (sourceOnlyAttrs.remove(lowerName) == null)
1869 {
1870 // It wasn't in the set of source attributes, so it must be a
1871 // target-only attribute.
1872 targetOnlyAttrs.put(lowerName,e.getValue());
1873 }
1874 }
1875
1876 for (final String lowerName : sourceOnlyAttrs.keySet())
1877 {
1878 commonAttrs.remove(lowerName);
1879 }
1880
1881 RDN sourceRDN = null;
1882 RDN targetRDN = null;
1883 if (ignoreRDN)
1884 {
1885 try
1886 {
1887 sourceRDN = sourceEntry.getRDN();
1888 }
1889 catch (Exception e)
1890 {
1891 debugException(e);
1892 }
1893
1894 try
1895 {
1896 targetRDN = targetEntry.getRDN();
1897 }
1898 catch (Exception e)
1899 {
1900 debugException(e);
1901 }
1902 }
1903
1904 final ArrayList<Modification> mods = new ArrayList<Modification>(10);
1905
1906 for (final Attribute a : sourceOnlyAttrs.values())
1907 {
1908 if (reversible)
1909 {
1910 ASN1OctetString[] values = a.getRawValues();
1911 if ((sourceRDN != null) && (sourceRDN.hasAttribute(a.getName())))
1912 {
1913 final ArrayList<ASN1OctetString> newValues =
1914 new ArrayList<ASN1OctetString>(values.length);
1915 for (final ASN1OctetString value : values)
1916 {
1917 if (! sourceRDN.hasAttributeValue(a.getName(), value.getValue()))
1918 {
1919 newValues.add(value);
1920 }
1921 }
1922
1923 if (newValues.isEmpty())
1924 {
1925 continue;
1926 }
1927 else
1928 {
1929 values = new ASN1OctetString[newValues.size()];
1930 newValues.toArray(values);
1931 }
1932 }
1933
1934 mods.add(new Modification(ModificationType.DELETE, a.getName(),
1935 values));
1936 }
1937 else
1938 {
1939 mods.add(new Modification(ModificationType.REPLACE, a.getName()));
1940 }
1941 }
1942
1943 for (final Attribute a : targetOnlyAttrs.values())
1944 {
1945 ASN1OctetString[] values = a.getRawValues();
1946 if ((targetRDN != null) && (targetRDN.hasAttribute(a.getName())))
1947 {
1948 final ArrayList<ASN1OctetString> newValues =
1949 new ArrayList<ASN1OctetString>(values.length);
1950 for (final ASN1OctetString value : values)
1951 {
1952 if (! targetRDN.hasAttributeValue(a.getName(), value.getValue()))
1953 {
1954 newValues.add(value);
1955 }
1956 }
1957
1958 if (newValues.isEmpty())
1959 {
1960 continue;
1961 }
1962 else
1963 {
1964 values = new ASN1OctetString[newValues.size()];
1965 newValues.toArray(values);
1966 }
1967 }
1968
1969 if (reversible)
1970 {
1971 mods.add(new Modification(ModificationType.ADD, a.getName(), values));
1972 }
1973 else
1974 {
1975 mods.add(new Modification(ModificationType.REPLACE, a.getName(),
1976 values));
1977 }
1978 }
1979
1980 for (final Attribute sourceAttr : commonAttrs.values())
1981 {
1982 final Attribute targetAttr =
1983 targetEntry.getAttribute(sourceAttr.getName());
1984 if (sourceAttr.equals(targetAttr))
1985 {
1986 continue;
1987 }
1988
1989 if (reversible ||
1990 ((targetRDN != null) && targetRDN.hasAttribute(targetAttr.getName())))
1991 {
1992 final ASN1OctetString[] sourceValueArray = sourceAttr.getRawValues();
1993 final LinkedHashMap<ASN1OctetString,ASN1OctetString> sourceValues =
1994 new LinkedHashMap<ASN1OctetString,ASN1OctetString>(
1995 sourceValueArray.length);
1996 for (final ASN1OctetString s : sourceValueArray)
1997 {
1998 try
1999 {
2000 sourceValues.put(sourceAttr.getMatchingRule().normalize(s), s);
2001 }
2002 catch (final Exception e)
2003 {
2004 debugException(e);
2005 sourceValues.put(s, s);
2006 }
2007 }
2008
2009 final ASN1OctetString[] targetValueArray = targetAttr.getRawValues();
2010 final LinkedHashMap<ASN1OctetString,ASN1OctetString> targetValues =
2011 new LinkedHashMap<ASN1OctetString,ASN1OctetString>(
2012 targetValueArray.length);
2013 for (final ASN1OctetString s : targetValueArray)
2014 {
2015 try
2016 {
2017 targetValues.put(sourceAttr.getMatchingRule().normalize(s), s);
2018 }
2019 catch (final Exception e)
2020 {
2021 debugException(e);
2022 targetValues.put(s, s);
2023 }
2024 }
2025
2026 final Iterator<Map.Entry<ASN1OctetString,ASN1OctetString>>
2027 sourceIterator = sourceValues.entrySet().iterator();
2028 while (sourceIterator.hasNext())
2029 {
2030 final Map.Entry<ASN1OctetString,ASN1OctetString> e =
2031 sourceIterator.next();
2032 if (targetValues.remove(e.getKey()) != null)
2033 {
2034 sourceIterator.remove();
2035 }
2036 else if ((sourceRDN != null) &&
2037 sourceRDN.hasAttributeValue(sourceAttr.getName(),
2038 e.getValue().getValue()))
2039 {
2040 sourceIterator.remove();
2041 }
2042 }
2043
2044 final Iterator<Map.Entry<ASN1OctetString,ASN1OctetString>>
2045 targetIterator = targetValues.entrySet().iterator();
2046 while (targetIterator.hasNext())
2047 {
2048 final Map.Entry<ASN1OctetString,ASN1OctetString> e =
2049 targetIterator.next();
2050 if ((targetRDN != null) &&
2051 targetRDN.hasAttributeValue(targetAttr.getName(),
2052 e.getValue().getValue()))
2053 {
2054 targetIterator.remove();
2055 }
2056 }
2057
2058 final ArrayList<ASN1OctetString> addValues =
2059 new ArrayList<ASN1OctetString>(targetValues.values());
2060 final ArrayList<ASN1OctetString> delValues =
2061 new ArrayList<ASN1OctetString>(sourceValues.values());
2062
2063 if (! addValues.isEmpty())
2064 {
2065 final ASN1OctetString[] addArray =
2066 new ASN1OctetString[addValues.size()];
2067 mods.add(new Modification(ModificationType.ADD, targetAttr.getName(),
2068 addValues.toArray(addArray)));
2069 }
2070
2071 if (! delValues.isEmpty())
2072 {
2073 final ASN1OctetString[] delArray =
2074 new ASN1OctetString[delValues.size()];
2075 mods.add(new Modification(ModificationType.DELETE,
2076 sourceAttr.getName(), delValues.toArray(delArray)));
2077 }
2078 }
2079 else
2080 {
2081 mods.add(new Modification(ModificationType.REPLACE,
2082 targetAttr.getName(), targetAttr.getRawValues()));
2083 }
2084 }
2085
2086 return mods;
2087 }
2088
2089
2090
2091 /**
2092 * Merges the contents of all provided entries so that the resulting entry
2093 * will contain all attribute values present in at least one of the entries.
2094 *
2095 * @param entries The set of entries to be merged. At least one entry must
2096 * be provided.
2097 *
2098 * @return An entry containing all attribute values present in at least one
2099 * of the entries.
2100 */
2101 public static Entry mergeEntries(final Entry... entries)
2102 {
2103 ensureNotNull(entries);
2104 ensureTrue(entries.length > 0);
2105
2106 final Entry newEntry = entries[0].duplicate();
2107
2108 for (int i=1; i < entries.length; i++)
2109 {
2110 for (final Attribute a : entries[i].attributes.values())
2111 {
2112 newEntry.addAttribute(a);
2113 }
2114 }
2115
2116 return newEntry;
2117 }
2118
2119
2120
2121 /**
2122 * Intersects the contents of all provided entries so that the resulting
2123 * entry will contain only attribute values present in all of the provided
2124 * entries.
2125 *
2126 * @param entries The set of entries to be intersected. At least one entry
2127 * must be provided.
2128 *
2129 * @return An entry containing only attribute values contained in all of the
2130 * provided entries.
2131 */
2132 public static Entry intersectEntries(final Entry... entries)
2133 {
2134 ensureNotNull(entries);
2135 ensureTrue(entries.length > 0);
2136
2137 final Entry newEntry = entries[0].duplicate();
2138
2139 for (final Attribute a : entries[0].attributes.values())
2140 {
2141 final String name = a.getName();
2142 for (final byte[] v : a.getValueByteArrays())
2143 {
2144 for (int i=1; i < entries.length; i++)
2145 {
2146 if (! entries[i].hasAttributeValue(name, v))
2147 {
2148 newEntry.removeAttributeValue(name, v);
2149 break;
2150 }
2151 }
2152 }
2153 }
2154
2155 return newEntry;
2156 }
2157
2158
2159
2160 /**
2161 * Creates a duplicate of the provided entry with the given set of
2162 * modifications applied to it.
2163 *
2164 * @param entry The entry to be modified. It must not be
2165 * {@code null}.
2166 * @param lenient Indicates whether to exhibit a lenient behavior for
2167 * the modifications, which will cause it to ignore
2168 * problems like trying to add values that already
2169 * exist or to remove nonexistent attributes or values.
2170 * @param modifications The set of modifications to apply to the entry. It
2171 * must not be {@code null} or empty.
2172 *
2173 * @return An updated version of the entry with the requested modifications
2174 * applied.
2175 *
2176 * @throws LDAPException If a problem occurs while attempting to apply the
2177 * modifications.
2178 */
2179 public static Entry applyModifications(final Entry entry,
2180 final boolean lenient,
2181 final Modification... modifications)
2182 throws LDAPException
2183 {
2184 ensureNotNull(entry, modifications);
2185 ensureFalse(modifications.length == 0);
2186
2187 return applyModifications(entry, lenient, Arrays.asList(modifications));
2188 }
2189
2190
2191
2192 /**
2193 * Creates a duplicate of the provided entry with the given set of
2194 * modifications applied to it.
2195 *
2196 * @param entry The entry to be modified. It must not be
2197 * {@code null}.
2198 * @param lenient Indicates whether to exhibit a lenient behavior for
2199 * the modifications, which will cause it to ignore
2200 * problems like trying to add values that already
2201 * exist or to remove nonexistent attributes or values.
2202 * @param modifications The set of modifications to apply to the entry. It
2203 * must not be {@code null} or empty.
2204 *
2205 * @return An updated version of the entry with the requested modifications
2206 * applied.
2207 *
2208 * @throws LDAPException If a problem occurs while attempting to apply the
2209 * modifications.
2210 */
2211 public static Entry applyModifications(final Entry entry,
2212 final boolean lenient,
2213 final List<Modification> modifications)
2214 throws LDAPException
2215 {
2216 ensureNotNull(entry, modifications);
2217 ensureFalse(modifications.isEmpty());
2218
2219 final Entry e = entry.duplicate();
2220 final ArrayList<String> errors =
2221 new ArrayList<String>(modifications.size());
2222 ResultCode resultCode = null;
2223
2224 // Get the RDN for the entry to ensure that RDN modifications are not
2225 // allowed.
2226 RDN rdn = null;
2227 try
2228 {
2229 rdn = entry.getRDN();
2230 }
2231 catch (final LDAPException le)
2232 {
2233 debugException(le);
2234 }
2235
2236 for (final Modification m : modifications)
2237 {
2238 final String name = m.getAttributeName();
2239 final byte[][] values = m.getValueByteArrays();
2240 switch (m.getModificationType().intValue())
2241 {
2242 case ModificationType.ADD_INT_VALUE:
2243 if (lenient)
2244 {
2245 e.addAttribute(m.getAttribute());
2246 }
2247 else
2248 {
2249 if (values.length == 0)
2250 {
2251 errors.add(ERR_ENTRY_APPLY_MODS_ADD_NO_VALUES.get(name));
2252 }
2253
2254 for (int i=0; i < values.length; i++)
2255 {
2256 if (! e.addAttribute(name, values[i]))
2257 {
2258 if (resultCode == null)
2259 {
2260 resultCode = ResultCode.ATTRIBUTE_OR_VALUE_EXISTS;
2261 }
2262 errors.add(ERR_ENTRY_APPLY_MODS_ADD_EXISTING.get(
2263 m.getValues()[i], name));
2264 }
2265 }
2266 }
2267 break;
2268
2269 case ModificationType.DELETE_INT_VALUE:
2270 if (values.length == 0)
2271 {
2272 final boolean removed = e.removeAttribute(name);
2273 if (! (lenient || removed))
2274 {
2275 if (resultCode == null)
2276 {
2277 resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
2278 }
2279 errors.add(ERR_ENTRY_APPLY_MODS_DELETE_NONEXISTENT_ATTR.get(
2280 name));
2281 }
2282 }
2283 else
2284 {
2285 for (int i=0; i < values.length; i++)
2286 {
2287 final boolean removed = e.removeAttributeValue(name, values[i]);
2288 if (! (lenient || removed))
2289 {
2290 if (resultCode == null)
2291 {
2292 resultCode = ResultCode.NO_SUCH_ATTRIBUTE;
2293 }
2294 errors.add(ERR_ENTRY_APPLY_MODS_DELETE_NONEXISTENT_VALUE.get(
2295 m.getValues()[i], name));
2296 }
2297 }
2298 }
2299 break;
2300
2301 case ModificationType.REPLACE_INT_VALUE:
2302 if (values.length == 0)
2303 {
2304 e.removeAttribute(name);
2305 }
2306 else
2307 {
2308 e.setAttribute(m.getAttribute());
2309 }
2310 break;
2311
2312 case ModificationType.INCREMENT_INT_VALUE:
2313 final Attribute a = e.getAttribute(name);
2314 if ((a == null) || (! a.hasValue()))
2315 {
2316 errors.add(ERR_ENTRY_APPLY_MODS_INCREMENT_NO_SUCH_ATTR.get(name));
2317 continue;
2318 }
2319
2320 if (a.size() > 1)
2321 {
2322 errors.add(ERR_ENTRY_APPLY_MODS_INCREMENT_NOT_SINGLE_VALUED.get(
2323 name));
2324 continue;
2325 }
2326
2327 if ((rdn != null) && rdn.hasAttribute(name))
2328 {
2329 final String msg =
2330 ERR_ENTRY_APPLY_MODS_TARGETS_RDN.get(entry.getDN());
2331 if (! errors.contains(msg))
2332 {
2333 errors.add(msg);
2334 }
2335
2336 if (resultCode == null)
2337 {
2338 resultCode = ResultCode.NOT_ALLOWED_ON_RDN;
2339 }
2340 continue;
2341 }
2342
2343 final BigInteger currentValue;
2344 try
2345 {
2346 currentValue = new BigInteger(a.getValue());
2347 }
2348 catch (NumberFormatException nfe)
2349 {
2350 debugException(nfe);
2351 errors.add(
2352 ERR_ENTRY_APPLY_MODS_INCREMENT_ENTRY_VALUE_NOT_INTEGER.get(
2353 name, a.getValue()));
2354 continue;
2355 }
2356
2357 if (values.length == 0)
2358 {
2359 errors.add(ERR_ENTRY_APPLY_MODS_INCREMENT_NO_MOD_VALUES.get(name));
2360 continue;
2361 }
2362 else if (values.length > 1)
2363 {
2364 errors.add(ERR_ENTRY_APPLY_MODS_INCREMENT_MULTIPLE_MOD_VALUES.get(
2365 name));
2366 continue;
2367 }
2368
2369 final BigInteger incrementValue;
2370 final String incrementValueStr = m.getValues()[0];
2371 try
2372 {
2373 incrementValue = new BigInteger(incrementValueStr);
2374 }
2375 catch (NumberFormatException nfe)
2376 {
2377 debugException(nfe);
2378 errors.add(ERR_ENTRY_APPLY_MODS_INCREMENT_MOD_VALUE_NOT_INTEGER.get(
2379 name, incrementValueStr));
2380 continue;
2381 }
2382
2383 final BigInteger newValue = currentValue.add(incrementValue);
2384 e.setAttribute(name, newValue.toString());
2385 break;
2386
2387 default:
2388 errors.add(ERR_ENTRY_APPLY_MODS_UNKNOWN_TYPE.get(
2389 String.valueOf(m.getModificationType())));
2390 break;
2391 }
2392 }
2393
2394
2395 // Make sure that the entry still has all of the RDN attribute values.
2396 if (rdn != null)
2397 {
2398 final String[] rdnAttrs = rdn.getAttributeNames();
2399 final byte[][] rdnValues = rdn.getByteArrayAttributeValues();
2400 for (int i=0; i < rdnAttrs.length; i++)
2401 {
2402 if (! e.hasAttributeValue(rdnAttrs[i], rdnValues[i]))
2403 {
2404 errors.add(ERR_ENTRY_APPLY_MODS_TARGETS_RDN.get(entry.getDN()));
2405 if (resultCode == null)
2406 {
2407 resultCode = ResultCode.NOT_ALLOWED_ON_RDN;
2408 }
2409 break;
2410 }
2411 }
2412 }
2413
2414
2415 if (errors.isEmpty())
2416 {
2417 return e;
2418 }
2419
2420 if (resultCode == null)
2421 {
2422 resultCode = ResultCode.CONSTRAINT_VIOLATION;
2423 }
2424
2425 throw new LDAPException(resultCode,
2426 ERR_ENTRY_APPLY_MODS_FAILURE.get(e.getDN(),
2427 concatenateStrings(errors)));
2428 }
2429
2430
2431
2432 /**
2433 * Generates a hash code for this entry.
2434 *
2435 * @return The generated hash code for this entry.
2436 */
2437 @Override()
2438 public int hashCode()
2439 {
2440 int hashCode = 0;
2441 try
2442 {
2443 hashCode += getParsedDN().hashCode();
2444 }
2445 catch (LDAPException le)
2446 {
2447 debugException(le);
2448 hashCode += dn.hashCode();
2449 }
2450
2451 for (final Attribute a : attributes.values())
2452 {
2453 hashCode += a.hashCode();
2454 }
2455
2456 return hashCode;
2457 }
2458
2459
2460
2461 /**
2462 * Indicates whether the provided object is equal to this entry. The provided
2463 * object will only be considered equal to this entry if it is an entry with
2464 * the same DN and set of attributes.
2465 *
2466 * @param o The object for which to make the determination.
2467 *
2468 * @return {@code true} if the provided object is considered equal to this
2469 * entry, or {@code false} if not.
2470 */
2471 @Override()
2472 public boolean equals(final Object o)
2473 {
2474 if (o == null)
2475 {
2476 return false;
2477 }
2478
2479 if (o == this)
2480 {
2481 return true;
2482 }
2483
2484 if (! (o instanceof Entry))
2485 {
2486 return false;
2487 }
2488
2489 final Entry e = (Entry) o;
2490
2491 try
2492 {
2493 final DN thisDN = getParsedDN();
2494 final DN thatDN = e.getParsedDN();
2495 if (! thisDN.equals(thatDN))
2496 {
2497 return false;
2498 }
2499 }
2500 catch (LDAPException le)
2501 {
2502 debugException(le);
2503 if (! dn.equals(e.dn))
2504 {
2505 return false;
2506 }
2507 }
2508
2509 if (attributes.size() != e.attributes.size())
2510 {
2511 return false;
2512 }
2513
2514 for (final Attribute a : attributes.values())
2515 {
2516 if (! e.hasAttribute(a))
2517 {
2518 return false;
2519 }
2520 }
2521
2522 return true;
2523 }
2524
2525
2526
2527 /**
2528 * Creates a new entry that is a duplicate of this entry.
2529 *
2530 * @return A new entry that is a duplicate of this entry.
2531 */
2532 public Entry duplicate()
2533 {
2534 return new Entry(dn, schema, attributes.values());
2535 }
2536
2537
2538
2539 /**
2540 * Retrieves an LDIF representation of this entry, with each attribute value
2541 * on a separate line. Long lines will not be wrapped.
2542 *
2543 * @return An LDIF representation of this entry.
2544 */
2545 public final String[] toLDIF()
2546 {
2547 return toLDIF(0);
2548 }
2549
2550
2551
2552 /**
2553 * Retrieves an LDIF representation of this entry, with each attribute value
2554 * on a separate line. Long lines will be wrapped at the specified column.
2555 *
2556 * @param wrapColumn The column at which long lines should be wrapped. A
2557 * value less than or equal to two indicates that no
2558 * wrapping should be performed.
2559 *
2560 * @return An LDIF representation of this entry.
2561 */
2562 public final String[] toLDIF(final int wrapColumn)
2563 {
2564 List<String> ldifLines = new ArrayList<String>(2*attributes.size());
2565 ldifLines.add(LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(dn)));
2566
2567 for (final Attribute a : attributes.values())
2568 {
2569 final String name = a.getName();
2570 for (final ASN1OctetString value : a.getRawValues())
2571 {
2572 ldifLines.add(LDIFWriter.encodeNameAndValue(name, value));
2573 }
2574 }
2575
2576 if (wrapColumn > 2)
2577 {
2578 ldifLines = LDIFWriter.wrapLines(wrapColumn, ldifLines);
2579 }
2580
2581 final String[] lineArray = new String[ldifLines.size()];
2582 ldifLines.toArray(lineArray);
2583 return lineArray;
2584 }
2585
2586
2587
2588 /**
2589 * Appends an LDIF representation of this entry to the provided buffer. Long
2590 * lines will not be wrapped.
2591 *
2592 * @param buffer The buffer to which the LDIF representation of this entry
2593 * should be written.
2594 */
2595 public final void toLDIF(final ByteStringBuffer buffer)
2596 {
2597 toLDIF(buffer, 0);
2598 }
2599
2600
2601
2602 /**
2603 * Appends an LDIF representation of this entry to the provided buffer.
2604 *
2605 * @param buffer The buffer to which the LDIF representation of this
2606 * entry should be written.
2607 * @param wrapColumn The column at which long lines should be wrapped. A
2608 * value less than or equal to two indicates that no
2609 * wrapping should be performed.
2610 */
2611 public final void toLDIF(final ByteStringBuffer buffer, final int wrapColumn)
2612 {
2613 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(dn), buffer,
2614 wrapColumn);
2615 buffer.append(EOL_BYTES);
2616
2617 for (final Attribute a : attributes.values())
2618 {
2619 final String name = a.getName();
2620 for (final ASN1OctetString value : a.getRawValues())
2621 {
2622 LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
2623 buffer.append(EOL_BYTES);
2624 }
2625 }
2626 }
2627
2628
2629
2630 /**
2631 * Retrieves an LDIF-formatted string representation of this entry. No
2632 * wrapping will be performed, and no extra blank lines will be added.
2633 *
2634 * @return An LDIF-formatted string representation of this entry.
2635 */
2636 public final String toLDIFString()
2637 {
2638 final StringBuilder buffer = new StringBuilder();
2639 toLDIFString(buffer, 0);
2640 return buffer.toString();
2641 }
2642
2643
2644
2645 /**
2646 * Retrieves an LDIF-formatted string representation of this entry. No
2647 * extra blank lines will be added.
2648 *
2649 * @param wrapColumn The column at which long lines should be wrapped. A
2650 * value less than or equal to two indicates that no
2651 * wrapping should be performed.
2652 *
2653 * @return An LDIF-formatted string representation of this entry.
2654 */
2655 public final String toLDIFString(final int wrapColumn)
2656 {
2657 final StringBuilder buffer = new StringBuilder();
2658 toLDIFString(buffer, wrapColumn);
2659 return buffer.toString();
2660 }
2661
2662
2663
2664 /**
2665 * Appends an LDIF-formatted string representation of this entry to the
2666 * provided buffer. No wrapping will be performed, and no extra blank lines
2667 * will be added.
2668 *
2669 * @param buffer The buffer to which to append the LDIF representation of
2670 * this entry.
2671 */
2672 public final void toLDIFString(final StringBuilder buffer)
2673 {
2674 toLDIFString(buffer, 0);
2675 }
2676
2677
2678
2679 /**
2680 * Appends an LDIF-formatted string representation of this entry to the
2681 * provided buffer. No extra blank lines will be added.
2682 *
2683 * @param buffer The buffer to which to append the LDIF representation
2684 * of this entry.
2685 * @param wrapColumn The column at which long lines should be wrapped. A
2686 * value less than or equal to two indicates that no
2687 * wrapping should be performed.
2688 */
2689 public final void toLDIFString(final StringBuilder buffer,
2690 final int wrapColumn)
2691 {
2692 LDIFWriter.encodeNameAndValue("dn", new ASN1OctetString(dn), buffer,
2693 wrapColumn);
2694 buffer.append(EOL);
2695
2696 for (final Attribute a : attributes.values())
2697 {
2698 final String name = a.getName();
2699 for (final ASN1OctetString value : a.getRawValues())
2700 {
2701 LDIFWriter.encodeNameAndValue(name, value, buffer, wrapColumn);
2702 buffer.append(EOL);
2703 }
2704 }
2705 }
2706
2707
2708
2709 /**
2710 * Retrieves a string representation of this entry.
2711 *
2712 * @return A string representation of this entry.
2713 */
2714 @Override()
2715 public final String toString()
2716 {
2717 final StringBuilder buffer = new StringBuilder();
2718 toString(buffer);
2719 return buffer.toString();
2720 }
2721
2722
2723
2724 /**
2725 * Appends a string representation of this entry to the provided buffer.
2726 *
2727 * @param buffer The buffer to which to append the string representation of
2728 * this entry.
2729 */
2730 public void toString(final StringBuilder buffer)
2731 {
2732 buffer.append("Entry(dn='");
2733 buffer.append(dn);
2734 buffer.append("', attributes={");
2735
2736 final Iterator<Attribute> iterator = attributes.values().iterator();
2737
2738 while (iterator.hasNext())
2739 {
2740 iterator.next().toString(buffer);
2741 if (iterator.hasNext())
2742 {
2743 buffer.append(", ");
2744 }
2745 }
2746
2747 buffer.append("})");
2748 }
2749 }