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