001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.types; 028 029 030 031 import java.util.ArrayList; 032 import java.util.Collection; 033 import java.util.LinkedHashSet; 034 import java.util.List; 035 import java.util.Set; 036 037 import org.opends.server.api.ApproximateMatchingRule; 038 import org.opends.server.api.OrderingMatchingRule; 039 import org.opends.server.api.SubstringMatchingRule; 040 import org.opends.server.core.DirectoryServer; 041 import org.opends.server.util.Base64; 042 043 import static org.opends.server.loggers.debug.DebugLogger.*; 044 import org.opends.server.loggers.debug.DebugTracer; 045 import static org.opends.server.util.ServerConstants.*; 046 import static org.opends.server.util.StaticUtils.*; 047 048 049 050 /** 051 * This class defines a data structure for storing and interacting 052 * with an attribute that may be used in the Directory Server. 053 */ 054 @org.opends.server.types.PublicAPI( 055 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 056 mayInstantiate=true, 057 mayExtend=false, 058 mayInvoke=true) 059 public class Attribute 060 { 061 /** 062 * The tracer object for the debug logger. 063 */ 064 private static final DebugTracer TRACER = getTracer(); 065 066 // The attribute type for this attribute. 067 private final AttributeType attributeType; 068 069 // The set of values for this attribute. 070 private LinkedHashSet<AttributeValue> values; 071 072 // The set of options for this attribute. 073 private final LinkedHashSet<String> options; 074 075 // The set of options for this attribute, formatted in all lowercase 076 // characters. 077 private final LinkedHashSet<String> lowerOptions; 078 079 // The name of this attribute as provided by the end user. 080 private final String name; 081 082 083 084 /** 085 * Creates a new attribute with the specified type. It will not 086 * have any values. 087 * 088 * @param attributeType The attribute type for this attribute. 089 */ 090 public Attribute(AttributeType attributeType) 091 { 092 this.attributeType = attributeType; 093 this.name = attributeType.getPrimaryName(); 094 this.options = new LinkedHashSet<String>(0); 095 this.values = new LinkedHashSet<AttributeValue>(); 096 097 lowerOptions = options; 098 } 099 100 101 102 /** 103 * Creates a new attribute with the specified type and user-provided 104 * name. It will not have any values. 105 * 106 * @param attributeType The attribute type for this attribute. 107 * @param name The user-provided name for this attribute. 108 */ 109 public Attribute(AttributeType attributeType, String name) 110 { 111 this.attributeType = attributeType; 112 this.name = name; 113 this.options = new LinkedHashSet<String>(0); 114 this.values = new LinkedHashSet<AttributeValue>(); 115 116 lowerOptions = options; 117 } 118 119 120 121 /** 122 * Creates a new attribute with the specified type, user-provided 123 * name, and set of values. 124 * 125 * @param attributeType The attribute type for this attribute. 126 * @param name The user-provided name for this attribute. 127 * @param values The set of values for this attribute. 128 */ 129 public Attribute(AttributeType attributeType, String name, 130 LinkedHashSet<AttributeValue> values) 131 { 132 this.attributeType = attributeType; 133 this.name = name; 134 this.options = new LinkedHashSet<String>(0); 135 136 lowerOptions = options; 137 138 if (values == null) 139 { 140 this.values = new LinkedHashSet<AttributeValue>(); 141 } 142 else 143 { 144 this.values = values; 145 } 146 } 147 148 149 150 /** 151 * Creates a new attribute with the specified name and value. 152 * 153 * @param lowerName The name or OID of the attribute type for 154 * this attribute, formatted in all lowercase 155 * characters. 156 * @param valueString The String representation of the attribute 157 * value. 158 */ 159 public Attribute(String lowerName, String valueString) 160 { 161 this.attributeType = 162 DirectoryServer.getAttributeType(lowerName, true); 163 this.name = lowerName; 164 this.values = new LinkedHashSet<AttributeValue>(); 165 this.values.add(new AttributeValue(this.attributeType, 166 valueString)); 167 this.options = new LinkedHashSet<String>(0); 168 169 lowerOptions = options; 170 } 171 172 173 174 /** 175 * Creates a new attribute with the specified type, user-provided 176 * name, and set of values. 177 * 178 * @param attributeType The attribute type for this attribute. 179 * @param name The user-provided name for this attribute. 180 * @param options The set of options for this attribute. 181 * @param values The set of values for this attribute. 182 */ 183 public Attribute(AttributeType attributeType, String name, 184 LinkedHashSet<String> options, 185 LinkedHashSet<AttributeValue> values) 186 { 187 this.attributeType = attributeType; 188 this.name = name; 189 190 if ((options == null) || options.isEmpty()) 191 { 192 this.options = new LinkedHashSet<String>(0); 193 lowerOptions = options; 194 } 195 else 196 { 197 this.options = options; 198 lowerOptions = new LinkedHashSet<String>(options.size()); 199 for (String option : options) 200 { 201 lowerOptions.add(toLowerCase(option)); 202 } 203 } 204 205 if (values == null) 206 { 207 this.values = new LinkedHashSet<AttributeValue>(0); 208 } 209 else 210 { 211 this.values = values; 212 } 213 } 214 215 216 217 /** 218 * Retrieves the attribute type for this attribute. 219 * 220 * @return The attribute type for this attribute. 221 */ 222 public AttributeType getAttributeType() 223 { 224 return attributeType; 225 } 226 227 228 229 /** 230 * Retrieves the user-provided name for this attribute. 231 * 232 * @return The user-provided name for this attribute. 233 */ 234 public String getName() 235 { 236 return name; 237 } 238 239 240 241 /** 242 * Retrieves the user-provided name of the attribute, along with any 243 * options that might have been provided. 244 * 245 * @return The user-provided name of the attribute, along with any 246 * options that might have been provided. 247 */ 248 public String getNameWithOptions() 249 { 250 if (options.isEmpty()) 251 { 252 return name; 253 } 254 else 255 { 256 StringBuilder buffer = new StringBuilder(); 257 buffer.append(name); 258 for (String option : options) 259 { 260 buffer.append(';'); 261 buffer.append(option); 262 } 263 return buffer.toString(); 264 } 265 } 266 267 268 269 /** 270 * Retrieves the set of attribute options for this attribute. 271 * 272 * @return The set of attribute options for this attribute. 273 */ 274 public LinkedHashSet<String> getOptions() 275 { 276 return options; 277 } 278 279 280 281 /** 282 * Indicates whether this attribute has the specified option. 283 * 284 * @param option The option for which to make the determination. 285 * 286 * @return <CODE>true</CODE> if this attribute has the specified 287 * option, or <CODE>false</CODE> if not. 288 */ 289 public boolean hasOption(String option) 290 { 291 return lowerOptions.contains(toLowerCase(option)); 292 } 293 294 295 296 /** 297 * Indicates whether this attribute has any options at all. 298 * 299 * @return <CODE>true</CODE> if this attribute has at least one 300 * option, or <CODE>false</CODE> if not. 301 */ 302 public boolean hasOptions() 303 { 304 return (! options.isEmpty()); 305 } 306 307 308 309 /** 310 * Indicates whether this attribute has all of the options in the 311 * provided collection. 312 * 313 * @param options The collection of options for which to make the 314 * determination. 315 * 316 * @return <CODE>true</CODE> if this attribute has all of the 317 * specified options, or <CODE>false</CODE> if it does not 318 * have at least one of them. 319 */ 320 public boolean hasOptions(Collection<String> options) 321 { 322 if (options == null) 323 { 324 return true; 325 } 326 327 for (String option : options) 328 { 329 if (! lowerOptions.contains(toLowerCase(option))) 330 { 331 return false; 332 } 333 } 334 335 return true; 336 } 337 338 339 340 /** 341 * Indicates whether this attribute has exactly the set of options 342 * in the provided set. 343 * 344 * @param options The set of options for which to make the 345 * determination. 346 * 347 * @return <CODE>true</CODE> if this attribute has exactly the 348 * specified set of options, or <CODE>false</CODE> if the 349 * set of options is different in any way. 350 */ 351 public boolean optionsEqual(Set<String> options) 352 { 353 if (options == null) 354 { 355 return this.options == null || this.options.isEmpty(); 356 } 357 358 if (options.isEmpty() && this.options.isEmpty()) 359 { 360 return true; 361 } 362 363 if (options.size() != this.options.size()) 364 { 365 return false; 366 } 367 368 for (String s : options) 369 { 370 if (! lowerOptions.contains(toLowerCase(s))) 371 { 372 return false; 373 } 374 } 375 376 return true; 377 } 378 379 380 381 /** 382 * Retrieves the set of values for this attribute. The returned set 383 * of values may be altered by the caller. 384 * 385 * @return The set of values for this attribute. 386 */ 387 public LinkedHashSet<AttributeValue> getValues() 388 { 389 return values; 390 } 391 392 393 394 /** 395 * Specifies the set of values for this attribute. 396 * 397 * @param values The set of values for this attribute. 398 */ 399 public void setValues(LinkedHashSet<AttributeValue> values) 400 { 401 if (values == null) 402 { 403 this.values = new LinkedHashSet<AttributeValue>(); 404 } 405 else 406 { 407 this.values = values; 408 } 409 } 410 411 412 413 /** 414 * Indicates whether this attribute contains one or more values. 415 * 416 * @return <CODE>true</CODE> if this attribute contains one or more 417 * values, or <CODE>false</CODE> if it does not. 418 */ 419 public boolean hasValue() 420 { 421 return (! getValues().isEmpty()); 422 } 423 424 425 426 /** 427 * Indicates whether this attribute contains the specified value. 428 * 429 * @param value The value for which to make the determination. 430 * 431 * @return <CODE>true</CODE> if this attribute has the specified 432 * value, or <CODE>false</CODE> if not. 433 */ 434 public boolean hasValue(AttributeValue value) 435 { 436 return getValues().contains(value); 437 } 438 439 440 441 /** 442 * Indicates whether this attribute contains all the values in the 443 * collection. 444 * 445 * @param values The set of values for which to make the 446 * determination. 447 * 448 * @return <CODE>true</CODE> if this attribute contains all the 449 * values in the provided collection, or <CODE>false</CODE> 450 * if it does not contain at least one of them. 451 */ 452 public boolean hasAllValues(Collection<AttributeValue> values) 453 { 454 for (AttributeValue value : values) 455 { 456 if (! getValues().contains(value)) 457 { 458 return false; 459 } 460 } 461 462 return true; 463 } 464 465 466 467 /** 468 * Indicates whether this attribute contains any of the values in 469 * the collection. 470 * 471 * @param values The set of values for which to make the 472 * determination. 473 * 474 * @return <CODE>true</CODE> if this attribute contains at least 475 * one of the values in the provided collection, or 476 * <CODE>false</CODE> if it does not contain any of the 477 * values. 478 */ 479 public boolean hasAnyValue(Collection<AttributeValue> values) 480 { 481 for (AttributeValue value : values) 482 { 483 if (getValues().contains(value)) 484 { 485 return true; 486 } 487 } 488 489 return false; 490 } 491 492 493 494 /** 495 * Indicates whether this attribute has any value(s) that match the 496 * provided substring. 497 * 498 * @param subInitial The subInitial component to use in the 499 * determination. 500 * @param subAny The subAny components to use in the 501 * determination. 502 * @param subFinal The subFinal component to use in the 503 * determination. 504 * 505 * @return <CODE>UNDEFINED</CODE> if this attribute does not have a 506 * substring matching rule, <CODE>TRUE</CODE> if at least 507 * one value matches the provided substring, or 508 * <CODE>FALSE</CODE> otherwise. 509 */ 510 public ConditionResult matchesSubstring(ByteString subInitial, 511 List<ByteString> subAny, 512 ByteString subFinal) 513 { 514 SubstringMatchingRule matchingRule = 515 attributeType.getSubstringMatchingRule(); 516 if (matchingRule == null) 517 { 518 return ConditionResult.UNDEFINED; 519 } 520 521 522 ByteString normalizedSubInitial; 523 if (subInitial == null) 524 { 525 normalizedSubInitial = null; 526 } 527 else 528 { 529 try 530 { 531 normalizedSubInitial = 532 matchingRule.normalizeSubstring(subInitial); 533 } 534 catch (Exception e) 535 { 536 if (debugEnabled()) 537 { 538 TRACER.debugCaught(DebugLogLevel.ERROR, e); 539 } 540 541 // The substring couldn't be normalized. We have to return 542 // "undefined". 543 return ConditionResult.UNDEFINED; 544 } 545 } 546 547 548 ArrayList<ByteString> normalizedSubAny; 549 if (subAny == null) 550 { 551 normalizedSubAny = null; 552 } 553 else 554 { 555 normalizedSubAny = 556 new ArrayList<ByteString>(subAny.size()); 557 for (ByteString subAnyElement : subAny) 558 { 559 try 560 { 561 normalizedSubAny.add(matchingRule.normalizeSubstring( 562 subAnyElement)); 563 } 564 catch (Exception e) 565 { 566 if (debugEnabled()) 567 { 568 TRACER.debugCaught(DebugLogLevel.ERROR, e); 569 } 570 571 // The substring couldn't be normalized. We have to return 572 // "undefined". 573 return ConditionResult.UNDEFINED; 574 } 575 } 576 } 577 578 579 ByteString normalizedSubFinal; 580 if (subFinal == null) 581 { 582 normalizedSubFinal = null; 583 } 584 else 585 { 586 try 587 { 588 normalizedSubFinal = 589 matchingRule.normalizeSubstring(subFinal); 590 } 591 catch (Exception e) 592 { 593 if (debugEnabled()) 594 { 595 TRACER.debugCaught(DebugLogLevel.ERROR, e); 596 } 597 598 // The substring couldn't be normalized. We have to return 599 // "undefined". 600 return ConditionResult.UNDEFINED; 601 } 602 } 603 604 605 ConditionResult result = ConditionResult.FALSE; 606 for (AttributeValue value : getValues()) 607 { 608 try 609 { 610 if (matchingRule.valueMatchesSubstring( 611 value.getNormalizedValue(), 612 normalizedSubInitial, 613 normalizedSubAny, 614 normalizedSubFinal)) 615 { 616 return ConditionResult.TRUE; 617 } 618 } 619 catch (Exception e) 620 { 621 if (debugEnabled()) 622 { 623 TRACER.debugCaught(DebugLogLevel.ERROR, e); 624 } 625 626 // The value couldn't be normalized. If we can't find a 627 // definite match, then we should return "undefined". 628 result = ConditionResult.UNDEFINED; 629 } 630 } 631 632 return result; 633 } 634 635 636 637 /** 638 * Indicates whether this attribute has any value(s) that are 639 * greater than or equal to the provided value. 640 * 641 * @param value The value for which to make the determination. 642 * 643 * @return <CODE>UNDEFINED</CODE> if this attribute does not have 644 * an ordering matching rule, <CODE>TRUE</CODE> if at least 645 * one value is greater than or equal to the provided 646 * value, or <CODE>false</CODE> otherwise. 647 */ 648 public ConditionResult greaterThanOrEqualTo(AttributeValue value) 649 { 650 OrderingMatchingRule matchingRule = 651 attributeType.getOrderingMatchingRule(); 652 if (matchingRule == null) 653 { 654 return ConditionResult.UNDEFINED; 655 } 656 657 ByteString normalizedValue; 658 try 659 { 660 normalizedValue = value.getNormalizedValue(); 661 } 662 catch (Exception e) 663 { 664 if (debugEnabled()) 665 { 666 TRACER.debugCaught(DebugLogLevel.ERROR, e); 667 } 668 669 // We couldn't normalize the provided value. We should return 670 // "undefined". 671 return ConditionResult.UNDEFINED; 672 } 673 674 ConditionResult result = ConditionResult.FALSE; 675 for (AttributeValue v : getValues()) 676 { 677 try 678 { 679 ByteString nv = v.getNormalizedValue(); 680 int comparisonResult = 681 matchingRule.compareValues(nv, normalizedValue); 682 if (comparisonResult >= 0) 683 { 684 return ConditionResult.TRUE; 685 } 686 } 687 catch (Exception e) 688 { 689 if (debugEnabled()) 690 { 691 TRACER.debugCaught(DebugLogLevel.ERROR, e); 692 } 693 694 // We couldn't normalize one of the attribute values. If we 695 // can't find a definite match, then we should return 696 // "undefined". 697 result = ConditionResult.UNDEFINED; 698 } 699 } 700 701 return result; 702 } 703 704 705 706 /** 707 * Indicates whether this attribute has any value(s) that are less 708 * than or equal to the provided value. 709 * 710 * @param value The value for which to make the determination. 711 * 712 * @return <CODE>UNDEFINED</CODE> if this attribute does not have 713 * an ordering matching rule, <CODE>TRUE</CODE> if at least 714 * one value is less than or equal to the provided value, 715 * or <CODE>false</CODE> otherwise. 716 */ 717 public ConditionResult lessThanOrEqualTo(AttributeValue value) 718 { 719 OrderingMatchingRule matchingRule = 720 attributeType.getOrderingMatchingRule(); 721 if (matchingRule == null) 722 { 723 return ConditionResult.UNDEFINED; 724 } 725 726 ByteString normalizedValue; 727 try 728 { 729 normalizedValue = value.getNormalizedValue(); 730 } 731 catch (Exception e) 732 { 733 if (debugEnabled()) 734 { 735 TRACER.debugCaught(DebugLogLevel.ERROR, e); 736 } 737 738 // We couldn't normalize the provided value. We should return 739 // "undefined". 740 return ConditionResult.UNDEFINED; 741 } 742 743 ConditionResult result = ConditionResult.FALSE; 744 for (AttributeValue v : getValues()) 745 { 746 try 747 { 748 ByteString nv = v.getNormalizedValue(); 749 int comparisonResult = 750 matchingRule.compareValues(nv, normalizedValue); 751 if (comparisonResult <= 0) 752 { 753 return ConditionResult.TRUE; 754 } 755 } 756 catch (Exception e) 757 { 758 if (debugEnabled()) 759 { 760 TRACER.debugCaught(DebugLogLevel.ERROR, e); 761 } 762 763 // We couldn't normalize one of the attribute values. If we 764 // can't find a definite match, then we should return 765 // "undefined". 766 result = ConditionResult.UNDEFINED; 767 } 768 } 769 770 return result; 771 } 772 773 774 775 /** 776 * Indicates whether this attribute has any value(s) that are 777 * approximately equal to the provided value. 778 * 779 * @param value The value for which to make the determination. 780 * 781 * @return <CODE>UNDEFINED</CODE> if this attribute does not have 782 * an approximate matching rule, <CODE>TRUE</CODE> if at 783 * least one value is approximately equal to the provided 784 * value, or <CODE>false</CODE> otherwise. 785 */ 786 public ConditionResult approximatelyEqualTo(AttributeValue value) 787 { 788 ApproximateMatchingRule matchingRule = 789 attributeType.getApproximateMatchingRule(); 790 if (matchingRule == null) 791 { 792 return ConditionResult.UNDEFINED; 793 } 794 795 ByteString normalizedValue; 796 try 797 { 798 normalizedValue = matchingRule.normalizeValue(value.getValue()); 799 } 800 catch (Exception e) 801 { 802 if (debugEnabled()) 803 { 804 TRACER.debugCaught(DebugLogLevel.ERROR, e); 805 } 806 807 // We couldn't normalize the provided value. We should return 808 // "undefined". 809 return ConditionResult.UNDEFINED; 810 } 811 812 ConditionResult result = ConditionResult.FALSE; 813 for (AttributeValue v : getValues()) 814 { 815 try 816 { 817 ByteString nv = matchingRule.normalizeValue(v.getValue()); 818 if (matchingRule.approximatelyMatch(nv, normalizedValue)) 819 { 820 return ConditionResult.TRUE; 821 } 822 } 823 catch (Exception e) 824 { 825 if (debugEnabled()) 826 { 827 TRACER.debugCaught(DebugLogLevel.ERROR, e); 828 } 829 830 // We couldn't normalize one of the attribute values. If we 831 // can't find a definite match, then we should return 832 // "undefined". 833 result = ConditionResult.UNDEFINED; 834 } 835 } 836 837 return result; 838 } 839 840 841 842 /** 843 * Indicates whether this is a virtual attribute rather than a real 844 * attribute. 845 * 846 * @return {@code true} if this is a virtual attribute, or 847 * {@code false} if it is a real attribute. 848 */ 849 public boolean isVirtual() 850 { 851 return false; 852 } 853 854 855 856 /** 857 * Creates a duplicate of this attribute that can be modified 858 * without impacting this attribute. 859 * 860 * @return A duplicate of this attribute that can be modified 861 * without impacting this attribute. 862 */ 863 public Attribute duplicate() 864 { 865 return duplicate(false); 866 } 867 868 869 /** 870 * Creates a duplicate of this attribute that can be modified 871 * without impacting this attribute. 872 * 873 * @param omitValues <CODE>true</CODE> if the values should be 874 * omitted. 875 * 876 * @return A duplicate of this attribute that can be modified 877 * without impacting this attribute. 878 */ 879 public Attribute duplicate(boolean omitValues) 880 { 881 LinkedHashSet<String> optionsCopy = 882 new LinkedHashSet<String>(options); 883 884 if (omitValues) 885 { 886 return new Attribute(attributeType, name, optionsCopy, null); 887 } 888 else 889 { 890 LinkedHashSet<AttributeValue> valuesCopy = 891 new LinkedHashSet<AttributeValue>(getValues()); 892 893 return new Attribute(attributeType, name, optionsCopy, 894 valuesCopy); 895 } 896 } 897 898 899 /** 900 * Indicates whether the provided object is an attribute that is 901 * equal to this attribute. It will be considered equal if the 902 * attribute type, set of values, and set of options are equal. 903 * 904 * @param o The object for which to make the determination. 905 * 906 * @return <CODE>true</CODE> if the provided object is an attribute 907 * that is equal to this attribute, or <CODE>false</CODE> 908 * if not. 909 */ 910 public boolean equals(Object o) 911 { 912 if (this == o) 913 { 914 return true; 915 } 916 917 if ((o == null) || (! (o instanceof Attribute))) 918 { 919 return false; 920 } 921 922 Attribute a = (Attribute) o; 923 if (! attributeType.equals(a.attributeType)) 924 { 925 return false; 926 } 927 928 if (getValues().size() != a.getValues().size()) 929 { 930 return false; 931 } 932 933 if (! hasAllValues(a.getValues())) 934 { 935 return false; 936 } 937 938 return optionsEqual(a.options); 939 } 940 941 942 943 /** 944 * Retrieves the hash code for this attribute. It will be 945 * calculated as the sum of the hash code for the attribute type and 946 * all values. 947 * 948 * @return The hash code for this attribute. 949 */ 950 public int hashCode() 951 { 952 int hashCode = attributeType.hashCode(); 953 for (AttributeValue value : getValues()) 954 { 955 hashCode += value.hashCode(); 956 } 957 958 return hashCode; 959 } 960 961 962 963 /** 964 * Retrieves a one-line string representation of this attribute. 965 * 966 * @return A one-line string representation of this attribute. 967 */ 968 public String toString() 969 { 970 StringBuilder buffer = new StringBuilder(); 971 toString(buffer); 972 return buffer.toString(); 973 } 974 975 976 977 /** 978 * Appends a one-line string representation of this attribute to the 979 * provided buffer. 980 * 981 * @param buffer The buffer to which the information should be 982 * appended. 983 */ 984 public void toString(StringBuilder buffer) 985 { 986 buffer.append("Attribute("); 987 buffer.append(name); 988 buffer.append(", {"); 989 990 boolean firstValue = true; 991 for (AttributeValue value : getValues()) 992 { 993 if (! firstValue) 994 { 995 buffer.append(", "); 996 } 997 998 value.toString(buffer); 999 firstValue = false; 1000 } 1001 1002 buffer.append("})"); 1003 } 1004 1005 1006 1007 /** 1008 * Retrieves a string representation of this attribute in LDIF form. 1009 * 1010 * @return A string representation of this attribute in LDIF form. 1011 */ 1012 public String toLDIF() 1013 { 1014 StringBuilder buffer = new StringBuilder(); 1015 toLDIF(buffer); 1016 return buffer.toString(); 1017 } 1018 1019 1020 1021 /** 1022 * Appends a string representation of this attribute in LDIF form to 1023 * the provided buffer. 1024 * 1025 * @param buffer The buffer to which the information should be 1026 * appended. 1027 */ 1028 public void toLDIF(StringBuilder buffer) 1029 { 1030 for (AttributeValue value : getValues()) 1031 { 1032 buffer.append(name); 1033 1034 if (needsBase64Encoding(value.getValueBytes())) 1035 { 1036 buffer.append("::"); 1037 buffer.append(Base64.encode(value.getValueBytes())); 1038 } 1039 else 1040 { 1041 buffer.append(": "); 1042 buffer.append(value.getStringValue()); 1043 } 1044 1045 buffer.append(EOL); 1046 } 1047 } 1048 } 1049