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