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