001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.config; 018 019import static org.opends.messages.ConfigMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021import static org.opends.server.util.CollectionUtils.*; 022 023import java.lang.reflect.Array; 024import java.util.ArrayList; 025import java.util.LinkedHashSet; 026import java.util.List; 027 028import javax.management.AttributeList; 029import javax.management.MBeanAttributeInfo; 030import javax.management.MBeanParameterInfo; 031 032import org.forgerock.i18n.LocalizableMessage; 033import org.forgerock.i18n.slf4j.LocalizedLogger; 034import org.forgerock.opendj.ldap.ByteString; 035import org.forgerock.opendj.ldap.schema.Syntax; 036import org.opends.server.core.DirectoryServer; 037import org.opends.server.types.Attribute; 038import org.forgerock.opendj.ldap.DN; 039 040/** 041 * This class defines a DN configuration attribute, which can hold zero or more 042 * DN values. 043 */ 044@org.opends.server.types.PublicAPI( 045 stability=org.opends.server.types.StabilityLevel.VOLATILE, 046 mayInstantiate=true, 047 mayExtend=false, 048 mayInvoke=true) 049public final class DNConfigAttribute 050 extends ConfigAttribute 051{ 052 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 053 054 /** The set of active values for this attribute. */ 055 private List<DN> activeValues; 056 057 /** The set of pending values for this attribute. */ 058 private List<DN> pendingValues; 059 060 061 062 /** 063 * Creates a new DN configuration attribute stub with the provided information 064 * but no values. The values will be set using the 065 * <CODE>setInitialValue</CODE> method. 066 * 067 * @param name The name for this configuration attribute. 068 * @param description The description for this configuration 069 * attribute. 070 * @param isRequired Indicates whether this configuration attribute 071 * is required to have at least one value. 072 * @param isMultiValued Indicates whether this configuration attribute 073 * may have multiple values. 074 * @param requiresAdminAction Indicates whether changes to this 075 * configuration attribute require administrative 076 * action before they will take effect. 077 */ 078 public DNConfigAttribute(String name, LocalizableMessage description, boolean isRequired, 079 boolean isMultiValued, boolean requiresAdminAction) 080 { 081 super(name, description, isRequired, isMultiValued, requiresAdminAction); 082 083 084 activeValues = new ArrayList<>(); 085 pendingValues = activeValues; 086 } 087 088 089 090 /** 091 * Creates a new DN configuration attribute with the provided information. No 092 * validation will be performed on the provided value. 093 * 094 * @param name The name for this configuration attribute. 095 * @param description The description for this configuration 096 * attribute. 097 * @param isRequired Indicates whether this configuration attribute 098 * is required to have at least one value. 099 * @param isMultiValued Indicates whether this configuration attribute 100 * may have multiple values. 101 * @param requiresAdminAction Indicates whether changes to this 102 * configuration attribute require administrative 103 * action before they will take effect. 104 * @param value The value for this DN configuration attribute. 105 */ 106 public DNConfigAttribute(String name, LocalizableMessage description, boolean isRequired, 107 boolean isMultiValued, boolean requiresAdminAction, 108 DN value) 109 { 110 super(name, description, isRequired, isMultiValued, requiresAdminAction, 111 getDNValueSet(value)); 112 113 114 if (value == null) 115 { 116 activeValues = new ArrayList<>(); 117 } 118 else 119 { 120 activeValues = newArrayList(value); 121 } 122 123 pendingValues = activeValues; 124 } 125 126 127 128 /** 129 * Creates a new DN configuration attribute with the provided information. No 130 * validation will be performed on the provided values. 131 * 132 * @param name The name for this configuration attribute. 133 * @param description The description for this configuration 134 * attribute. 135 * @param isRequired Indicates whether this configuration attribute 136 * is required to have at least one value. 137 * @param isMultiValued Indicates whether this configuration attribute 138 * may have multiple values. 139 * @param requiresAdminAction Indicates whether changes to this 140 * configuration attribute require administrative 141 * action before they will take effect. 142 * @param values The set of values for this configuration 143 * attribute. 144 */ 145 public DNConfigAttribute(String name, LocalizableMessage description, boolean isRequired, 146 boolean isMultiValued, boolean requiresAdminAction, 147 List<DN> values) 148 { 149 super(name, description, isRequired, isMultiValued, requiresAdminAction, 150 getDNValueSet(values)); 151 152 activeValues = values != null ? values : new ArrayList<DN>(); 153 pendingValues = activeValues; 154 } 155 156 157 158 /** 159 * Creates a new DN configuration attribute with the provided information. No 160 * validation will be performed on the provided values. 161 * 162 * @param name The name for this configuration attribute. 163 * @param description The description for this configuration 164 * attribute. 165 * @param isRequired Indicates whether this configuration attribute 166 * is required to have at least one value. 167 * @param isMultiValued Indicates whether this configuration attribute 168 * may have multiple values. 169 * @param requiresAdminAction Indicates whether changes to this 170 * configuration attribute require administrative 171 * action before they will take effect. 172 * @param activeValues The set of active values for this 173 * configuration attribute. 174 * @param pendingValues The set of pending values for this 175 * configuration attribute. 176 */ 177 public DNConfigAttribute(String name, LocalizableMessage description, boolean isRequired, 178 boolean isMultiValued, boolean requiresAdminAction, 179 List<DN> activeValues, List<DN> pendingValues) 180 { 181 super(name, description, isRequired, isMultiValued, requiresAdminAction, 182 getDNValueSet(activeValues), pendingValues != null, 183 getDNValueSet(pendingValues)); 184 185 186 if (activeValues == null) 187 { 188 this.activeValues = new ArrayList<>(); 189 } 190 else 191 { 192 this.activeValues = activeValues; 193 } 194 195 if (pendingValues == null) 196 { 197 this.pendingValues = this.activeValues; 198 } 199 else 200 { 201 this.pendingValues = pendingValues; 202 } 203 } 204 205 206 207 /** 208 * Retrieves the name of the data type for this configuration attribute. This 209 * is for informational purposes (e.g., inclusion in method signatures and 210 * other kinds of descriptions) and does not necessarily need to map to an 211 * actual Java type. 212 * 213 * @return The name of the data type for this configuration attribute. 214 */ 215 @Override 216 public String getDataType() 217 { 218 return "DN"; 219 } 220 221 222 223 /** 224 * Retrieves the attribute syntax for this configuration attribute. 225 * 226 * @return The attribute syntax for this configuration attribute. 227 */ 228 @Override 229 public Syntax getSyntax() 230 { 231 return DirectoryServer.getDefaultStringSyntax(); 232 } 233 234 235 236 /** 237 * Retrieves the active value for this configuration attribute as a DN. This 238 * is only valid for single-valued attributes that have a value. 239 * 240 * @return The active value for this configuration attribute as a DN. 241 * 242 * @throws ConfigException If this attribute does not have exactly one 243 * active value. 244 */ 245 public DN activeValue() 246 throws ConfigException 247 { 248 if (activeValues == null || activeValues.isEmpty()) 249 { 250 throw new ConfigException(ERR_CONFIG_ATTR_NO_STRING_VALUE.get(getName())); 251 } 252 if (activeValues.size() > 1) 253 { 254 throw new ConfigException(ERR_CONFIG_ATTR_MULTIPLE_STRING_VALUES.get(getName())); 255 } 256 257 return activeValues.get(0); 258 } 259 260 261 262 /** 263 * Retrieves the set of active values for this configuration attribute. 264 * 265 * @return The set of active values for this configuration attribute. 266 */ 267 public List<DN> activeValues() 268 { 269 return activeValues; 270 } 271 272 273 274 /** 275 * Retrieves the pending value for this configuration attribute as a DN. 276 * This is only valid for single-valued attributes that have a value. If this 277 * attribute does not have any pending values, then the active value will be 278 * returned. 279 * 280 * @return The pending value for this configuration attribute as a DN. 281 * 282 * @throws ConfigException If this attribute does not have exactly one 283 * pending value. 284 */ 285 public DN pendingValue() 286 throws ConfigException 287 { 288 if (! hasPendingValues()) 289 { 290 return activeValue(); 291 } 292 293 if (pendingValues == null || pendingValues.isEmpty()) 294 { 295 throw new ConfigException(ERR_CONFIG_ATTR_NO_STRING_VALUE.get(getName())); 296 } 297 if (pendingValues.size() > 1) 298 { 299 throw new ConfigException(ERR_CONFIG_ATTR_MULTIPLE_STRING_VALUES.get(getName())); 300 } 301 302 return pendingValues.get(0); 303 } 304 305 306 307 /** 308 * Retrieves the set of pending values for this configuration attribute. If 309 * there are no pending values, then the set of active values will be 310 * returned. 311 * 312 * @return The set of pending values for this configuration attribute. 313 */ 314 public List<DN> pendingValues() 315 { 316 if (! hasPendingValues()) 317 { 318 return activeValues; 319 } 320 321 return pendingValues; 322 } 323 324 325 326 /** 327 * Sets the value for this DN configuration attribute. 328 * 329 * @param value The value for this DN configuration attribute. 330 * 331 * @throws ConfigException If the provided value is not acceptable. 332 */ 333 public void setValue(DN value) 334 throws ConfigException 335 { 336 if (value == null) 337 { 338 LocalizableMessage message = ERR_CONFIG_ATTR_DN_NULL.get(getName()); 339 throw new ConfigException(message); 340 } 341 342 if (requiresAdminAction()) 343 { 344 pendingValues = newArrayList(value); 345 setPendingValues(getDNValueSet(value)); 346 } 347 else 348 { 349 activeValues.clear(); 350 activeValues.add(value); 351 pendingValues = activeValues; 352 setActiveValues(getDNValueSet(value)); 353 } 354 } 355 356 357 358 /** 359 * Sets the values for this DN configuration attribute. 360 * 361 * @param values The set of values for this DN configuration attribute. 362 * 363 * @throws ConfigException If the provided value set or any of the 364 * individual values are not acceptable. 365 */ 366 public void setValues(List<DN> values) 367 throws ConfigException 368 { 369 // First check if the set is empty and if that is allowed. 370 if (values == null || values.isEmpty()) 371 { 372 if (isRequired()) 373 { 374 throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(getName())); 375 } 376 377 if (requiresAdminAction()) 378 { 379 setPendingValues(new LinkedHashSet<ByteString>(0)); 380 pendingValues = new ArrayList<>(); 381 } 382 else 383 { 384 setActiveValues(new LinkedHashSet<ByteString>(0)); 385 activeValues.clear(); 386 } 387 } 388 389 390 // Next check if the set contains multiple values and if that is allowed. 391 int numValues = values.size(); 392 if (!isMultiValued() && numValues > 1) 393 { 394 throw new ConfigException(ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(getName())); 395 } 396 397 398 // Iterate through all the provided values, make sure that they are 399 // acceptable, and build the value set. 400 LinkedHashSet<ByteString> valueSet = new LinkedHashSet<>(numValues); 401 for (DN value : values) 402 { 403 if (value == null) 404 { 405 throw new ConfigException(ERR_CONFIG_ATTR_DN_NULL.get(getName())); 406 } 407 408 ByteString attrValue = ByteString.valueOfUtf8(value.toString()); 409 if (valueSet.contains(attrValue)) 410 { 411 throw new ConfigException(ERR_CONFIG_ATTR_ADD_VALUES_ALREADY_EXISTS.get(getName(), value)); 412 } 413 414 valueSet.add(attrValue); 415 } 416 417 418 // Apply this value set to the new active or pending value set. 419 if (requiresAdminAction()) 420 { 421 pendingValues = values; 422 setPendingValues(valueSet); 423 } 424 else 425 { 426 activeValues = values; 427 pendingValues = activeValues; 428 setActiveValues(valueSet); 429 } 430 } 431 432 433 434 /** 435 * Creates the appropriate value set with the provided value. 436 * 437 * @param value The value to use to create the value set. 438 * 439 * @return The constructed value set. 440 */ 441 private static LinkedHashSet<ByteString> getDNValueSet(DN value) 442 { 443 if (value == null) 444 { 445 return new LinkedHashSet<>(0); 446 } 447 return newLinkedHashSet(ByteString.valueOfUtf8(value.toString())); 448 } 449 450 451 452 /** 453 * Creates the appropriate value set with the provided values. 454 * 455 * @param values The values to use to create the value set. 456 * 457 * @return The constructed value set. 458 */ 459 private static LinkedHashSet<ByteString> getDNValueSet(List<DN> values) 460 { 461 if (values == null) 462 { 463 return null; 464 } 465 466 LinkedHashSet<ByteString> valueSet = new LinkedHashSet<>(values.size()); 467 for (DN value : values) 468 { 469 valueSet.add(ByteString.valueOfUtf8(value.toString())); 470 } 471 return valueSet; 472 } 473 474 475 476 /** 477 * Applies the set of pending values, making them the active values for this 478 * configuration attribute. This will not take any action if there are no 479 * pending values. 480 */ 481 @Override 482 public void applyPendingValues() 483 { 484 if (! hasPendingValues()) 485 { 486 return; 487 } 488 489 super.applyPendingValues(); 490 activeValues = pendingValues; 491 } 492 493 494 495 /** 496 * Indicates whether the provided value is acceptable for use in this 497 * attribute. If it is not acceptable, then the reason should be written into 498 * the provided buffer. 499 * 500 * @param value The value for which to make the determination. 501 * @param rejectReason A buffer into which a human-readable reason for the 502 * reject may be written. 503 * 504 * @return <CODE>true</CODE> if the provided value is acceptable for use in 505 * this attribute, or <CODE>false</CODE> if not. 506 */ 507 @Override 508 public boolean valueIsAcceptable(ByteString value, StringBuilder rejectReason) 509 { 510 // Make sure that the value is not null. 511 if (value == null) 512 { 513 rejectReason.append(ERR_CONFIG_ATTR_DN_NULL.get(getName())); 514 return false; 515 } 516 517 518 // Make sure that it can be parsed as a DN. 519 try 520 { 521 DN.valueOf(value.toString()); 522 } 523 catch (Exception e) 524 { 525 logger.traceException(e); 526 527 rejectReason.append(ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(value, getName(), e)); 528 return false; 529 } 530 return true; 531 } 532 533 534 535 /** 536 * Converts the provided set of strings to a corresponding set of attribute 537 * values. 538 * 539 * @param valueStrings The set of strings to be converted into attribute 540 * values. 541 * @param allowFailures Indicates whether the decoding process should allow 542 * any failures in which one or more values could be 543 * decoded but at least one could not. If this is 544 * <CODE>true</CODE> and such a condition is acceptable 545 * for the underlying attribute type, then the returned 546 * set of values should simply not include those 547 * undecodable values. 548 * 549 * @return The set of attribute values converted from the provided strings. 550 * 551 * @throws ConfigException If an unrecoverable problem occurs while 552 * performing the conversion. 553 */ 554 @Override 555 public LinkedHashSet<ByteString> stringsToValues(List<String> valueStrings, boolean allowFailures) 556 throws ConfigException 557 { 558 if (valueStrings == null || valueStrings.isEmpty()) 559 { 560 if (isRequired()) 561 { 562 throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(getName())); 563 } 564 return new LinkedHashSet<>(); 565 } 566 567 568 int numValues = valueStrings.size(); 569 if (!isMultiValued() && numValues > 1) 570 { 571 throw new ConfigException(ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(getName())); 572 } 573 574 575 LinkedHashSet<ByteString> valueSet = new LinkedHashSet<>(numValues); 576 for (String valueString : valueStrings) 577 { 578 if (valueString == null) 579 { 580 reportError(allowFailures, ERR_CONFIG_ATTR_DN_NULL.get(getName())); 581 continue; 582 } 583 584 585 DN dn; 586 try 587 { 588 dn = DN.valueOf(valueString); 589 } 590 catch (Exception e) 591 { 592 logger.traceException(e); 593 594 reportError(allowFailures, ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(valueString, getName(), e)); 595 continue; 596 } 597 598 valueSet.add(ByteString.valueOfUtf8(dn.toString())); 599 } 600 601 // If this method was configured to continue on error, then it is possible 602 // that we ended up with an empty list. Check to see if this is a required 603 // attribute and if so deal with it accordingly. 604 if (isRequired() && valueSet.isEmpty()) 605 { 606 throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(getName())); 607 } 608 609 return valueSet; 610 } 611 612 private void reportError(boolean allowFailures, LocalizableMessage message) throws ConfigException 613 { 614 if (!allowFailures) 615 { 616 throw new ConfigException(message); 617 } 618 logger.error(message); 619 } 620 621 /** 622 * Converts the set of active values for this configuration attribute into a 623 * set of strings that may be stored in the configuration or represented over 624 * protocol. The string representation used by this method should be 625 * compatible with the decoding used by the <CODE>stringsToValues</CODE> 626 * method. 627 * 628 * @return The string representations of the set of active values for this 629 * configuration attribute. 630 */ 631 @Override 632 public List<String> activeValuesToStrings() 633 { 634 ArrayList<String> valueStrings = new ArrayList<>(activeValues.size()); 635 for (DN dn : activeValues) 636 { 637 valueStrings.add(dn.toString()); 638 } 639 640 return valueStrings; 641 } 642 643 644 645 /** 646 * Converts the set of pending values for this configuration attribute into a 647 * set of strings that may be stored in the configuration or represented over 648 * protocol. The string representation used by this method should be 649 * compatible with the decoding used by the <CODE>stringsToValues</CODE> 650 * method. 651 * 652 * @return The string representations of the set of pending values for this 653 * configuration attribute, or <CODE>null</CODE> if there are no 654 * pending values. 655 */ 656 @Override 657 public List<String> pendingValuesToStrings() 658 { 659 if (hasPendingValues()) 660 { 661 ArrayList<String> valueStrings = new ArrayList<>(pendingValues.size()); 662 for (DN dn : pendingValues) 663 { 664 valueStrings.add(dn.toString()); 665 } 666 return valueStrings; 667 } 668 return null; 669 } 670 671 672 673 /** 674 * Retrieves a new configuration attribute of this type that will contain the 675 * values from the provided attribute. 676 * 677 * @param attributeList The list of attributes to use to create the config 678 * attribute. The list must contain either one or two 679 * elements, with both attributes having the same base 680 * name and the only option allowed is ";pending" and 681 * only if this attribute is one that requires admin 682 * action before a change may take effect. 683 * 684 * @return The generated configuration attribute. 685 * 686 * @throws ConfigException If the provided attribute cannot be treated as a 687 * configuration attribute of this type (e.g., if 688 * one or more of the values of the provided 689 * attribute are not suitable for an attribute of 690 * this type, or if this configuration attribute is 691 * single-valued and the provided attribute has 692 * multiple values). 693 */ 694 @Override 695 public ConfigAttribute getConfigAttribute(List<Attribute> attributeList) 696 throws ConfigException 697 { 698 ArrayList<DN> activeValues = null; 699 ArrayList<DN> pendingValues = null; 700 701 for (Attribute a : attributeList) 702 { 703 if (a.hasOptions()) 704 { 705 // This must be the pending value. 706 if (a.hasOption(OPTION_PENDING_VALUES)) 707 { 708 if (pendingValues != null) 709 { 710 // We cannot have multiple pending value sets. 711 LocalizableMessage message = 712 ERR_CONFIG_ATTR_MULTIPLE_PENDING_VALUE_SETS.get(a.getName()); 713 throw new ConfigException(message); 714 } 715 716 717 if (a.isEmpty()) 718 { 719 if (isRequired()) 720 { 721 // This is illegal -- it must have a value. 722 throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(a.getName())); 723 } 724 // This is fine. The pending value set can be empty. 725 pendingValues = new ArrayList<>(0); 726 } 727 else 728 { 729 int numValues = a.size(); 730 if (numValues > 1 && !isMultiValued()) 731 { 732 // This is illegal -- the attribute is single-valued. 733 throw new ConfigException(ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(a.getName())); 734 } 735 736 pendingValues = new ArrayList<>(numValues); 737 for (ByteString v : a) 738 { 739 DN dn; 740 try 741 { 742 dn = DN.valueOf(v.toString()); 743 } 744 catch (Exception e) 745 { 746 logger.traceException(e); 747 748 LocalizableMessage message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(v, getName(), e); 749 throw new ConfigException(message, e); 750 } 751 752 pendingValues.add(dn); 753 } 754 } 755 } 756 else 757 { 758 // This is illegal -- only the pending option is allowed for 759 // configuration attributes. 760 throw new ConfigException( 761 ERR_CONFIG_ATTR_OPTIONS_NOT_ALLOWED.get(a.getName())); 762 } 763 } 764 else 765 { 766 // This must be the active value. 767 if (activeValues!= null) 768 { 769 // We cannot have multiple active value sets. 770 throw new ConfigException( 771 ERR_CONFIG_ATTR_MULTIPLE_ACTIVE_VALUE_SETS.get(a.getName())); 772 } 773 774 775 if (a.isEmpty()) 776 { 777 if (isRequired()) 778 { 779 // This is illegal -- it must have a value. 780 throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(a.getName())); 781 } 782 // This is fine. The active value set can be empty. 783 activeValues = new ArrayList<>(0); 784 } 785 else 786 { 787 int numValues = a.size(); 788 if (numValues > 1 && !isMultiValued()) 789 { 790 // This is illegal -- the attribute is single-valued. 791 throw new ConfigException(ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(a.getName())); 792 } 793 794 activeValues = new ArrayList<>(numValues); 795 for (ByteString v : a) 796 { 797 DN dn; 798 try 799 { 800 dn = DN.valueOf(v.toString()); 801 } 802 catch (Exception e) 803 { 804 logger.traceException(e); 805 806 LocalizableMessage message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(v, getName(), e); 807 throw new ConfigException(message, e); 808 } 809 810 activeValues.add(dn); 811 } 812 } 813 } 814 } 815 816 if (activeValues == null) 817 { 818 // This is not OK. The value set must contain an active value. 819 LocalizableMessage message = ERR_CONFIG_ATTR_NO_ACTIVE_VALUE_SET.get(getName()); 820 throw new ConfigException(message); 821 } 822 823 if (pendingValues == null) 824 { 825 // This is OK. We'll just use the active value set. 826 pendingValues = activeValues; 827 } 828 829 return new DNConfigAttribute(getName(), getDescription(), isRequired(), 830 isMultiValued(), requiresAdminAction(), 831 activeValues, pendingValues); 832 } 833 834 835 836 /** 837 * Retrieves a JMX attribute containing the requested value set for this 838 * configuration attribute (active or pending). 839 * 840 * @param pending indicates if pending or active values are required. 841 * 842 * @return A JMX attribute containing the active value set for this 843 * configuration attribute, or <CODE>null</CODE> if it does not have 844 * any active values. 845 */ 846 private javax.management.Attribute _toJMXAttribute(boolean pending) 847 { 848 List<DN> requestedValues ; 849 String name ; 850 if (pending) 851 { 852 requestedValues = pendingValues ; 853 name = getName() + ";" + OPTION_PENDING_VALUES ; 854 } 855 else 856 { 857 requestedValues = activeValues ; 858 name = getName() ; 859 } 860 861 if (isMultiValued()) 862 { 863 String[] values = new String[requestedValues.size()]; 864 for (int i=0; i < values.length; i++) 865 { 866 values[i] = requestedValues.get(i).toString(); 867 } 868 869 return new javax.management.Attribute(name, values); 870 } 871 else if (!requestedValues.isEmpty()) 872 { 873 DN dn = requestedValues.get(0); 874 return new javax.management.Attribute(name, dn.toString()); 875 } 876 else 877 { 878 return null; 879 } 880 } 881 882 /** 883 * Retrieves a JMX attribute containing the active value set for this 884 * configuration attribute. 885 * 886 * @return A JMX attribute containing the active value set for this 887 * configuration attribute, or <CODE>null</CODE> if it does not have 888 * any active values. 889 */ 890 @Override 891 public javax.management.Attribute toJMXAttribute() 892 { 893 return _toJMXAttribute(false) ; 894 } 895 896 /** 897 * Retrieves a JMX attribute containing the pending value set for this 898 * configuration attribute. 899 * 900 * @return A JMX attribute containing the pending value set for this 901 * configuration attribute. 902 */ 903 @Override 904 public javax.management.Attribute toJMXAttributePending() 905 { 906 return _toJMXAttribute(true) ; 907 } 908 909 /** 910 * Adds information about this configuration attribute to the provided JMX 911 * attribute list. If this configuration attribute requires administrative 912 * action before changes take effect and it has a set of pending values, then 913 * two attributes should be added to the list -- one for the active value 914 * and one for the pending value. The pending value should be named with 915 * the pending option. 916 * 917 * @param attributeList The attribute list to which the JMX attribute(s) 918 * should be added. 919 */ 920 @Override 921 public void toJMXAttribute(AttributeList attributeList) 922 { 923 if (!activeValues.isEmpty()) 924 { 925 if (isMultiValued()) 926 { 927 String[] values = new String[activeValues.size()]; 928 for (int i=0; i < values.length; i++) 929 { 930 values[i] = activeValues.get(i).toString(); 931 } 932 933 attributeList.add(new javax.management.Attribute(getName(), values)); 934 } 935 else 936 { 937 attributeList.add(new javax.management.Attribute(getName(), 938 activeValues.get(0).toString())); 939 } 940 } 941 else 942 { 943 if (isMultiValued()) 944 { 945 attributeList.add(new javax.management.Attribute(getName(), 946 new String[0])); 947 } 948 else 949 { 950 attributeList.add(new javax.management.Attribute(getName(), null)); 951 } 952 } 953 954 955 if (requiresAdminAction() && pendingValues != null && pendingValues != activeValues) 956 { 957 String name = getName() + ";" + OPTION_PENDING_VALUES; 958 959 if (isMultiValued()) 960 { 961 String[] values = new String[pendingValues.size()]; 962 for (int i=0; i < values.length; i++) 963 { 964 values[i] = pendingValues.get(i).toString(); 965 } 966 967 attributeList.add(new javax.management.Attribute(name, values)); 968 } 969 else if (! pendingValues.isEmpty()) 970 { 971 attributeList.add(new javax.management.Attribute(name, 972 pendingValues.get(0).toString())); 973 } 974 } 975 } 976 977 978 979 /** 980 * Adds information about this configuration attribute to the provided list in 981 * the form of a JMX <CODE>MBeanAttributeInfo</CODE> object. If this 982 * configuration attribute requires administrative action before changes take 983 * effect and it has a set of pending values, then two attribute info objects 984 * should be added to the list -- one for the active value (which should be 985 * read-write) and one for the pending value (which should be read-only). The 986 * pending value should be named with the pending option. 987 * 988 * @param attributeInfoList The list to which the attribute information 989 * should be added. 990 */ 991 @Override 992 public void toJMXAttributeInfo(List<MBeanAttributeInfo> attributeInfoList) 993 { 994 attributeInfoList.add(new MBeanAttributeInfo(getName(), getType(), 995 String.valueOf(getDescription()), true, true, false)); 996 997 if (requiresAdminAction()) 998 { 999 String name = getName() + ";" + OPTION_PENDING_VALUES; 1000 attributeInfoList.add(new MBeanAttributeInfo(name, getType(), 1001 String.valueOf(getDescription()), true, false, false)); 1002 } 1003 } 1004 1005 1006 1007 /** 1008 * Retrieves a JMX <CODE>MBeanParameterInfo</CODE> object that describes this 1009 * configuration attribute. 1010 * 1011 * @return A JMX <CODE>MBeanParameterInfo</CODE> object that describes this 1012 * configuration attribute. 1013 */ 1014 @Override 1015 public MBeanParameterInfo toJMXParameterInfo() 1016 { 1017 return new MBeanParameterInfo(getName(), getType(), String.valueOf(getDescription())); 1018 } 1019 1020 private String getType() 1021 { 1022 return isMultiValued() ? JMX_TYPE_STRING_ARRAY : String.class.getName(); 1023 } 1024 1025 /** 1026 * Attempts to set the value of this configuration attribute based on the 1027 * information in the provided JMX attribute. 1028 * 1029 * @param jmxAttribute The JMX attribute to use to attempt to set the value 1030 * of this configuration attribute. 1031 * 1032 * @throws ConfigException If the provided JMX attribute does not have an 1033 * acceptable value for this configuration 1034 * attribute. 1035 */ 1036 @Override 1037 public void setValue(javax.management.Attribute jmxAttribute) 1038 throws ConfigException 1039 { 1040 Object value = jmxAttribute.getValue(); 1041 if (value == null) 1042 { 1043 throw new ConfigException(ERR_CONFIG_ATTR_DN_NULL.get(getName())); 1044 } 1045 else if (value instanceof DN) 1046 { 1047 setValue((DN) value); 1048 } 1049 if (value instanceof String) 1050 { 1051 DN dn; 1052 try 1053 { 1054 dn = DN.valueOf((String) value); 1055 } 1056 catch (Exception e) 1057 { 1058 logger.traceException(e); 1059 1060 LocalizableMessage message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(value, getName(), e); 1061 throw new ConfigException(message, e); 1062 } 1063 1064 setValue(dn); 1065 } 1066 else if (value.getClass().isArray()) 1067 { 1068 String componentType = value.getClass().getComponentType().getName(); 1069 int length = Array.getLength(value); 1070 1071 if (componentType.equals(DN.class.getName())) 1072 { 1073 ArrayList<DN> dnList = new ArrayList<>(length); 1074 for (int i=0; i < length; i++) 1075 { 1076 dnList.add((DN) Array.get(value, i)); 1077 } 1078 1079 setValues(dnList); 1080 } 1081 else if (componentType.equals(String.class.getName())) 1082 { 1083 try 1084 { 1085 ArrayList<DN> values = new ArrayList<>(length); 1086 for (int i=0; i < length; i++) 1087 { 1088 String valueStr = (String) Array.get(value, i); 1089 1090 DN dn; 1091 try 1092 { 1093 dn = DN.valueOf(valueStr); 1094 } 1095 catch (Exception e) 1096 { 1097 logger.traceException(e); 1098 1099 LocalizableMessage message = ERR_CONFIG_ATTR_DN_CANNOT_PARSE.get(valueStr, getName(), e); 1100 throw new ConfigException(message, e); 1101 } 1102 1103 values.add(dn); 1104 } 1105 1106 setValues(values); 1107 } 1108 catch (ConfigException ce) 1109 { 1110 logger.traceException(ce); 1111 1112 throw ce; 1113 } 1114 catch (Exception e) 1115 { 1116 logger.traceException(e); 1117 1118 LocalizableMessage message = ERR_CONFIG_ATTR_INVALID_DN_VALUE.get( 1119 getName(), value, e); 1120 throw new ConfigException(message, e); 1121 } 1122 } 1123 else 1124 { 1125 LocalizableMessage message = 1126 ERR_CONFIG_ATTR_DN_INVALID_ARRAY_TYPE.get(jmxAttribute, componentType); 1127 throw new ConfigException(message); 1128 } 1129 } 1130 else 1131 { 1132 throw new ConfigException(ERR_CONFIG_ATTR_DN_INVALID_TYPE.get( 1133 value, getName(), value.getClass().getName())); 1134 } 1135 } 1136 1137 1138 1139 /** 1140 * Creates a duplicate of this configuration attribute. 1141 * 1142 * @return A duplicate of this configuration attribute. 1143 */ 1144 @Override 1145 public ConfigAttribute duplicate() 1146 { 1147 return new DNConfigAttribute(getName(), getDescription(), isRequired(), 1148 isMultiValued(), requiresAdminAction(), 1149 activeValues, pendingValues); 1150 } 1151}