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