1 /*
   2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 package javax.management.openmbean;
  28 
  29 
  30 // java import
  31 //
  32 import java.util.Set;
  33 import javax.management.Descriptor;
  34 import javax.management.DescriptorRead;  // for Javadoc
  35 import javax.management.ImmutableDescriptor;
  36 import javax.management.MBeanParameterInfo;
  37 
  38 // OpenMBeanAttributeInfoSupport and this class are very similar
  39 // but can't easily be refactored because there's no multiple inheritance.
  40 // The best we can do for refactoring is to put a bunch of static methods
  41 // in OpenMBeanAttributeInfoSupport and import them here.
  42 import static javax.management.openmbean.OpenMBeanAttributeInfoSupport.*;
  43 
  44 /**
  45  * Describes a parameter used in one or more operations or
  46  * constructors of an open MBean.
  47  *
  48  *
  49  * @since 1.5
  50  */
  51 public class OpenMBeanParameterInfoSupport
  52     extends MBeanParameterInfo
  53     implements OpenMBeanParameterInfo {
  54 
  55     /* Serial version */
  56     static final long serialVersionUID = -7235016873758443122L;
  57 
  58     /**
  59      * @serial The open mbean parameter's <i>open type</i>
  60      */
  61     @SuppressWarnings("serial") // Not statically typed as Serializable
  62     private OpenType<?>    openType;
  63 
  64     /**
  65      * @serial The open mbean parameter's default value
  66      */
  67     @SuppressWarnings("serial") // Not statically typed as Serializable
  68     private Object      defaultValue    = null;
  69 
  70     /**
  71      * @serial The open mbean parameter's legal values. This {@link
  72      * Set} is unmodifiable
  73      */
  74     @SuppressWarnings("serial") // Conditionally serializable
  75     private Set<?> legalValues     = null;  // to be constructed unmodifiable
  76 
  77     /**
  78      * @serial The open mbean parameter's min value
  79      */
  80     @SuppressWarnings("serial") // Conditionally serializable
  81     private Comparable<?> minValue        = null;
  82 
  83     /**
  84      * @serial The open mbean parameter's max value
  85      */
  86     @SuppressWarnings("serial") // Conditionally serializable
  87     private Comparable<?> maxValue        = null;
  88 
  89 
  90     // As this instance is immutable, these two values need only
  91     // be calculated once.
  92     private transient Integer myHashCode = null;        // As this instance is immutable, these two values
  93     private transient String  myToString = null;        // need only be calculated once.
  94 
  95 
  96     /**
  97      * Constructs an {@code OpenMBeanParameterInfoSupport} instance,
  98      * which describes the parameter used in one or more operations or
  99      * constructors of a class of open MBeans, with the specified
 100      * {@code name}, {@code openType} and {@code description}.
 101      *
 102      * @param name  cannot be a null or empty string.
 103      *
 104      * @param description  cannot be a null or empty string.
 105      *
 106      * @param openType  cannot be null.
 107      *
 108      * @throws IllegalArgumentException if {@code name} or {@code
 109      * description} are null or empty string, or {@code openType} is
 110      * null.
 111      */
 112     public OpenMBeanParameterInfoSupport(String name,
 113                                          String description,
 114                                          OpenType<?> openType) {
 115         this(name, description, openType, (Descriptor) null);
 116     }
 117 
 118     /**
 119      * Constructs an {@code OpenMBeanParameterInfoSupport} instance,
 120      * which describes the parameter used in one or more operations or
 121      * constructors of a class of open MBeans, with the specified
 122      * {@code name}, {@code openType}, {@code description},
 123      * and {@code descriptor}.
 124      *
 125      * <p>The {@code descriptor} can contain entries that will define
 126      * the values returned by certain methods of this class, as
 127      * explained in the <a href="package-summary.html#constraints">
 128      * package description</a>.
 129      *
 130      * @param name  cannot be a null or empty string.
 131      *
 132      * @param description  cannot be a null or empty string.
 133      *
 134      * @param openType  cannot be null.
 135      *
 136      * @param descriptor The descriptor for the parameter.  This may be null
 137      * which is equivalent to an empty descriptor.
 138      *
 139      * @throws IllegalArgumentException if {@code name} or {@code
 140      * description} are null or empty string, or {@code openType} is
 141      * null, or the descriptor entries are invalid as described in the
 142      * <a href="package-summary.html#constraints">package
 143      * description</a>.
 144      *
 145      * @since 1.6
 146      */
 147     public OpenMBeanParameterInfoSupport(String name,
 148                                          String description,
 149                                          OpenType<?> openType,
 150                                          Descriptor descriptor) {
 151 
 152 
 153         // Construct parent's state
 154         //
 155         super(name,
 156               (openType==null) ? null : openType.getClassName(),
 157               description,
 158               ImmutableDescriptor.union(descriptor,(openType==null)?null:
 159                 openType.getDescriptor()));
 160 
 161         // Initialize this instance's specific state
 162         //
 163         this.openType = openType;
 164 
 165         descriptor = getDescriptor();  // replace null by empty
 166         this.defaultValue = valueFrom(descriptor, "defaultValue", openType);
 167         this.legalValues = valuesFrom(descriptor, "legalValues", openType);
 168         this.minValue = comparableValueFrom(descriptor, "minValue", openType);
 169         this.maxValue = comparableValueFrom(descriptor, "maxValue", openType);
 170 
 171         try {
 172             check(this);
 173         } catch (OpenDataException e) {
 174             throw new IllegalArgumentException(e.getMessage(), e);
 175         }
 176     }
 177 
 178 
 179     /**
 180      * Constructs an {@code OpenMBeanParameterInfoSupport} instance,
 181      * which describes the parameter used in one or more operations or
 182      * constructors of a class of open MBeans, with the specified
 183      * {@code name}, {@code openType}, {@code description} and {@code
 184      * defaultValue}.
 185      *
 186      * @param name  cannot be a null or empty string.
 187      *
 188      * @param description  cannot be a null or empty string.
 189      *
 190      * @param openType  cannot be null.
 191      *
 192      * @param defaultValue must be a valid value for the {@code
 193      * openType} specified for this parameter; default value not
 194      * supported for {@code ArrayType} and {@code TabularType}; can be
 195      * null, in which case it means that no default value is set.
 196      *
 197      * @param <T> allows the compiler to check that the {@code defaultValue},
 198      * if non-null, has the correct Java type for the given {@code openType}.
 199      *
 200      * @throws IllegalArgumentException if {@code name} or {@code
 201      * description} are null or empty string, or {@code openType} is
 202      * null.
 203      *
 204      * @throws OpenDataException if {@code defaultValue} is not a
 205      * valid value for the specified {@code openType}, or {@code
 206      * defaultValue} is non null and {@code openType} is an {@code
 207      * ArrayType} or a {@code TabularType}.
 208      */
 209     public <T> OpenMBeanParameterInfoSupport(String   name,
 210                                              String   description,
 211                                              OpenType<T> openType,
 212                                              T        defaultValue)
 213             throws OpenDataException {
 214         this(name, description, openType, defaultValue, (T[]) null);
 215     }
 216 
 217     /**
 218      * <p>Constructs an {@code OpenMBeanParameterInfoSupport} instance,
 219      * which describes the parameter used in one or more operations or
 220      * constructors of a class of open MBeans, with the specified
 221      * {@code name}, {@code openType}, {@code description}, {@code
 222      * defaultValue} and {@code legalValues}.</p>
 223      *
 224      * <p>The contents of {@code legalValues} are copied, so subsequent
 225      * modifications of the array referenced by {@code legalValues}
 226      * have no impact on this {@code OpenMBeanParameterInfoSupport}
 227      * instance.</p>
 228      *
 229      * @param name  cannot be a null or empty string.
 230      *
 231      * @param description  cannot be a null or empty string.
 232      *
 233      * @param openType  cannot be null.
 234      *
 235      * @param defaultValue must be a valid value for the {@code
 236      * openType} specified for this parameter; default value not
 237      * supported for {@code ArrayType} and {@code TabularType}; can be
 238      * null, in which case it means that no default value is set.
 239      *
 240      * @param legalValues each contained value must be valid for the
 241      * {@code openType} specified for this parameter; legal values not
 242      * supported for {@code ArrayType} and {@code TabularType}; can be
 243      * null or empty.
 244      *
 245      * @param <T> allows the compiler to check that the {@code
 246      * defaultValue} and {@code legalValues}, if non-null, have the
 247      * correct Java type for the given {@code openType}.
 248      *
 249      * @throws IllegalArgumentException if {@code name} or {@code
 250      * description} are null or empty string, or {@code openType} is
 251      * null.
 252      *
 253      * @throws OpenDataException if {@code defaultValue} is not a
 254      * valid value for the specified {@code openType}, or one value in
 255      * {@code legalValues} is not valid for the specified {@code
 256      * openType}, or {@code defaultValue} is non null and {@code
 257      * openType} is an {@code ArrayType} or a {@code TabularType}, or
 258      * {@code legalValues} is non null and non empty and {@code
 259      * openType} is an {@code ArrayType} or a {@code TabularType}, or
 260      * {@code legalValues} is non null and non empty and {@code
 261      * defaultValue} is not contained in {@code legalValues}.
 262      */
 263     public <T> OpenMBeanParameterInfoSupport(String   name,
 264                                              String   description,
 265                                              OpenType<T> openType,
 266                                              T        defaultValue,
 267                                              T[]      legalValues)
 268             throws OpenDataException {
 269         this(name, description, openType,
 270              defaultValue, legalValues, null, null);
 271     }
 272 
 273 
 274     /**
 275      * Constructs an {@code OpenMBeanParameterInfoSupport} instance,
 276      * which describes the parameter used in one or more operations or
 277      * constructors of a class of open MBeans, with the specified
 278      * {@code name}, {@code openType}, {@code description}, {@code
 279      * defaultValue}, {@code minValue} and {@code maxValue}.
 280      *
 281      * It is possible to specify minimal and maximal values only for
 282      * an open type whose values are {@code Comparable}.
 283      *
 284      * @param name  cannot be a null or empty string.
 285      *
 286      * @param description  cannot be a null or empty string.
 287      *
 288      * @param openType  cannot be null.
 289      *
 290      * @param defaultValue must be a valid value for the {@code
 291      * openType} specified for this parameter; default value not
 292      * supported for {@code ArrayType} and {@code TabularType}; can be
 293      * null, in which case it means that no default value is set.
 294      *
 295      * @param minValue must be valid for the {@code openType}
 296      * specified for this parameter; can be null, in which case it
 297      * means that no minimal value is set.
 298      *
 299      * @param maxValue must be valid for the {@code openType}
 300      * specified for this parameter; can be null, in which case it
 301      * means that no maximal value is set.
 302      *
 303      * @param <T> allows the compiler to check that the {@code
 304      * defaultValue}, {@code minValue}, and {@code maxValue}, if
 305      * non-null, have the correct Java type for the given {@code
 306      * openType}.
 307      *
 308      * @throws IllegalArgumentException if {@code name} or {@code
 309      * description} are null or empty string, or {@code openType} is
 310      * null.
 311      *
 312      * @throws OpenDataException if {@code defaultValue}, {@code
 313      * minValue} or {@code maxValue} is not a valid value for the
 314      * specified {@code openType}, or {@code defaultValue} is non null
 315      * and {@code openType} is an {@code ArrayType} or a {@code
 316      * TabularType}, or both {@code minValue} and {@code maxValue} are
 317      * non-null and {@code minValue.compareTo(maxValue) > 0} is {@code
 318      * true}, or both {@code defaultValue} and {@code minValue} are
 319      * non-null and {@code minValue.compareTo(defaultValue) > 0} is
 320      * {@code true}, or both {@code defaultValue} and {@code maxValue}
 321      * are non-null and {@code defaultValue.compareTo(maxValue) > 0}
 322      * is {@code true}.
 323      */
 324     public <T> OpenMBeanParameterInfoSupport(String     name,
 325                                              String     description,
 326                                              OpenType<T>   openType,
 327                                              T          defaultValue,
 328                                              Comparable<T> minValue,
 329                                              Comparable<T> maxValue)
 330             throws OpenDataException {
 331         this(name, description, openType,
 332              defaultValue, null, minValue, maxValue);
 333     }
 334 
 335     private <T> OpenMBeanParameterInfoSupport(String name,
 336                                               String description,
 337                                               OpenType<T> openType,
 338                                               T defaultValue,
 339                                               T[] legalValues,
 340                                               Comparable<T> minValue,
 341                                               Comparable<T> maxValue)
 342             throws OpenDataException {
 343         super(name,
 344               (openType == null) ? null : openType.getClassName(),
 345               description,
 346               makeDescriptor(openType,
 347                              defaultValue, legalValues, minValue, maxValue));
 348 
 349         this.openType = openType;
 350 
 351         Descriptor d = getDescriptor();
 352         this.defaultValue = defaultValue;
 353         this.minValue = minValue;
 354         this.maxValue = maxValue;
 355         // We already converted the array into an unmodifiable Set
 356         // in the descriptor.
 357         this.legalValues = (Set<?>) d.getFieldValue("legalValues");
 358 
 359         check(this);
 360     }
 361 
 362     /**
 363      * An object serialized in a version of the API before Descriptors were
 364      * added to this class will have an empty or null Descriptor.
 365      * For consistency with our
 366      * behavior in this version, we must replace the object with one
 367      * where the Descriptors reflect the same values of openType, defaultValue,
 368      * etc.
 369      **/
 370     private Object readResolve() {
 371         if (getDescriptor().getFieldNames().length == 0) {
 372             // This noise allows us to avoid "unchecked" warnings without
 373             // having to suppress them explicitly.
 374             OpenType<Object> xopenType = cast(openType);
 375             Set<Object> xlegalValues = cast(legalValues);
 376             Comparable<Object> xminValue = cast(minValue);
 377             Comparable<Object> xmaxValue = cast(maxValue);
 378             return new OpenMBeanParameterInfoSupport(
 379                     name, description, openType,
 380                     makeDescriptor(xopenType, defaultValue, xlegalValues,
 381                                    xminValue, xmaxValue));
 382         } else
 383             return this;
 384     }
 385 
 386     /**
 387      * Returns the open type for the values of the parameter described
 388      * by this {@code OpenMBeanParameterInfoSupport} instance.
 389      */
 390     public OpenType<?> getOpenType() {
 391         return openType;
 392     }
 393 
 394     /**
 395      * Returns the default value for the parameter described by this
 396      * {@code OpenMBeanParameterInfoSupport} instance, if specified,
 397      * or {@code null} otherwise.
 398      */
 399     public Object getDefaultValue() {
 400 
 401         // Special case for ArrayType and TabularType
 402         // [JF] TODO: clone it so that it cannot be altered,
 403         // [JF] TODO: if we decide to support defaultValue as an array itself.
 404         // [JF] As of today (oct 2000) it is not supported so
 405         // defaultValue is null for arrays. Nothing to do.
 406 
 407         return defaultValue;
 408     }
 409 
 410     /**
 411      * Returns an unmodifiable Set of legal values for the parameter
 412      * described by this {@code OpenMBeanParameterInfoSupport}
 413      * instance, if specified, or {@code null} otherwise.
 414      */
 415     public Set<?> getLegalValues() {
 416 
 417         // Special case for ArrayType and TabularType
 418         // [JF] TODO: clone values so that they cannot be altered,
 419         // [JF] TODO: if we decide to support LegalValues as an array itself.
 420         // [JF] As of today (oct 2000) it is not supported so
 421         // legalValues is null for arrays. Nothing to do.
 422 
 423         // Returns our legalValues Set (set was constructed unmodifiable)
 424         return (legalValues);
 425     }
 426 
 427     /**
 428      * Returns the minimal value for the parameter described by this
 429      * {@code OpenMBeanParameterInfoSupport} instance, if specified,
 430      * or {@code null} otherwise.
 431      */
 432     public Comparable<?> getMinValue() {
 433 
 434         // Note: only comparable values have a minValue, so that's not
 435         // the case of arrays and tabulars (always null).
 436 
 437         return minValue;
 438     }
 439 
 440     /**
 441      * Returns the maximal value for the parameter described by this
 442      * {@code OpenMBeanParameterInfoSupport} instance, if specified,
 443      * or {@code null} otherwise.
 444      */
 445     public Comparable<?> getMaxValue() {
 446 
 447         // Note: only comparable values have a maxValue, so that's not
 448         // the case of arrays and tabulars (always null).
 449 
 450         return maxValue;
 451     }
 452 
 453     /**
 454      * Returns {@code true} if this {@code
 455      * OpenMBeanParameterInfoSupport} instance specifies a non-null
 456      * default value for the described parameter, {@code false}
 457      * otherwise.
 458      */
 459     public boolean hasDefaultValue() {
 460 
 461         return (defaultValue != null);
 462     }
 463 
 464     /**
 465      * Returns {@code true} if this {@code
 466      * OpenMBeanParameterInfoSupport} instance specifies a non-null
 467      * set of legal values for the described parameter, {@code false}
 468      * otherwise.
 469      */
 470     public boolean hasLegalValues() {
 471 
 472         return (legalValues != null);
 473     }
 474 
 475     /**
 476      * Returns {@code true} if this {@code
 477      * OpenMBeanParameterInfoSupport} instance specifies a non-null
 478      * minimal value for the described parameter, {@code false}
 479      * otherwise.
 480      */
 481     public boolean hasMinValue() {
 482 
 483         return (minValue != null);
 484     }
 485 
 486     /**
 487      * Returns {@code true} if this {@code
 488      * OpenMBeanParameterInfoSupport} instance specifies a non-null
 489      * maximal value for the described parameter, {@code false}
 490      * otherwise.
 491      */
 492     public boolean hasMaxValue() {
 493 
 494         return (maxValue != null);
 495     }
 496 
 497 
 498     /**
 499      * Tests whether {@code obj} is a valid value for the parameter
 500      * described by this {@code OpenMBeanParameterInfo} instance.
 501      *
 502      * @param obj the object to be tested.
 503      *
 504      * @return {@code true} if {@code obj} is a valid value
 505      * for the parameter described by this
 506      * {@code OpenMBeanParameterInfo} instance,
 507      * {@code false} otherwise.
 508      */
 509     public boolean isValue(Object obj) {
 510         return OpenMBeanAttributeInfoSupport.isValue(this, obj);
 511         // compiler bug? should be able to omit class name here
 512         // also below in toString and hashCode
 513     }
 514 
 515 
 516     /* ***  Commodity methods from java.lang.Object  *** */
 517 
 518 
 519     /**
 520      * <p>Compares the specified {@code obj} parameter with this {@code
 521      * OpenMBeanParameterInfoSupport} instance for equality.</p>
 522      *
 523      * <p>Returns {@code true} if and only if all of the following
 524      * statements are true:
 525      *
 526      * <ul>
 527      * <li>{@code obj} is non null,</li>
 528      * <li>{@code obj} also implements the {@code OpenMBeanParameterInfo}
 529      * interface,</li>
 530      * <li>their names are equal</li>
 531      * <li>their open types are equal</li>
 532      * <li>their default, min, max and legal values are equal.</li>
 533      * </ul>
 534      * This ensures that this {@code equals} method works properly for
 535      * {@code obj} parameters which are different implementations of
 536      * the {@code OpenMBeanParameterInfo} interface.
 537      *
 538      * <p>If {@code obj} also implements {@link DescriptorRead}, then its
 539      * {@link DescriptorRead#getDescriptor() getDescriptor()} method must
 540      * also return the same value as for this object.</p>
 541      *
 542      * @param obj the object to be compared for equality with this
 543      * {@code OpenMBeanParameterInfoSupport} instance.
 544      *
 545      * @return {@code true} if the specified object is equal to this
 546      * {@code OpenMBeanParameterInfoSupport} instance.
 547      */
 548     public boolean equals(Object obj) {
 549         if (!(obj instanceof OpenMBeanParameterInfo))
 550             return false;
 551 
 552         OpenMBeanParameterInfo other = (OpenMBeanParameterInfo) obj;
 553 
 554         return equal(this, other);
 555     }
 556 
 557     /**
 558      * <p>Returns the hash code value for this {@code
 559      * OpenMBeanParameterInfoSupport} instance.</p>
 560      *
 561      * <p>The hash code of an {@code OpenMBeanParameterInfoSupport}
 562      * instance is the sum of the hash codes of all elements of
 563      * information used in {@code equals} comparisons (ie: its name,
 564      * its <i>open type</i>, its default, min, max and legal
 565      * values, and its Descriptor).
 566      *
 567      * <p>This ensures that {@code t1.equals(t2)} implies that {@code
 568      * t1.hashCode()==t2.hashCode()} for any two {@code
 569      * OpenMBeanParameterInfoSupport} instances {@code t1} and {@code
 570      * t2}, as required by the general contract of the method {@link
 571      * Object#hashCode() Object.hashCode()}.
 572      *
 573      * <p>However, note that another instance of a class implementing
 574      * the {@code OpenMBeanParameterInfo} interface may be equal to
 575      * this {@code OpenMBeanParameterInfoSupport} instance as defined
 576      * by {@link #equals(java.lang.Object)}, but may have a different
 577      * hash code if it is calculated differently.
 578      *
 579      * <p>As {@code OpenMBeanParameterInfoSupport} instances are
 580      * immutable, the hash code for this instance is calculated once,
 581      * on the first call to {@code hashCode}, and then the same value
 582      * is returned for subsequent calls.
 583      *
 584      * @return the hash code value for this {@code
 585      * OpenMBeanParameterInfoSupport} instance
 586      */
 587     public int hashCode() {
 588 
 589         // Calculate the hash code value if it has not yet been done
 590         // (ie 1st call to hashCode())
 591         //
 592         if (myHashCode == null)
 593             myHashCode = OpenMBeanAttributeInfoSupport.hashCode(this);
 594 
 595         // return always the same hash code for this instance (immutable)
 596         //
 597         return myHashCode.intValue();
 598     }
 599 
 600     /**
 601      * Returns a string representation of this
 602      * {@code OpenMBeanParameterInfoSupport} instance.
 603      * <p>
 604      * The string representation consists of the name of this class (i.e.
 605      * {@code javax.management.openmbean.OpenMBeanParameterInfoSupport}),
 606      * the string representation of the name and open type of the described
 607      * parameter, the string representation of its default, min, max and legal
 608      * values and the string representation of its descriptor.
 609      * <p>
 610      * As {@code OpenMBeanParameterInfoSupport} instances are immutable,
 611      * the string representation for this instance is calculated once,
 612      * on the first call to {@code toString}, and then the same value
 613      * is returned for subsequent calls.
 614      *
 615      * @return a string representation of this
 616      * {@code OpenMBeanParameterInfoSupport} instance.
 617      */
 618     public String toString() {
 619 
 620         // Calculate the string value if it has not yet been done (ie
 621         // 1st call to toString())
 622         //
 623         if (myToString == null)
 624             myToString = OpenMBeanAttributeInfoSupport.toString(this);
 625 
 626         // return always the same string representation for this
 627         // instance (immutable)
 628         //
 629         return myToString;
 630     }
 631 
 632 }