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