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