001    /* OpenMBeanAttributeInfoSupport.java -- Open typed info about an attribute.
002       Copyright (C) 2006, 2007 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.management.openmbean;
039    
040    import java.util.Collections;
041    import java.util.HashSet;
042    import java.util.Set;
043    
044    import javax.management.MBeanAttributeInfo;
045    
046    /**
047     * Describes an attribute of an open management bean.  
048     *
049     * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
050     * @since 1.5
051     */
052    public class OpenMBeanAttributeInfoSupport
053      extends MBeanAttributeInfo
054      implements OpenMBeanAttributeInfo
055    {
056    
057      /**
058       * Compatible with JDK 1.5
059       */
060      private static final long serialVersionUID = -4867215622149721849L;
061    
062      /**
063       * The open type of the attribute.
064       */
065      private OpenType<?> openType;
066    
067      /**
068       * The default value of the attribute (may be <code>null</code>).
069       */
070      private Object defaultValue;
071    
072      /**
073       * The possible legal values of the attribute (may be <code>null</code>).
074       */
075      private Set<?> legalValues;
076    
077      /**
078       * The minimum value of the attribute (may be <code>null</code>).
079       */
080      private Comparable<Object> minValue;
081    
082      /**
083       * The maximum value of the attribute (may be <code>null</code>).
084       */
085      private Comparable<Object> maxValue;
086    
087      /**
088       * The hash code of this instance.
089       */
090      private transient Integer hashCode;
091    
092      /**
093       * The <code>toString()</code> result of this instance.
094       */
095      private transient String string;
096    
097      /**
098       * Constructs a new {@link OpenMBeanAttributeInfo} using the
099       * specified name, description, open type and access properties.
100       * The name, description and open type may not be <code>null</code>
101       * and the name and description may not be equal to the empty
102       * string.
103       *
104       * @param name the name of the attribute.
105       * @param desc a description of the attribute.
106       * @param type the open type of the attribute.
107       * @param isReadable true if the attribute's value can be read.
108       * @param isWritable true if the attribute's value can be changed.
109       * @param isIs true if the attribute uses an accessor of the form isXXX.
110       * @throws IllegalArgumentException if the name, description or
111       *                                  open type are <code>null</code>
112       *                                  or the name or description are
113       *                                  the empty string.
114       */
115      public OpenMBeanAttributeInfoSupport(String name, String desc, OpenType<?> type,
116                                           boolean isReadable, boolean isWritable,
117                                           boolean isIs)
118      {
119        super(name, type == null ? null : type.getClassName(), desc, isReadable,
120              isWritable, isIs);
121        if (name == null)
122          throw new IllegalArgumentException("The name may not be null.");
123        if (desc == null)
124          throw new IllegalArgumentException("The description may not be null.");
125        if (type == null)
126          throw new IllegalArgumentException("The type may not be null.");
127        if (name.length() == 0)
128          throw new IllegalArgumentException("The name may not be the empty string.");
129        if (desc.length() == 0)
130          throw new IllegalArgumentException("The description may not be the " +
131                                             "empty string.");
132      }
133    
134      /**
135       * Constructs a new {@link OpenMBeanAttributeInfo} using the
136       * specified name, description, open type and default value.  The
137       * name, description and open type cannot be <code>null</code> and
138       * the name and description may not be equal to the empty string.
139       * The default value may be <code>null</code>.  If non-null, it must
140       * be a valid value of the given open type.  Default values are not
141       * applicable to the open types, {@link ArrayType} and {@link
142       * TabularType}.
143       *
144       * @param name the name of the attribute.
145       * @param desc a description of the attribute.
146       * @param type the open type of the attribute.
147       * @param isReadable true if the attribute's value can be read.
148       * @param isWritable true if the attribute's value can be changed.
149       * @param isIs true if the attribute uses an accessor of the form isXXX.
150       * @param defaultValue the default value of the attribute.
151       * @throws IllegalArgumentException if the name, description or
152       *                                  open type are <code>null</code>
153       *                                  or the name or description are
154       *                                  the empty string.
155       * @throws OpenDataException if <code>defaultValue<code> is non-null
156       *                           and is either not a value of the given
157       *                           open type or the open type is an instance
158       *                           of {@link ArrayType} or {@link TabularType}.
159       */
160      public <T> OpenMBeanAttributeInfoSupport(String name, String desc, OpenType<T> type,
161                                               boolean isReadable, boolean isWritable,
162                                               boolean isIs, T defaultValue)
163        throws OpenDataException
164      {
165        this(name, desc, type, isReadable, isWritable, isIs, defaultValue, null);
166      }
167    
168      /**
169       * <p>
170       * Constructs a new {@link OpenMBeanAttributeInfo} using the
171       * specified name, description, open type, access properties, 
172       * default, maximum and minimum values.  The name, description
173       * and open type cannot be <code>null</code> and the name and
174       * description may not be equal to the empty string.  The
175       * default, maximum and minimum values may be <code>null</code>.
176       * The following conditions apply when the attributes mentioned
177       * are non-null:
178       * </p>
179       * <ul>
180       * <li>The values must be valid values for the given open type.</li>
181       * <li>Default values are not applicable to the open types, {@link
182       * ArrayType} and {@link TabularType}.</li>
183       * <li>The minimum value must be smaller than or equal to the maximum value
184       * (literally, <code>minValue.compareTo(maxValue) <= 0</code>.</li>
185       * <li>The minimum value must be smaller than or equal to the default value
186       * (literally, <code>minValue.compareTo(defaultValue) <= 0</code>.</li>
187       * <li>The default value must be smaller than or equal to the maximum value
188       * (literally, <code>defaultValue.compareTo(maxValue) <= 0</code>.</li>
189       * </ul>
190       * 
191       * @param name the name of the attribute.
192       * @param desc a description of the attribute.
193       * @param type the open type of the attribute.
194       * @param isReadable true if the attribute's value can be read.
195       * @param isWritable true if the attribute's value can be changed.
196       * @param isIs true if the attribute uses an accessor of the form isXXX.
197       * @param defaultValue the default value of the attribute, or <code>null</code>.
198       * @param minimumValue the minimum value of the attribute, or <code>null</code>.
199       * @param maximumValue the maximum value of the attribute, or <code>null</code>.
200       * @throws IllegalArgumentException if the name, description or
201       *                                  open type are <code>null</code>
202       *                                  or the name or description are
203       *                                  the empty string.
204       * @throws OpenDataException if any condition in the list above is broken.
205       */
206      public <T> OpenMBeanAttributeInfoSupport(String name, String desc, OpenType<T> type,
207                                               boolean isReadable, boolean isWritable,
208                                               boolean isIs, T defaultValue,
209                                               Comparable<T> minimumValue,
210                                               Comparable<T> maximumValue)
211        throws OpenDataException
212      {
213        this(name, desc, type, isReadable, isWritable, isIs);
214        if (defaultValue != null && !(type.isValue(defaultValue)))
215          throw new OpenDataException("The default value is not a member of the " +
216                                      "open type given.");
217        if (minimumValue != null && !(type.isValue(minimumValue)))
218          throw new OpenDataException("The minimum value is not a member of the " +
219                                      "open type given.");
220        if (maximumValue != null && !(type.isValue(maximumValue)))
221          throw new OpenDataException("The maximum value is not a member of the " +
222                                      "open type given.");
223        if (defaultValue != null && (type instanceof ArrayType || 
224                                     type instanceof TabularType))
225          throw new OpenDataException("Default values are not applicable for " +
226                                      "array or tabular types.");
227        if (minValue != null && maxValue != null 
228            && minValue.compareTo(maxValue) > 0)
229          throw new OpenDataException("The minimum value is greater than the " +
230                                      "maximum.");
231        if (minValue != null && defaultValue != null 
232            && minValue.compareTo(defaultValue) > 0)
233          throw new OpenDataException("The minimum value is greater than the " +
234                                      "default.");
235        if (defaultValue != null && maxValue != null
236            && maxValue.compareTo(defaultValue) < 0)
237          throw new OpenDataException("The default value is greater than the " +
238                                      "maximum.");
239        
240        openType = type;
241        this.defaultValue = defaultValue;
242        minValue = (Comparable<Object>) minimumValue;
243        maxValue = (Comparable<Object>) maximumValue;
244      }
245    
246      /**
247       * <p>
248       * Constructs a new {@link OpenMBeanAttributeInfo} using the
249       * specified name, description, open type, access properties, default
250       * value and set of legal values.  The name, description and open type
251       * cannot be <code>null</code> and the name and description may not be
252       * equal to the empty string.  The default, maximum and minimum values
253       * may be <code>null</code>.  The following conditions apply when the
254       * attributes mentioned are non-null:
255       * </p>
256       * <ul>
257       * <li>The default value and each of the legal values must be a valid
258       * value for the given open type.</li>
259       * <li>Default and legal values are not applicable to the open types, {@link
260       * ArrayType} and {@link TabularType}.</li>
261       * <li>The default value is not in the set of legal values.</li>
262       * </ul>
263       * <p>
264       * The legal values are copied from the array into a unmodifiable set,
265       * so future modifications to the array have no effect.
266       * </p>
267       *
268       * @param name the name of the attribute.
269       * @param desc a description of the attribute.
270       * @param type the open type of the attribute.
271       * @param isReadable true if the attribute's value can be read.
272       * @param isWritable true if the attribute's value can be changed.
273       * @param isIs true if the attribute uses an accessor of the form isXXX.
274       * @param defaultValue the default value of the attribute, or <code>null</code>.
275       * @param legalValues the legal values of the attribute.  May be
276       *                    <code>null</code> or an empty array.
277       * @throws IllegalArgumentException if the name, description or
278       *                                  open type are <code>null</code>
279       *                                  or the name or description are
280       *                                  the empty string.
281       * @throws OpenDataException if any condition in the list above is broken.
282       */
283      public <T> OpenMBeanAttributeInfoSupport(String name, String desc, OpenType<T> type,
284                                               boolean isReadable, boolean isWritable,
285                                               boolean isIs, T defaultValue,
286                                               T[] legalValues)
287        throws OpenDataException
288      {
289        this(name, desc, type, isReadable, isWritable, isIs);
290        if (defaultValue != null && !(type.isValue(defaultValue)))
291          throw new OpenDataException("The default value is not a member of the " +
292                                      "open type given.");
293        if (defaultValue != null && (type instanceof ArrayType || 
294                                     type instanceof TabularType))
295          throw new OpenDataException("Default values are not applicable for " +
296                                      "array or tabular types.");
297        if (legalValues != null && (type instanceof ArrayType || 
298                                    type instanceof TabularType))
299          throw new OpenDataException("Legal values are not applicable for " +
300                                      "array or tabular types.");
301        if (legalValues != null && legalValues.length > 0)
302          {
303            Set lv = new HashSet(legalValues.length);
304            for (int a = 0; a < legalValues.length; ++a)
305              {
306                if (legalValues[a] != null && 
307                    !(type.isValue(legalValues[a])))
308                  throw new OpenDataException("The legal value, " 
309                                              + legalValues[a] + 
310                                              "is not a member of the " +
311                                              "open type given.");
312                lv.add(legalValues[a]);
313              }
314            if (defaultValue != null && !(lv.contains(defaultValue)))
315              throw new OpenDataException("The default value is not in the set " +
316                                          "of legal values.");
317            this.legalValues = Collections.unmodifiableSet(lv);
318          }
319        openType = type;
320        this.defaultValue = defaultValue;
321      }
322    
323      /**
324       * Compares this attribute with the supplied object.  This returns
325       * true iff the object is an instance of {@link OpenMBeanAttributeInfo}
326       * with an equal name and open type and the same default, minimum,
327       * maximum and legal values and the same access properties.
328       *
329       * @param obj the object to compare.
330       * @return true if the object is a {@link OpenMBeanAttributeInfo}
331       *         instance, 
332       *         <code>name.equals(object.getName())</code>,
333       *         <code>openType.equals(object.getOpenType())</code>,
334       *         <code>isRead == object.isReadable()</code>,
335       *         <code>isWrite == object.isWritable()</code>,
336       *         <code>isIs == object.isIs()</code>,
337       *         <code>defaultValue.equals(object.getDefaultValue())</code>,
338       *         <code>minValue.equals(object.getMinValue())</code>,
339       *         <code>maxValue.equals(object.getMaxValue())</code>,
340       *         and <code>legalValues.equals(object.getLegalValues())</code>.
341       */
342      public boolean equals(Object obj)
343      {
344        if (!(obj instanceof OpenMBeanAttributeInfo))
345          return false;
346        OpenMBeanAttributeInfo o = (OpenMBeanAttributeInfo) obj;
347        return getName().equals(o.getName()) &&
348          openType.equals(o.getOpenType()) &&
349          isReadable() == o.isReadable() &&
350          isWritable() == o.isWritable() &&
351          isIs() == o.isIs() &&
352          (defaultValue == null ? o.getDefaultValue() == null :
353           defaultValue.equals(o.getDefaultValue())) &&
354          (minValue == null ? o.getMinValue() == null :
355           minValue.equals(o.getMinValue())) &&
356          (maxValue == null ? o.getMaxValue() == null :
357           maxValue.equals(o.getMaxValue())) &&
358          (legalValues == null ? o.getLegalValues() == null :
359           legalValues.equals(o.getLegalValues()));
360      }
361    
362      /**
363       * Returns the default value of this attribute, or <code>null</code>
364       * if there is no default value.
365       *
366       * @return the default value of the attribute, or <code>null</code>
367       *         if there is no default.
368       */
369      public Object getDefaultValue()
370      {
371        return defaultValue;
372      }
373    
374      /**
375       * Returns a {@link java.util.Set} enumerating the legal values
376       * of this attribute, or <code>null</code> if no such limited
377       * set exists for this attribute.
378       *
379       * @return a set of legal values, or <code>null</code> if no such
380       *         set exists.
381       */
382      public Set<?> getLegalValues()
383      {
384        return legalValues;
385      }
386    
387      /**
388       * Returns the maximum value of this attribute, or <code>null</code>
389       * if there is no maximum.
390       *
391       * @return the maximum value, or <code>null</code> if none exists.
392       */
393      public Comparable<?> getMaxValue()
394      {
395        return maxValue;
396      }
397    
398      /**
399       * Returns the minimum value of this attribute, or <code>null</code>
400       * if there is no minimum.
401       *
402       * @return the minimum value, or <code>null</code> if none exists.
403       */
404      public Comparable<?> getMinValue()
405      {
406        return minValue;
407      }
408    
409      /**
410       * Returns the open type instance which represents the type of this
411       * attribute.
412       *
413       * @return the open type of this attribute.
414       */
415      public OpenType<?> getOpenType()
416      {
417        return openType;
418      }
419    
420      /**
421       * Returns true if this attribute has a default value
422       * (i.e. the value is non-null).
423       *
424       * @return true if this attribute has a default.
425       */
426      public boolean hasDefaultValue()
427      {
428        return defaultValue != null;
429      }
430    
431      /**
432       * <p>
433       * Returns the hashcode of the attribute information as the sum of
434       * the hashcodes of the name, open type, default value, maximum
435       * value, minimum value and the set of legal values.
436       * </p>
437       * <p>
438       * As instances of this class are immutable, the hash code
439       * is computed just once for each instance and reused
440       * throughout its life.
441       * </p>
442       *
443       * @return the hashcode of the attribute information.
444       */
445      public int hashCode()
446      {
447        if (hashCode == null)
448          hashCode = Integer.valueOf(getName().hashCode() + 
449                                     openType.hashCode() +
450                                     Boolean.valueOf(isReadable()).hashCode() +
451                                     (2 * 
452                                      Boolean.valueOf(isWritable()).hashCode()) +
453                                     (4 * Boolean.valueOf(isIs()).hashCode()) +
454                                     (defaultValue == null ? 0 :
455                                      defaultValue.hashCode()) +
456                                     (minValue == null ? 0 :
457                                      minValue.hashCode()) +
458                                     (maxValue == null ? 0 :
459                                      maxValue.hashCode()) +
460                                     (legalValues == null ? 0 :
461                                      legalValues.hashCode()));
462        return hashCode.intValue();
463      }
464    
465      /**
466       * Returns true if there is a set of legal values for this
467       * attribute (i.e. the value is non-null).
468       *
469       * @return true if a set of legal values exists for this
470       *         attribute.
471       */
472      public boolean hasLegalValues()
473      {
474        return legalValues != null;
475      }
476    
477      /**
478       * Returns true if there is a maximum value for this attribute
479       * (i.e. the value is non-null).
480       *
481       * @return true if a maximum value exists for this attribute.
482       */
483      public boolean hasMaxValue()
484      {
485        return maxValue != null;
486      }
487    
488      /**
489       * Returns true if there is a minimum value for this attribute.
490       * (i.e. the value is non-null).
491       *
492       * @return true if a minimum value exists for this attribute.
493       */
494      public boolean hasMinValue()
495      {
496        return minValue != null;
497      }
498    
499      /**
500       * Returns true if the specified object is a valid value for
501       * this attribute.
502       *
503       * @param obj the object to test.
504       * @return true if <code>obj</code> is a valid value for this
505       *         attribute.
506       */
507      public boolean isValue(Object obj)
508      {
509        return openType.isValue(obj);
510      }
511    
512      /**
513       * <p>
514       * Returns a textual representation of this instance.  This
515       * is constructed using the class name
516       * (<code>javax.management.openmbean.OpenMBeanAttributeInfo</code>)
517       * along with the name, open type, access properties, default,
518       * minimum, maximum  and legal values of the attribute.
519       * </p>
520       * <p>
521       * As instances of this class are immutable, the return value
522       * is computed just once for each instance and reused
523       * throughout its life.
524       * </p>
525       *
526       * @return a @link{java.lang.String} instance representing
527       *         the instance in textual form.
528       */
529      public String toString()
530      {
531        if (string == null)
532          string = getClass().getName()
533            + "[name=" + getName() 
534            + ",openType=" + openType
535            + ",isReadable=" + isReadable()
536            + ",isWritable=" + isWritable()
537            + ",isIs=" + isIs()
538            + ",defaultValue=" + defaultValue
539            + ",minValue=" + minValue
540            + ",maxValue=" + maxValue
541            + ",legalValues=" + legalValues
542            + "]";
543        return string;
544      }
545    
546    }