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