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 }