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