001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2008 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2015 ForgeRock AS.
016 */
017package org.opends.server.config;
018
019import static org.opends.messages.ConfigMessages.*;
020
021import java.util.Iterator;
022import java.util.LinkedHashSet;
023import java.util.List;
024
025import javax.management.AttributeList;
026import javax.management.MBeanAttributeInfo;
027import javax.management.MBeanParameterInfo;
028
029import org.forgerock.i18n.LocalizableMessage;
030import org.forgerock.opendj.ldap.ByteString;
031import org.forgerock.opendj.ldap.schema.Syntax;
032import org.opends.server.types.Attribute;
033
034/**
035 * This class defines a configuration attribute, which can hold zero or more
036 * values associated with a configurable property within the Directory Server.
037 * Subclasses should define and enforce actual data types.
038 */
039@org.opends.server.types.PublicAPI(
040     stability=org.opends.server.types.StabilityLevel.VOLATILE,
041     mayInstantiate=true,
042     mayExtend=true,
043     mayInvoke=true)
044public abstract class ConfigAttribute
045{
046  /**
047   * Indicates whether this configuration attribute has pending changes that
048   * will be applied after appropriate administrative action has been performed.
049   */
050  private boolean hasPendingValues;
051
052  /** Indicates whether this configuration attribute may have multiple values. */
053  private boolean isMultiValued;
054
055  /** Indicates whether this configuration attribute is required to have a value. */
056  private boolean isRequired;
057
058  /**
059   * Indicates whether changes to this attribute require administrative action
060   * before they will take effect.
061   */
062  private boolean requiresAdminAction;
063
064  /**
065   * The value or set of values that are currently in effect for this
066   * configuration attribute.
067   */
068  private LinkedHashSet<ByteString> activeValues;
069
070  /**
071   * The value or set of values that will be in effect once the appropriate
072   * administrative action has been taken.
073   */
074  private LinkedHashSet<ByteString> pendingValues;
075
076  /** The description for this configuration attribute. */
077  private LocalizableMessage description;
078
079  /** The name for this configuration attribute. */
080  private String name;
081
082
083
084  /**
085   * Creates a new configuration attribute stub with the provided information
086   * but no values.  The values will be set using the
087   * <CODE>setInitialValue</CODE> method.
088   *
089   * @param  name                 The name for this configuration attribute.
090   * @param  description          The description for this configuration
091   *                              attribute.
092   * @param  isRequired           Indicates whether this configuration attribute
093   *                              is required to have at least one value.
094   * @param  isMultiValued        Indicates whether this configuration attribute
095   *                              may have multiple values.
096   * @param  requiresAdminAction  Indicates whether changes to this
097   *                              configuration attribute require administrative
098   *                              action before they will take effect.
099   */
100  protected ConfigAttribute(String name, LocalizableMessage description,
101                            boolean isRequired, boolean isMultiValued,
102                            boolean requiresAdminAction)
103  {
104    this.name                = name;
105    this.description         = description;
106    this.isRequired          = isRequired;
107    this.isMultiValued       = isMultiValued;
108    this.requiresAdminAction = requiresAdminAction;
109
110    hasPendingValues = false;
111    activeValues     = new LinkedHashSet<>();
112    pendingValues    = activeValues;
113  }
114
115
116
117  /**
118   * Creates a new configuration attribute with the provided information.
119   *
120   * @param  name                 The name for this configuration attribute.
121   * @param  description          The description for this configuration
122   *                              attribute.
123   * @param  isRequired           Indicates whether this configuration attribute
124   *                              is required to have at least one value.
125   * @param  isMultiValued        Indicates whether this configuration attribute
126   *                              may have multiple values.
127   * @param  requiresAdminAction  Indicates whether changes to this
128   *                              configuration attribute require administrative
129   *                              action before they will take effect.
130   * @param  activeValues         The set of values for this attribute that are
131   *                              currently active.
132   */
133  protected ConfigAttribute(String name, LocalizableMessage description,
134                            boolean isRequired, boolean isMultiValued,
135                            boolean requiresAdminAction,
136                            LinkedHashSet<ByteString> activeValues)
137  {
138    this.name                = name;
139    this.description         = description;
140    this.isRequired          = isRequired;
141    this.isMultiValued       = isMultiValued;
142    this.requiresAdminAction = requiresAdminAction;
143    this.hasPendingValues    = false;
144
145    this.activeValues = notNull(activeValues);
146    this.pendingValues = this.activeValues;
147  }
148
149
150
151  /**
152   * Creates a new configuration attribute with the provided information.
153   *
154   * @param  name                 The name for this configuration attribute.
155   * @param  description          The description for this configuration
156   *                              attribute.
157   * @param  isRequired           Indicates whether this configuration attribute
158   *                              is required to have at least one value.
159   * @param  isMultiValued        Indicates whether this configuration attribute
160   *                              may have multiple values.
161   * @param  requiresAdminAction  Indicates whether changes to this
162   *                              configuration attribute require administrative
163   *                              action before they will take effect.
164   * @param  activeValues         The set of values for this attribute that are
165   *                              currently active.
166   * @param  hasPendingValues     Indicates whether this attribute has any
167   *                              pending values that will take effect after
168   *                              appropriate administrative action.
169   * @param  pendingValues        The set of values for this attribute that will
170   *                              be in effect after the appropriate
171   *                              administrative action is taken.  This may be
172   *                              <CODE>null</CODE> if changes will take effect
173   *                              immediately.
174   */
175  protected ConfigAttribute(String name, LocalizableMessage description,
176                            boolean isRequired, boolean isMultiValued,
177                            boolean requiresAdminAction,
178                            LinkedHashSet<ByteString> activeValues,
179                            boolean hasPendingValues,
180                            LinkedHashSet<ByteString> pendingValues)
181  {
182    this.name                = name;
183    this.description         = description;
184    this.isRequired          = isRequired;
185    this.isMultiValued       = isMultiValued;
186    this.requiresAdminAction = requiresAdminAction;
187    this.hasPendingValues    = hasPendingValues;
188
189    this.activeValues = notNull(activeValues);
190
191    if (!hasPendingValues)
192    {
193      this.pendingValues = this.activeValues;
194    }
195    else
196    {
197      this.pendingValues = notNull(pendingValues);
198    }
199  }
200
201
202
203  /**
204   * Retrieves the name for this configuration attribute.
205   *
206   * @return  The name for this configuration attribute.
207   */
208  public String getName()
209  {
210    return name;
211  }
212
213
214
215  /**
216   * Retrieves the description for this configuration attribute.
217   *
218   * @return  The description for this configuration attribute, or
219   *          <CODE>null</CODE> if there is no description.
220   */
221  public LocalizableMessage getDescription()
222  {
223    return description;
224  }
225
226
227
228  /**
229   * Retrieves the name of the data type for this configuration attribute.  This
230   * is for informational purposes (e.g., inclusion in method signatures and
231   * other kinds of descriptions) and does not necessarily need to map to an
232   * actual Java type.
233   *
234   * @return  The name of the data type for this configuration attribute.
235   */
236  public abstract String getDataType();
237
238
239
240  /**
241   * Retrieves the attribute syntax for this configuration attribute.
242   *
243   * @return  The attribute syntax for this configuration attribute.
244   */
245  public abstract Syntax getSyntax();
246
247
248
249  /**
250   * Indicates whether this configuration attribute is required to have at least
251   * one value.
252   *
253   * @return  <CODE>true</CODE> if this configuration attribute is required to
254   *          have at least one value, or <CODE>false</CODE> if not.
255   */
256  public boolean isRequired()
257  {
258    return isRequired;
259  }
260
261
262
263  /**
264   * Indicates whether this configuration attribute may have multiple values.
265   *
266   * @return  <CODE>true</CODE> if this configuration attribute may have
267   *          multiple values, or <CODE>false</CODE> if not.
268   */
269  public boolean isMultiValued()
270  {
271    return isMultiValued;
272  }
273
274
275
276  /**
277   * Indicates whether changes to this configuration attribute require
278   * administrative action before they will take effect.
279   *
280   * @return  <CODE>true</CODE> if changes to this configuration attribute
281   *          require administrative action before they will take effect, or
282   *          <CODE>false</CODE> if changes will take effect immediately.
283   */
284  public boolean requiresAdminAction()
285  {
286    return requiresAdminAction;
287  }
288
289
290
291  /**
292   * Retrieves the set of active values for this configuration attribute.  This
293   * must not be modified by the caller.
294   *
295   * @return  The set of active values for this configuration attribute.
296   */
297  public LinkedHashSet<ByteString> getActiveValues()
298  {
299    return activeValues;
300  }
301
302
303
304  /**
305   * Indicates whether this attribute has been altered and that there are a set
306   * of pending values that will take effect after appropriate administrative
307   * action.
308   *
309   * @return  <CODE>true</CODE> if this attribute has pending values, or
310   *          <CODE>false</CODE> if not.
311   */
312  public boolean hasPendingValues()
313  {
314    return hasPendingValues;
315  }
316
317
318
319  /**
320   * Retrieves the set of values that this configuration attribute will have on
321   * restart or after any necessary administrative action is performed.  For
322   * attributes whose changes take effect immediately, this will always be the
323   * same as the set of active values.  This must not be modified by the caller.
324   *
325   * @return  The set of values that this configuration attribute will have
326   *          after any appropriate administrative action is taken.
327   */
328  public LinkedHashSet<ByteString> getPendingValues()
329  {
330    if (requiresAdminAction)
331    {
332      return pendingValues;
333    }
334    return activeValues;
335  }
336
337
338
339  /**
340   * Indicates whether the provided value is acceptable for use in this
341   * attribute.  If it is not acceptable, then the reason should be written into
342   * the provided buffer.
343   *
344   * @param  value         The value for which to make the determination.
345   * @param  rejectReason  A buffer into which a human-readable reason for the
346   *                       reject may be written.
347   *
348   * @return  <CODE>true</CODE> if the provided value is acceptable for use in
349   *          this attribute, or <CODE>false</CODE> if not.
350   */
351  public abstract boolean valueIsAcceptable(ByteString value,
352                                            StringBuilder rejectReason);
353
354
355
356  /**
357   * Specifies the set of values for this configuration attribute.  Each value
358   * will be validated using the <CODE>valueIsAcceptable</CODE> method, and
359   * only a single value will be allowed unless <CODE>isMultiValued</CODE>
360   * returns <CODE>true</CODE>.  If the set of values is acceptable, then it
361   * will be set either as the active set of values if changes are to take
362   * effect immediately, or if not then it will be applied to the set of
363   * pending values.
364   *
365   * @param  values  The set of values to apply to this attribute.
366   *
367   * @throws  ConfigException  If the provided set of values is not acceptable
368   *                           for some reason.
369   */
370  protected void setValues(LinkedHashSet<ByteString> values)
371         throws ConfigException
372  {
373    // If no values are provided, then check to see if this is a required
374    // attribute.  If it is, then reject the change.
375    if (values == null || values.isEmpty())
376    {
377      if (isRequired)
378      {
379        throw new ConfigException(ERR_CONFIG_ATTR_IS_REQUIRED.get(name));
380      }
381
382      if (requiresAdminAction)
383      {
384        pendingValues = notNull(values);
385        hasPendingValues = true;
386      }
387      else
388      {
389        activeValues = notNull(values);
390
391        pendingValues = activeValues;
392        hasPendingValues = false;
393      }
394
395      return;
396    }
397
398
399    // We know that we have at least one value, so get it and see if it is OK.
400    Iterator<ByteString>     iterator     = values.iterator();
401    ByteString               value        = iterator.next();
402    StringBuilder            rejectReason = new StringBuilder();
403
404    if (! valueIsAcceptable(value, rejectReason))
405    {
406      throw new ConfigException(ERR_CONFIG_ATTR_REJECTED_VALUE.get(
407          value, name, rejectReason));
408    }
409
410
411    // If this is not a multivalued attribute but there were more values
412    // provided, then reject it.
413    if (! isMultiValued && iterator.hasNext())
414    {
415      LocalizableMessage message = ERR_CONFIG_ATTR_SET_VALUES_IS_SINGLE_VALUED.get(name);
416      throw new ConfigException(message);
417    }
418
419
420    // Iterate through the remaining values to see if they are acceptable.
421    while (iterator.hasNext())
422    {
423      value = iterator.next();
424      if (! valueIsAcceptable(value, rejectReason))
425      {
426        throw new ConfigException(ERR_CONFIG_ATTR_REJECTED_VALUE.get(
427            value, name, rejectReason));
428      }
429    }
430
431
432    // If we've gotten here, then everything is OK.  Make this the new active or
433    // pending value set depending on the configuration.
434    if (requiresAdminAction)
435    {
436      pendingValues    = values;
437      hasPendingValues = true;
438    }
439    else
440    {
441      activeValues     = values;
442      pendingValues    = activeValues;
443      hasPendingValues = false;
444
445    }
446  }
447
448  private LinkedHashSet<ByteString> notNull(LinkedHashSet<ByteString> values)
449  {
450    return values != null ? values : new LinkedHashSet<ByteString>();
451  }
452
453  /**
454   * Specifies the set of active values for this configuration attribute.  No
455   * validation will be performed, and no checks will be made to determine if
456   * administrative action is required.
457   *
458   * @param  values  The set of active values for this configuration attribute.
459   */
460  protected void setActiveValues(LinkedHashSet<ByteString> values)
461  {
462    activeValues = values;
463  }
464
465
466
467  /**
468   * Specifies the set of pending values for this configuration attribute.  No
469   * validation will be performed, and no checks will be made to determine if
470   * administrative action is required.
471   *
472   * @param  values  The set of pending values for this configuration attribute.
473   */
474  protected void setPendingValues(LinkedHashSet<ByteString> values)
475  {
476    pendingValues    = values;
477    hasPendingValues = true;
478  }
479
480
481
482  /**
483   * Attempts to add the provided set of values to this configuration attribute.
484   * All of the appropriate validity checks will be performed, and the changes
485   * will be applied to either the active or pending values, depending on the
486   * configuration of this attribute.
487   *
488   * @param  values  The set of values to add to this configuration attribute.
489   *
490   * @throws  ConfigException  If a problem occurs while attempting to add the
491   *                           provided set of values to this configuration
492   *                           attribute.
493   */
494  protected void addValues(List<ByteString> values) throws ConfigException
495  {
496    // If there are no values provided, then do nothing.
497    if (values == null)
498    {
499      return;
500    }
501
502    int numValues = values.size();
503    if (numValues == 0)
504    {
505      return;
506    }
507
508
509    // Make sure that the value limit will not be exceeded for a single-valued
510    // attribute.
511    if (!isMultiValued)
512    {
513      if (numValues > 1
514          || (hasPendingValues && !pendingValues.isEmpty())
515          || (!hasPendingValues && !activeValues.isEmpty()))
516      {
517        throw new ConfigException(ERR_CONFIG_ATTR_ADD_VALUES_IS_SINGLE_VALUED.get(name));
518      }
519    }
520
521
522    // Create a temporary set of values that we will use for this change.  It
523    // may not actually be applied if an error occurs for some reason.
524    final LinkedHashSet<ByteString> vals = getValues();
525    LinkedHashSet<ByteString> tempValues = new LinkedHashSet<>(vals.size() + numValues);
526
527    // Iterate through all of the provided values.  Make sure that each is
528    // acceptable for use and that it is not already contained in the value set.
529    StringBuilder rejectReason = new StringBuilder();
530    for (ByteString value : values)
531    {
532      if (tempValues.contains(value))
533      {
534        throw new ConfigException(ERR_CONFIG_ATTR_ADD_VALUES_ALREADY_EXISTS.get(
535            name, value));
536      }
537
538      if (! valueIsAcceptable(value, rejectReason))
539      {
540        throw new ConfigException(ERR_CONFIG_ATTR_REJECTED_VALUE.get(
541            value, name, rejectReason));
542      }
543    }
544
545
546    // If we have gotten here, then everything is OK, so go ahead and assign
547    // the temporary value set to either the active or pending lists.
548    if (requiresAdminAction)
549    {
550      pendingValues    = tempValues;
551      hasPendingValues = true;
552    }
553    else
554    {
555      activeValues     = tempValues;
556      pendingValues    = tempValues;
557      hasPendingValues = false;
558    }
559  }
560
561  private LinkedHashSet<ByteString> getValues()
562  {
563    return requiresAdminAction && hasPendingValues
564        ? pendingValues
565        : activeValues;
566  }
567
568  /**
569   * Attempts to remove the set of values from this configuration attribute.
570   *
571   * @param  values  The set of values to remove from this configuration
572   *                 attribute.
573   *
574   * @throws  ConfigException  If any of the provided values are not in the
575   *                           value set, or if this is a required attribute and
576   *                           the resulting value list would be empty.
577   */
578  protected void removeValues(List<ByteString> values) throws ConfigException
579  {
580    // Create a temporary set of values that we will use for this change.  It
581    // may not actually be applied if an error occurs for some reason.
582    LinkedHashSet<ByteString> tempValues = new LinkedHashSet<>(getValues());
583
584    // Iterate through all the provided values and make sure that they are
585    // contained in the list.  If not, then throw an exception.  If so, then
586    // remove it.
587    for (ByteString value : values)
588    {
589      if (! tempValues.remove(value))
590      {
591        throw new ConfigException(ERR_CONFIG_ATTR_NO_SUCH_VALUE.get(name, value));
592      }
593    }
594
595
596    // If this is a required attribute, then make sure that it will have at
597    // least one value.
598    if (isRequired && tempValues.isEmpty())
599    {
600      LocalizableMessage message = ERR_CONFIG_ATTR_IS_REQUIRED.get(name);
601      throw new ConfigException(message);
602    }
603
604
605    // If we have gotten here, then everything is OK, so go ahead and assign
606    // the temporary value set to either the active or pending lists.
607    if (requiresAdminAction)
608    {
609      pendingValues    = tempValues;
610      hasPendingValues = true;
611    }
612    else
613    {
614      activeValues     = tempValues;
615      pendingValues    = tempValues;
616      hasPendingValues = false;
617    }
618  }
619
620
621
622  /**
623   * Removes all values from this configuration attribute.
624   *
625   * @throws  ConfigException  If this is a required attribute that must have at
626   *                           least one value.
627   */
628  protected void removeAllValues()
629         throws ConfigException
630  {
631    if (isRequired)
632    {
633      LocalizableMessage message = ERR_CONFIG_ATTR_IS_REQUIRED.get(name);
634      throw new ConfigException(message);
635    }
636
637
638    if (requiresAdminAction)
639    {
640      if (pendingValues == null)
641      {
642        pendingValues = new LinkedHashSet<>();
643      }
644      else
645      {
646        pendingValues.clear();
647      }
648
649      hasPendingValues = true;
650    }
651    else
652    {
653      activeValues.clear();
654      pendingValues = activeValues;
655      hasPendingValues = false;
656    }
657  }
658
659
660
661  /**
662   * Assigns the initial values to this configuration attribute.  This will wipe
663   * out any previous active or pending values that may have been assigned, and
664   * it will not perform any validation on those values.  This method must only
665   * be used to set the initial values for this attribute from the configuration
666   * repository and must not be called any other time.
667   *
668   * @param  values  The initial set of values to assign to this configuration
669   *                 attribute.
670   */
671  public void setInitialValues(LinkedHashSet<ByteString> values)
672  {
673    if (values == null)
674    {
675      values = new LinkedHashSet<>();
676    }
677
678    activeValues     = values;
679    pendingValues    = values;
680    hasPendingValues = false;
681  }
682
683
684
685  /**
686   * Applies the set of pending values, making them the active values for this
687   * configuration attribute.  This will not take any action if there are no
688   * pending values.
689   */
690  public void applyPendingValues()
691  {
692    if (hasPendingValues)
693    {
694      activeValues     = pendingValues;
695      hasPendingValues = false;
696    }
697  }
698
699
700
701  /**
702   * Converts the provided set of strings to a corresponding set of attribute
703   * values.
704   *
705   * @param  valueStrings   The set of strings to be converted into attribute
706   *                        values.
707   * @param  allowFailures  Indicates whether the decoding process should allow
708   *                        any failures in which one or more values could be
709   *                        decoded but at least one could not.  If this is
710   *                        <CODE>true</CODE> and such a condition is acceptable
711   *                        for the underlying attribute type, then the returned
712   *                        set of values should simply not include those
713   *                        undecodable values.
714   *
715   * @return  The set of attribute values converted from the provided strings.
716   *
717   * @throws  ConfigException  If an unrecoverable problem occurs while
718   *                           performing the conversion.
719   */
720  public abstract LinkedHashSet<ByteString> stringsToValues(
721      List<String> valueStrings, boolean allowFailures) throws ConfigException;
722
723
724
725  /**
726   * Converts the set of active values for this configuration attribute into a
727   * set of strings that may be stored in the configuration or represented over
728   * protocol.  The string representation used by this method should be
729   * compatible with the decoding used by the <CODE>stringsToValues</CODE>
730   * method.
731   *
732   * @return  The string representations of the set of active values for this
733   *          configuration attribute.
734   */
735  public abstract List<String> activeValuesToStrings();
736
737
738
739  /**
740   * Converts the set of pending values for this configuration attribute into a
741   * set of strings that may be stored in the configuration or represented over
742   * protocol.  The string representation used by this method should be
743   * compatible with the decoding used by the <CODE>stringsToValues</CODE>
744   * method.
745   *
746   * @return  The string representations of the set of pending values for this
747   *          configuration attribute, or <CODE>null</CODE> if there are no
748   *          pending values.
749   */
750  public abstract List<String> pendingValuesToStrings();
751
752
753
754  /**
755   * Retrieves a new configuration attribute of this type that will contain the
756   * values from the provided attribute.
757   *
758   * @param  attributeList  The list of attributes to use to create the config
759   *                        attribute.  The list must contain either one or two
760   *                        elements, with both attributes having the same base
761   *                        name and the only option allowed is ";pending" and
762   *                        only if this attribute is one that requires admin
763   *                        action before a change may take effect.
764   *
765   * @return  The generated configuration attribute.
766   *
767   * @throws  ConfigException  If the provided attribute cannot be treated as a
768   *                           configuration attribute of this type (e.g., if
769   *                           one or more of the values of the provided
770   *                           attribute are not suitable for an attribute of
771   *                           this type, or if this configuration attribute is
772   *                           single-valued and the provided attribute has
773   *                           multiple values).
774   */
775  public abstract ConfigAttribute getConfigAttribute(List<Attribute>
776                                                          attributeList)
777         throws ConfigException;
778
779
780
781  /**
782   * Retrieves a JMX attribute containing the active value set for this
783   * configuration attribute.
784   *
785   * @return  A JMX attribute containing the active value set for this
786   *          configuration attribute.
787   */
788  public abstract javax.management.Attribute toJMXAttribute();
789
790  /**
791   * Retrieves a JMX attribute containing the pending value set for this
792   * configuration attribute.
793   *
794   * @return  A JMX attribute containing the pending value set for this
795   *          configuration attribute.
796   */
797  public abstract javax.management.Attribute toJMXAttributePending();
798
799
800
801  /**
802   * Adds information about this configuration attribute to the provided JMX
803   * attribute list.  If this configuration attribute requires administrative
804   * action before changes take effect and it has a set of pending values, then
805   * two attributes should be added to the list -- one for the active value
806   * and one for the pending value.  The pending value should be named with
807   * the pending option.
808   *
809   * @param  attributeList  The attribute list to which the JMX attribute(s)
810   *                        should be added.
811   */
812  public abstract void toJMXAttribute(AttributeList attributeList);
813
814
815
816  /**
817   * Adds information about this configuration attribute to the provided list in
818   * the form of a JMX <CODE>MBeanAttributeInfo</CODE> object.  If this
819   * configuration attribute requires administrative action before changes take
820   * effect and it has a set of pending values, then two attribute info objects
821   * should be added to the list -- one for the active value (which should be
822   * read-write) and one for the pending value (which should be read-only).  The
823   * pending value should be named with the pending option.
824   *
825   * @param  attributeInfoList  The list to which the attribute information
826   *                            should be added.
827   */
828  public abstract void toJMXAttributeInfo(List<MBeanAttributeInfo>
829                                               attributeInfoList);
830
831
832
833  /**
834   * Retrieves a JMX <CODE>MBeanParameterInfo</CODE> object that describes this
835   * configuration attribute.
836   *
837   * @return  A JMX <CODE>MBeanParameterInfo</CODE> object that describes this
838   *          configuration attribute.
839   */
840  public abstract MBeanParameterInfo toJMXParameterInfo();
841
842
843
844  /**
845   * Attempts to set the value of this configuration attribute based on the
846   * information in the provided JMX attribute.
847   *
848   * @param  jmxAttribute  The JMX attribute to use to attempt to set the value
849   *                       of this configuration attribute.
850   *
851   * @throws  ConfigException  If the provided JMX attribute does not have an
852   *                           acceptable value for this configuration
853   *                           attribute.
854   */
855  public abstract void setValue(javax.management.Attribute jmxAttribute)
856         throws ConfigException;
857
858
859
860  /**
861   * Creates a duplicate of this configuration attribute.
862   *
863   * @return  A duplicate of this configuration attribute.
864   */
865  public abstract ConfigAttribute duplicate();
866
867  /**
868   * Creates the appropriate value set with the provided value.
869   *
870   * @param value
871   *          The value to use to create the value set.
872   * @return The value set constructed from the provided value.
873   */
874  static LinkedHashSet<ByteString> getValueSet(String value)
875  {
876    LinkedHashSet<ByteString> valueSet = new LinkedHashSet<>(1);
877    valueSet.add(ByteString.valueOfUtf8(value));
878    return valueSet;
879  }
880
881  /**
882   * Creates the appropriate value set with the provided values.
883   *
884   * @param values
885   *          The values to use to create the value set.
886   * @return The constructed value set.
887   */
888  static LinkedHashSet<ByteString> getValueSet(List<String> values)
889  {
890    if (values == null)
891    {
892      return null;
893    }
894
895    LinkedHashSet<ByteString> valueSet = new LinkedHashSet<>(values.size());
896    for (String value : values)
897    {
898      valueSet.add(ByteString.valueOfUtf8(value));
899    }
900    return valueSet;
901  }
902}