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.util.ArrayList; 033 import java.util.Iterator; 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 046 import static org.opends.server.config.ConfigConstants.*; 047 import static org.opends.messages.ConfigMessages.*; 048 import static org.opends.server.util.ServerConstants.*; 049 050 051 052 /** 053 * This class defines a Boolean configuration attribute, which can hold a single 054 * Boolean value of <CODE>true</CODE> or <CODE>false</CODE>. Boolean 055 * configuration attributes will always be required and will never be 056 * multivalued. 057 */ 058 @org.opends.server.types.PublicAPI( 059 stability=org.opends.server.types.StabilityLevel.VOLATILE, 060 mayInstantiate=true, 061 mayExtend=false, 062 mayInvoke=true) 063 public final class BooleanConfigAttribute 064 extends ConfigAttribute 065 { 066 // The active value for this attribute. 067 private boolean activeValue; 068 069 // The pending value for this attribute. 070 private boolean pendingValue; 071 072 073 074 /** 075 * Creates a new Boolean configuration attribute stub with the provided 076 * information but no values. The values will be set using the 077 * <CODE>setInitialValue</CODE> method. 078 * 079 * @param name The name for this configuration attribute. 080 * @param description The description for this configuration 081 * attribute. 082 * @param requiresAdminAction Indicates whether changes to this 083 * configuration attribute require administrative 084 * action before they will take effect. 085 */ 086 public BooleanConfigAttribute(String name, Message description, 087 boolean requiresAdminAction) 088 { 089 super(name, description, true, false, requiresAdminAction); 090 091 } 092 093 094 095 /** 096 * Creates a new Boolean configuration attribute with the provided 097 * information. 098 * 099 * @param name The name for this configuration attribute. 100 * @param description The description for this configuration 101 * attribute. 102 * @param requiresAdminAction Indicates whether changes to this 103 * configuration attribute require administrative 104 * action before they will take effect. 105 * @param value The value for this Boolean configuration 106 * attribute. 107 */ 108 public BooleanConfigAttribute(String name, Message description, 109 boolean requiresAdminAction, 110 boolean value) 111 { 112 super(name, description, true, false, requiresAdminAction, 113 getValueSet(value)); 114 115 activeValue = value; 116 pendingValue = value; 117 } 118 119 120 121 /** 122 * Creates a new Boolean configuration attribute with the provided 123 * information. 124 * 125 * @param name The name for this configuration attribute. 126 * @param description The description for this configuration 127 * attribute. 128 * @param requiresAdminAction Indicates whether changes to this 129 * configuration attribute require administrative 130 * action before they will take effect. 131 * @param activeValue The active value for this Boolean 132 * configuration attribute. 133 * @param pendingValue The pending value for this Boolean 134 * configuration attribute. 135 */ 136 public BooleanConfigAttribute(String name, Message description, 137 boolean requiresAdminAction, 138 boolean activeValue, boolean pendingValue) 139 { 140 super(name, description, true, false, requiresAdminAction, 141 getValueSet(activeValue), true, getValueSet(pendingValue)); 142 143 144 this.activeValue = activeValue; 145 this.pendingValue = pendingValue; 146 } 147 148 149 150 /** 151 * Retrieves the name of the data type for this configuration attribute. This 152 * is for informational purposes (e.g., inclusion in method signatures and 153 * other kinds of descriptions) and does not necessarily need to map to an 154 * actual Java type. 155 * 156 * @return The name of the data type for this configuration attribute. 157 */ 158 public String getDataType() 159 { 160 return "Boolean"; 161 } 162 163 164 165 /** 166 * Retrieves the attribute syntax for this configuration attribute. 167 * 168 * @return The attribute syntax for this configuration attribute. 169 */ 170 public AttributeSyntax getSyntax() 171 { 172 return DirectoryServer.getDefaultBooleanSyntax(); 173 } 174 175 176 177 /** 178 * Retrieves the active boolean value for this configuration attribute. 179 * 180 * @return The active boolean value for this configuration attribute. 181 */ 182 public boolean activeValue() 183 { 184 return activeValue; 185 } 186 187 188 189 /** 190 * Retrieves the pending boolean value for this configuration attribute. If 191 * there is no pending value, then the active value will be returned. 192 * 193 * @return The pending boolean value for this configuration attribute. 194 */ 195 public boolean pendingValue() 196 { 197 if (hasPendingValues()) 198 { 199 return pendingValue; 200 } 201 else 202 { 203 return activeValue; 204 } 205 } 206 207 208 209 /** 210 * Specifies the boolean value for this configuration attribute. 211 * 212 * @param booleanValue The boolean value for this configuration attribute. 213 */ 214 public void setValue(boolean booleanValue) 215 { 216 if (requiresAdminAction()) 217 { 218 pendingValue = booleanValue; 219 setPendingValues(getValueSet(booleanValue)); 220 } 221 else 222 { 223 activeValue = booleanValue; 224 setActiveValues(getValueSet(booleanValue)); 225 } 226 } 227 228 229 230 /** 231 * Creates the appropriate value set with the provided value. 232 * 233 * @param booleanValue The boolean value to use to create the value set. 234 * 235 * @return The value set constructed from the provided value. 236 */ 237 private static LinkedHashSet<AttributeValue> getValueSet(boolean booleanValue) 238 { 239 LinkedHashSet<AttributeValue> valueSet = 240 new LinkedHashSet<AttributeValue>(1); 241 if (booleanValue) 242 { 243 valueSet.add(new AttributeValue(new ASN1OctetString(CONFIG_VALUE_TRUE), 244 new ASN1OctetString(CONFIG_VALUE_TRUE))); 245 } 246 else 247 { 248 valueSet.add(new AttributeValue(new ASN1OctetString(CONFIG_VALUE_FALSE), 249 new ASN1OctetString(CONFIG_VALUE_FALSE))); 250 } 251 252 return valueSet; 253 } 254 255 256 257 /** 258 * Applies the set of pending values, making them the active values for this 259 * configuration attribute. This will not take any action if there are no 260 * pending values. 261 */ 262 public void applyPendingValues() 263 { 264 if (! hasPendingValues()) 265 { 266 return; 267 } 268 269 super.applyPendingValues(); 270 activeValue = pendingValue; 271 } 272 273 274 275 /** 276 * Indicates whether the provided value is acceptable for use in this 277 * attribute. If it is not acceptable, then the reason should be written into 278 * the provided buffer. 279 * 280 * @param value The value for which to make the determination. 281 * @param rejectReason A buffer into which a human-readable reason for the 282 * reject may be written. 283 * 284 * @return <CODE>true</CODE> if the provided value is acceptable for use in 285 * this attribute, or <CODE>false</CODE> if not. 286 */ 287 public boolean valueIsAcceptable(AttributeValue value, 288 StringBuilder rejectReason) 289 { 290 String stringValue = value.getStringValue(); 291 if (stringValue.equalsIgnoreCase(CONFIG_VALUE_TRUE) || 292 stringValue.equalsIgnoreCase(CONFIG_VALUE_FALSE)) 293 { 294 return true; 295 } 296 297 rejectReason.append(ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get( 298 getName(), stringValue)); 299 return false; 300 } 301 302 303 304 /** 305 * Converts the provided set of strings to a corresponding set of attribute 306 * values. 307 * 308 * @param valueStrings The set of strings to be converted into attribute 309 * values. 310 * @param allowFailures Indicates whether the decoding process should allow 311 * any failures in which one or more values could be 312 * decoded but at least one could not. If this is 313 * <CODE>true</CODE> and such a condition is acceptable 314 * for the underlying attribute type, then the returned 315 * set of values should simply not include those 316 * undecodable values. 317 * 318 * @return The set of attribute values converted from the provided strings. 319 * 320 * @throws ConfigException If an unrecoverable problem occurs while 321 * performing the conversion. 322 */ 323 public LinkedHashSet<AttributeValue> 324 stringsToValues(List<String> valueStrings, 325 boolean allowFailures) 326 throws ConfigException 327 { 328 if ((valueStrings == null) || valueStrings.isEmpty()) 329 { 330 Message message = ERR_CONFIG_ATTR_IS_REQUIRED.get(getName()); 331 throw new ConfigException(message); 332 } 333 334 335 Iterator<String> iterator = valueStrings.iterator(); 336 String valueString = iterator.next().toLowerCase(); 337 if (iterator.hasNext()) 338 { 339 Message message = ERR_CONFIG_ATTR_IS_REQUIRED.get(getName()); 340 throw new ConfigException(message); 341 } 342 343 if (valueString.equals("true") || valueString.equals("yes") || 344 valueString.equals("on") || valueString.equals("1")) 345 { 346 return getValueSet(true); 347 } 348 else if (valueString.equals("false") || valueString.equals("no") || 349 valueString.equals("off") || valueString.equals("0")) 350 { 351 return getValueSet(false); 352 } 353 else 354 { 355 Message message = 356 ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get(getName(), valueString); 357 throw new ConfigException(message); 358 } 359 } 360 361 362 363 /** 364 * Converts the set of active values for this configuration attribute into a 365 * set of strings that may be stored in the configuration or represented over 366 * protocol. The string representation used by this method should be 367 * compatible with the decoding used by the <CODE>stringsToValues</CODE> 368 * method. 369 * 370 * @return The string representations of the set of active values for this 371 * configuration attribute. 372 */ 373 public List<String> activeValuesToStrings() 374 { 375 ArrayList<String> valueStrings = new ArrayList<String>(1); 376 valueStrings.add(String.valueOf(activeValue)); 377 378 return valueStrings; 379 } 380 381 382 383 /** 384 * Converts the set of pending values for this configuration attribute into a 385 * set of strings that may be stored in the configuration or represented over 386 * protocol. The string representation used by this method should be 387 * compatible with the decoding used by the <CODE>stringsToValues</CODE> 388 * method. 389 * 390 * @return The string representations of the set of pending values for this 391 * configuration attribute, or <CODE>null</CODE> if there are no 392 * pending values. 393 */ 394 public List<String> pendingValuesToStrings() 395 { 396 if (hasPendingValues()) 397 { 398 ArrayList<String> valueStrings = new ArrayList<String>(1); 399 valueStrings.add(String.valueOf(pendingValue)); 400 401 return valueStrings; 402 } 403 else 404 { 405 return null; 406 } 407 } 408 409 410 411 /** 412 * Retrieves a new configuration attribute of this type that will contain the 413 * values from the provided attribute. 414 * 415 * @param attributeList The list of attributes to use to create the config 416 * attribute. The list must contain either one or two 417 * elements, with both attributes having the same base 418 * name and the only option allowed is ";pending" and 419 * only if this attribute is one that requires admin 420 * action before a change may take effect. 421 * 422 * @return The generated configuration attribute. 423 * 424 * @throws ConfigException If the provided attribute cannot be treated as a 425 * configuration attribute of this type (e.g., if 426 * one or more of the values of the provided 427 * attribute are not suitable for an attribute of 428 * this type, or if this configuration attribute is 429 * single-valued and the provided attribute has 430 * multiple values). 431 */ 432 public ConfigAttribute getConfigAttribute(List<Attribute> attributeList) 433 throws ConfigException 434 { 435 boolean activeValue = false; 436 boolean pendingValue = false; 437 boolean activeValueSet = false; 438 boolean pendingValueSet = false; 439 440 for (Attribute a : attributeList) 441 { 442 if (a.hasOptions()) 443 { 444 // This must be the pending value. 445 if (a.hasOption(OPTION_PENDING_VALUES)) 446 { 447 if (pendingValueSet) 448 { 449 // We cannot have multiple pending values. 450 Message message = 451 ERR_CONFIG_ATTR_MULTIPLE_PENDING_VALUE_SETS.get(a.getName()); 452 throw new ConfigException(message); 453 } 454 455 456 LinkedHashSet<AttributeValue> values = a.getValues(); 457 if (values.isEmpty()) 458 { 459 // This is illegal -- it must have a value. 460 Message message = ERR_CONFIG_ATTR_IS_REQUIRED.get(a.getName()); 461 throw new ConfigException(message); 462 } 463 else 464 { 465 // Get the value and parse it as a Boolean. 466 Iterator<AttributeValue> iterator = values.iterator(); 467 String valueString = iterator.next().getStringValue().toLowerCase(); 468 469 if (valueString.equals("true") || valueString.equals("yes") || 470 valueString.equals("on") || valueString.equals("1")) 471 { 472 pendingValue = true; 473 pendingValueSet = true; 474 } 475 else if (valueString.equals("false") || valueString.equals("no") || 476 valueString.equals("off") || valueString.equals("0")) 477 { 478 pendingValue = false; 479 pendingValueSet = true; 480 } 481 else 482 { 483 // This is an illegal value. 484 Message message = ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get( 485 getName(), valueString); 486 throw new ConfigException(message); 487 } 488 489 if (iterator.hasNext()) 490 { 491 // This is illegal -- it must be single-valued. 492 Message message = 493 ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(a.getName()); 494 throw new ConfigException(message); 495 } 496 } 497 } 498 else 499 { 500 // This is illegal -- only the pending option is allowed for 501 // configuration attributes. 502 Message message = 503 ERR_CONFIG_ATTR_OPTIONS_NOT_ALLOWED.get(a.getName()); 504 throw new ConfigException(message); 505 } 506 } 507 else 508 { 509 // This must be the active value. 510 if (activeValueSet) 511 { 512 // We cannot have multiple active values. 513 Message message = 514 ERR_CONFIG_ATTR_MULTIPLE_ACTIVE_VALUE_SETS.get(a.getName()); 515 throw new ConfigException(message); 516 } 517 518 519 LinkedHashSet<AttributeValue> values = a.getValues(); 520 if (values.isEmpty()) 521 { 522 // This is illegal -- it must have a value. 523 Message message = ERR_CONFIG_ATTR_IS_REQUIRED.get(a.getName()); 524 throw new ConfigException(message); 525 } 526 else 527 { 528 // Get the value and parse it as a Boolean. 529 Iterator<AttributeValue> iterator = values.iterator(); 530 String valueString = iterator.next().getStringValue().toLowerCase(); 531 532 if (valueString.equals("true") || valueString.equals("yes") || 533 valueString.equals("on") || valueString.equals("1")) 534 { 535 activeValue = true; 536 activeValueSet = true; 537 } 538 else if (valueString.equals("false") || valueString.equals("no") || 539 valueString.equals("off") || valueString.equals("0")) 540 { 541 activeValue = false; 542 activeValueSet = true; 543 } 544 else 545 { 546 // This is an illegal value. 547 Message message = ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get( 548 getName(), valueString); 549 throw new ConfigException(message); 550 } 551 552 if (iterator.hasNext()) 553 { 554 // This is illegal -- it must be single-valued. 555 Message message = 556 ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(a.getName()); 557 throw new ConfigException(message); 558 } 559 } 560 } 561 } 562 563 if (! activeValueSet) 564 { 565 // This is not OK. The value set must contain an active value. 566 Message message = ERR_CONFIG_ATTR_NO_ACTIVE_VALUE_SET.get(getName()); 567 throw new ConfigException(message); 568 } 569 570 if (pendingValueSet) 571 { 572 return new BooleanConfigAttribute(getName(), getDescription(), 573 requiresAdminAction(), activeValue, 574 pendingValue); 575 } 576 else 577 { 578 return new BooleanConfigAttribute(getName(), getDescription(), 579 requiresAdminAction(), activeValue); 580 } 581 } 582 583 584 585 /** 586 * Retrieves a JMX attribute containing the active value set for this 587 * configuration attribute. 588 * 589 * @return A JMX attribute containing the active value set for this 590 * configuration attribute, or <CODE>null</CODE> if it does not have 591 * any active values. 592 */ 593 public javax.management.Attribute toJMXAttribute() 594 { 595 return new javax.management.Attribute(getName(), activeValue); 596 } 597 598 /** 599 * Retrieves a JMX attribute containing the pending value set for this 600 * configuration attribute. 601 * 602 * @return A JMX attribute containing the pending value set for this 603 * configuration attribute. 604 */ 605 public javax.management.Attribute toJMXAttributePending() 606 { 607 return new javax.management.Attribute(getName() + ";" 608 + OPTION_PENDING_VALUES, pendingValue); 609 } 610 611 612 613 /** 614 * Adds information about this configuration attribute to the provided JMX 615 * attribute list. If this configuration attribute requires administrative 616 * action before changes take effect and it has a set of pending values, then 617 * two attributes should be added to the list -- one for the active value 618 * and one for the pending value. The pending value should be named with 619 * the pending option. 620 * 621 * @param attributeList The attribute list to which the JMX attribute(s) 622 * should be added. 623 */ 624 public void toJMXAttribute(AttributeList attributeList) 625 { 626 attributeList.add(new javax.management.Attribute(getName(), activeValue)); 627 628 if (requiresAdminAction() && (pendingValue != activeValue)) 629 { 630 String name = getName() + ";" + OPTION_PENDING_VALUES; 631 attributeList.add(new javax.management.Attribute(name, pendingValue)); 632 } 633 } 634 635 636 637 /** 638 * Adds information about this configuration attribute to the provided list in 639 * the form of a JMX <CODE>MBeanAttributeInfo</CODE> object. If this 640 * configuration attribute requires administrative action before changes take 641 * effect and it has a set of pending values, then two attribute info objects 642 * should be added to the list -- one for the active value (which should be 643 * read-write) and one for the pending value (which should be read-only). The 644 * pending value should be named with the pending option. 645 * 646 * @param attributeInfoList The list to which the attribute information 647 * should be added. 648 */ 649 public void toJMXAttributeInfo(List<MBeanAttributeInfo> attributeInfoList) 650 { 651 attributeInfoList.add(new MBeanAttributeInfo(getName(), 652 Boolean.class.getName(), 653 String.valueOf( 654 getDescription()), 655 true, true, false)); 656 657 if (requiresAdminAction()) 658 { 659 String name = getName() + ";" + OPTION_PENDING_VALUES; 660 attributeInfoList.add(new MBeanAttributeInfo(name, 661 Boolean.class.getName(), 662 String.valueOf( 663 getDescription()), 664 true, false, false)); 665 } 666 } 667 668 669 670 /** 671 * Retrieves a JMX <CODE>MBeanParameterInfo</CODE> object that describes this 672 * configuration attribute. 673 * 674 * @return A JMX <CODE>MBeanParameterInfo</CODE> object that describes this 675 * configuration attribute. 676 */ 677 public MBeanParameterInfo toJMXParameterInfo() 678 { 679 return new MBeanParameterInfo(getName(), Boolean.TYPE.getName(), 680 String.valueOf(getDescription())); 681 } 682 683 684 685 /** 686 * Attempts to set the value of this configuration attribute based on the 687 * information in the provided JMX attribute. 688 * 689 * @param jmxAttribute The JMX attribute to use to attempt to set the value 690 * of this configuration attribute. 691 * 692 * @throws ConfigException If the provided JMX attribute does not have an 693 * acceptable value for this configuration 694 * attribute. 695 */ 696 public void setValue(javax.management.Attribute jmxAttribute) 697 throws ConfigException 698 { 699 Object value = jmxAttribute.getValue(); 700 if (value instanceof Boolean) 701 { 702 setValue(((Boolean) value).booleanValue()); 703 } 704 else if (value instanceof String) 705 { 706 String stringValue = ((String) value).toLowerCase(); 707 if (stringValue.equals("true") || stringValue.equals("yes") || 708 stringValue.equals("on") || stringValue.equals("1")) 709 { 710 setValue(true); 711 } 712 else if (stringValue.equals("false") || stringValue.equals("no") || 713 stringValue.equals("off") || stringValue.equals("0")) 714 { 715 setValue(false); 716 } 717 else 718 { 719 Message message = 720 ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get(getName(), stringValue); 721 throw new ConfigException(message); 722 } 723 } 724 else 725 { 726 Message message = ERR_CONFIG_ATTR_INVALID_BOOLEAN_VALUE.get( 727 getName(), value.getClass().getName() + ":" + 728 String.valueOf(value)); 729 throw new ConfigException(message); 730 } 731 } 732 733 734 735 /** 736 * Creates a duplicate of this configuration attribute. 737 * 738 * @return A duplicate of this configuration attribute. 739 */ 740 public ConfigAttribute duplicate() 741 { 742 return new BooleanConfigAttribute(getName(), getDescription(), 743 requiresAdminAction(), activeValue, 744 pendingValue); 745 } 746 } 747