001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package javax.management.openmbean;
009:
010: import java.util.Set;
011: import java.util.HashSet;
012: import java.util.Collections;
013: import java.io.Serializable;
014:
015: import javax.management.MBeanParameterInfo;
016:
017: /**
018: * Describes a parameter used in one or more operations or constructors of an open MBean.
019: *
020: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
021: */
022:
023: public class OpenMBeanParameterInfoSupport extends MBeanParameterInfo
024: implements OpenMBeanParameterInfo, Serializable {
025:
026: /**
027: * @serial The open mbean parameter's <i>open type</i>
028: */
029: private OpenType openType = null;
030:
031: /**
032: * @serial The open mbean parameter's default value
033: */
034: private Object defaultValue = null;
035:
036: /**
037: * @serial The open mbean parameter's legal values. This {@link Set} is unmodifiable
038: */
039: private Set legalValues = null; // to be constructed unmodifiable
040:
041: /**
042: * @serial The open mbean parameter's min value
043: */
044: private Comparable minValue = null;
045:
046: /**
047: * @serial The open mbean parameter's max value
048: */
049: private Comparable maxValue = null;
050:
051: private transient Integer myHashCode = null; // As this instance is immutable, these two values
052: private transient String myToString = null; // need only be calculated once.
053:
054: /**
055: * Constructs an <tt>OpenMBeanParameterInfoSupport</tt> instance, which describes the parameter
056: * used in one or more operations or constructors of a class of open MBeans,
057: * with the specified <var>name</var>, <var>openType</var> and <var>description</var>.
058: *
059: * @param name cannot be a null or empty string.
060: *
061: * @param description cannot be a null or empty string.
062: *
063: * @param openType cannot be null.
064: *
065: * @throws IllegalArgumentException if <var>name</var> or <var>description</var> are null or empty string,
066: * or <var>openType</var> is null.
067: */
068: public OpenMBeanParameterInfoSupport(String name,
069: String description, OpenType openType) {
070:
071: // Construct parent's state
072: //
073: super (name, ((openType == null) ? null : openType
074: .getClassName()), description);
075:
076: // check parameters that should not be null or empty (unfortunately it is not done in superclass :-( ! )
077: //
078: if ((name == null) || (name.trim().equals(""))) {
079: throw new IllegalArgumentException(
080: "Argument name cannot be null or empty.");
081: }
082: if ((description == null) || (description.trim().equals(""))) {
083: throw new IllegalArgumentException(
084: "Argument description cannot be null or empty.");
085: }
086: if (openType == null) {
087: throw new IllegalArgumentException(
088: "Argument openType cannot be null.");
089: }
090:
091: // Initialize this instance's specific state
092: //
093: this .openType = openType;
094: }
095:
096: /**
097: * Constructs an <tt>OpenMBeanParameterInfoSupport</tt> instance, which describes the parameter
098: * used in one or more operations or constructors of a class of open MBeans,
099: * with the specified <var>name</var>, <var>openType</var>, <var>description</var> and <var>defaultValue</var>.
100: *
101: * @param name cannot be a null or empty string.
102: *
103: * @param description cannot be a null or empty string.
104: *
105: * @param openType cannot be null.
106: *
107: * @param defaultValue must be a valid value for the <var>openType</var> specified for this parameter;
108: * default value not supported for <tt>ArrayType</tt> and <tt>TabularType</tt>;
109: * can be null, in which case it means that no default value is set.
110: *
111: * @throws IllegalArgumentException if <var>name</var> or <var>description</var> are null or empty string,
112: * or <var>openType</var> is null.
113: *
114: * @throws OpenDataException if <var>defaultValue</var> is not a valid value for the specified <var>openType</var>,
115: * or <var>defaultValue</var> is non null and
116: * <var>openType</var> is an <tt>ArrayType</tt> or a <tt>TabularType</tt>.
117: */
118: public OpenMBeanParameterInfoSupport(String name,
119: String description, OpenType openType, Object defaultValue)
120: throws OpenDataException {
121:
122: // First check and construct the part regarding name, openType and description
123: //
124: this (name, description, openType);
125:
126: // Check and initialize defaultValue
127: //
128: if (defaultValue != null) {
129: // Default value not supported for ArrayType and TabularType
130: if ((openType.isArray())
131: || (openType instanceof TabularType)) {
132: throw new OpenDataException(
133: "Default value not supported for ArrayType and TabularType.");
134: }
135: // Check defaultValue's class
136: if (!openType.isValue(defaultValue)) {
137: throw new OpenDataException(
138: "Argument defaultValue's class [\""
139: + defaultValue.getClass().getName()
140: + "\"] does not match the one defined in openType[\""
141: + openType.getClassName() + "\"].");
142: }
143: // Then initializes defaultValue:
144: // no need to clone it: apart from arrays and TabularData, basic data types are immutable
145: this .defaultValue = defaultValue;
146: }
147: }
148:
149: /**
150: * Constructs an <tt>OpenMBeanParameterInfoSupport</tt> instance, which describes the parameter
151: * used in one or more operations or constructors of a class of open MBeans,
152: * with the specified <var>name</var>, <var>openType</var>, <var>description</var>,
153: * <var>defaultValue</var> and <var>legalValues</var>.
154: *
155: * The contents of <var>legalValues</var> are internally dumped into an unmodifiable <tt>Set</tt>,
156: * so subsequent modifications of the array referenced by <var>legalValues</var> have no impact on
157: * this <tt>OpenMBeanParameterInfoSupport</tt> instance.
158: *
159: * @param name cannot be a null or empty string.
160: *
161: * @param description cannot be a null or empty string.
162: *
163: * @param openType cannot be null.
164: *
165: * @param defaultValue must be a valid value for the <var>openType</var> specified for this parameter;
166: * default value not supported for <tt>ArrayType</tt> and <tt>TabularType</tt>;
167: * can be null, in which case it means that no default value is set.
168: *
169: * @param legalValues each contained value must be valid for the <var>openType</var> specified for this parameter;
170: * legal values not supported for <tt>ArrayType</tt> and <tt>TabularType</tt>;
171: * can be null or empty.
172: *
173: * @throws IllegalArgumentException if <var>name</var> or <var>description</var> are null or empty string,
174: * or <var>openType</var> is null.
175: *
176: * @throws OpenDataException if <var>defaultValue</var> is not a valid value for the specified <var>openType</var>,
177: * or one value in <var>legalValues</var> is not valid for the specified <var>openType</var>,
178: * or <var>defaultValue</var> is non null and
179: * <var>openType</var> is an <tt>ArrayType</tt> or a <tt>TabularType</tt>,
180: * or <var>legalValues</var> is non null and non empty and
181: * <var>openType</var> is an <tt>ArrayType</tt> or a <tt>TabularType</tt>,
182: * or <var>legalValues</var> is non null and non empty and
183: * <var>defaultValue</var> is not contained in <var>legalValues</var>.
184: */
185: public OpenMBeanParameterInfoSupport(String name,
186: String description, OpenType openType, Object defaultValue,
187: Object[] legalValues) throws OpenDataException {
188:
189: // First check and construct the part regarding name, openType, description and defaultValue
190: //
191: this (name, description, openType, defaultValue);
192:
193: // Check and initialize legalValues
194: //
195: if ((legalValues != null) && (legalValues.length > 0)) {
196: // legalValues not supported for TabularType and arrays
197: if ((openType instanceof TabularType)
198: || (openType.isArray())) {
199: throw new OpenDataException(
200: "Legal values not supported for TabularType and arrays");
201: }
202: // Check legalValues are valid with openType
203: for (int i = 0; i < legalValues.length; i++) {
204: if (!openType.isValue(legalValues[i])) {
205: throw new OpenDataException(
206: "Element legalValues["
207: + i
208: + "]="
209: + legalValues[i]
210: + " is not a valid value for the specified openType ["
211: + openType.toString() + "].");
212: }
213: }
214: // dump the legalValues array content into a Set: ensures uniqueness of elements
215: // (and we could not keep the array reference as array content could be modified by the caller)
216: Set tmpSet = new HashSet(legalValues.length + 1, 1);
217: for (int i = 0; i < legalValues.length; i++) {
218: tmpSet.add(legalValues[i]);
219: }
220: // initializes legalValues as an unmodifiable Set
221: this .legalValues = Collections.unmodifiableSet(tmpSet);
222: }
223:
224: // Check that defaultValue is a legal value
225: //
226: if ((this .hasDefaultValue()) && (this .hasLegalValues())) {
227: if (!this .legalValues.contains(defaultValue)) {
228: throw new OpenDataException(
229: "defaultValue is not contained in legalValues");
230: }
231: }
232:
233: }
234:
235: /**
236: * Constructs an <tt>OpenMBeanParameterInfoSupport</tt> instance, which describes the parameter
237: * used in one or more operations or constructors of a class of open MBeans,
238: * with the specified <var>name</var>, <var>openType</var>, <var>description</var>,
239: * <var>defaultValue</var>, <var>minValue</var> and <var>maxValue</var>.
240: *
241: * It is possible to specify minimal and maximal values only for an open type
242: * whose values are <tt>Comparable</tt>.
243: *
244: * @param name cannot be a null or empty string.
245: *
246: * @param description cannot be a null or empty string.
247: *
248: * @param openType cannot be null.
249: *
250: * @param defaultValue must be a valid value for the <var>openType</var> specified for this parameter;
251: * default value not supported for <tt>ArrayType</tt> and <tt>TabularType</tt>;
252: * can be null, in which case it means that no default value is set.
253: *
254: * @param minValue must be valid for the <var>openType</var> specified for this parameter;
255: * can be null, in which case it means that no minimal value is set.
256: *
257: * @param maxValue must be valid for the <var>openType</var> specified for this parameter;
258: * can be null, in which case it means that no maximal value is set.
259: *
260: * @throws IllegalArgumentException if <var>name</var> or <var>description</var> are null or empty string,
261: * or <var>openType</var> is null.
262: *
263: * @throws OpenDataException if <var>defaultValue</var>, <var>minValue</var> or <var>maxValue</var>
264: * is not a valid value for the specified <var>openType</var>,
265: * or <var>defaultValue</var> is non null and
266: * <var>openType</var> is an <tt>ArrayType</tt> or a <tt>TabularType</tt>,
267: * or both <var>minValue</var> and <var>maxValue</var> are non-null and
268: * <tt>minValue.compareTo(maxValue) > 0</tt> is <tt>true</tt>,
269: * or both <var>defaultValue</var> and <var>minValue</var> are non-null and
270: * <tt>minValue.compareTo(defaultValue) > 0</tt> is <tt>true</tt>,
271: * or both <var>defaultValue</var> and <var>maxValue</var> are non-null and
272: * <tt>defaultValue.compareTo(maxValue) > 0</tt> is <tt>true</tt>.
273: */
274: public OpenMBeanParameterInfoSupport(String name,
275: String description, OpenType openType, Object defaultValue,
276: Comparable minValue, Comparable maxValue)
277: throws OpenDataException {
278:
279: // First check and construct the part regarding name, openType, description and defaultValue
280: //
281: this (name, description, openType, defaultValue);
282:
283: // Check and initialize minValue
284: //(note: no need to worry about Composite, Tabular and arrays as they are not Comparable)
285: //
286: if (minValue != null) {
287: if (!openType.isValue(minValue)) {
288: throw new OpenDataException(
289: "Argument minValue's class [\""
290: + minValue.getClass().getName()
291: + "\"] does not match openType's definition [\""
292: + openType.getClassName() + "\"].");
293: }
294: // then initializes minValue
295: this .minValue = minValue;
296: }
297:
298: // Check and initialize maxValue
299: //(note: no need to worry about Composite, Tabular and arrays as they are not Comparable)
300: //
301: if (maxValue != null) {
302: if (!openType.isValue(maxValue)) {
303: throw new OpenDataException(
304: "Argument maxValue's class [\""
305: + maxValue.getClass().getName()
306: + "\"] does not match openType's definition [\""
307: + openType.getClassName() + "\"].");
308: }
309: // then initializes maxValue
310: this .maxValue = maxValue;
311: }
312:
313: // Check that, if both specified, minValue <= maxValue
314: //
315: if (hasMinValue() && hasMaxValue()) {
316: if (minValue.compareTo(maxValue) > 0) {
317: throw new OpenDataException(
318: "minValue cannot be greater than maxValue.");
319: }
320: }
321:
322: // Check that minValue <= defaultValue <= maxValue
323: //
324: if ((this .hasDefaultValue()) && (this .hasMinValue())) {
325: if (minValue.compareTo(defaultValue) > 0) {
326: throw new OpenDataException(
327: "minValue cannot be greater than defaultValue.");
328: }
329: }
330: if ((this .hasDefaultValue()) && (this .hasMaxValue())) {
331: if (((Comparable) defaultValue).compareTo(maxValue) > 0) {
332: throw new OpenDataException(
333: "defaultValue cannot be greater than maxValue.");
334: }
335: }
336: }
337:
338: /**
339: * Returns the open type for the values of the parameter described by this <tt>OpenMBeanParameterInfoSupport</tt> instance.
340: */
341: public OpenType getOpenType() {
342: return openType;
343: }
344:
345: /**
346: * Returns the default value for the parameter described by this <tt>OpenMBeanParameterInfoSupport</tt> instance,
347: * if specified, or <tt>null</tt> otherwise.
348: */
349: public Object getDefaultValue() {
350:
351: // Special case for ArrayType and TabularType
352: // [JF] TODO: clone it so that it cannot be altered,
353: // [JF] TODO: if we decide to support defaultValue as an array itself.
354: // [JF] As of today (oct 2000) it is not supported so defaultValue is null for arrays. Nothing to do.
355:
356: return defaultValue;
357: }
358:
359: /**
360: * Returns an unmodifiable Set of legal values for the parameter described by this <tt>OpenMBeanParameterInfoSupport</tt> instance,
361: * if specified, or <tt>null</tt> otherwise.
362: */
363: public Set getLegalValues() {
364:
365: // Special case for ArrayType and TabularType
366: // [JF] TODO: clone values so that they cannot be altered,
367: // [JF] TODO: if we decide to support LegalValues as an array itself.
368: // [JF] As of today (oct 2000) it is not supported so legalValues is null for arrays. Nothing to do.
369:
370: // Returns our legalValues Set (set was constructed unmodifiable)
371: return legalValues;
372: }
373:
374: /**
375: * Returns the minimal value for the parameter described by this <tt>OpenMBeanParameterInfoSupport</tt> instance,
376: * if specified, or <tt>null</tt> otherwise.
377: */
378: public Comparable getMinValue() {
379:
380: // Note: only comparable values have a minValue, so that's not the case of arrays and tabulars (always null).
381:
382: return minValue;
383: }
384:
385: /**
386: * Returns the maximal value for the parameter described by this <tt>OpenMBeanParameterInfoSupport</tt> instance,
387: * if specified, or <tt>null</tt> otherwise.
388: */
389: public Comparable getMaxValue() {
390:
391: // Note: only comparable values have a maxValue, so that's not the case of arrays and tabulars (always null).
392:
393: return maxValue;
394: }
395:
396: /**
397: * Returns <tt>true</tt> if this <tt>OpenMBeanParameterInfoSupport</tt> instance specifies a non-null default value
398: * for the described parameter, <tt>false</tt> otherwise.
399: */
400: public boolean hasDefaultValue() {
401:
402: return (defaultValue != null);
403: }
404:
405: /**
406: * Returns <tt>true</tt> if this <tt>OpenMBeanParameterInfoSupport</tt> instance specifies a non-null set of legal values
407: * for the described parameter, <tt>false</tt> otherwise.
408: */
409: public boolean hasLegalValues() {
410:
411: return (legalValues != null);
412: }
413:
414: /**
415: * Returns <tt>true</tt> if this <tt>OpenMBeanParameterInfoSupport</tt> instance specifies a non-null minimal value
416: * for the described parameter, <tt>false</tt> otherwise.
417: */
418: public boolean hasMinValue() {
419:
420: return (minValue != null);
421: }
422:
423: /**
424: * Returns <tt>true</tt> if this <tt>OpenMBeanParameterInfoSupport</tt> instance specifies a non-null maximal value
425: * for the described parameter, <tt>false</tt> otherwise.
426: */
427: public boolean hasMaxValue() {
428:
429: return (maxValue != null);
430: }
431:
432: /**
433: * Tests whether <var>obj</var> is a valid value for the parameter
434: * described by this <code>OpenMBeanParameterInfo</code> instance.
435: *
436: * @param obj the object to be tested.
437: *
438: * @return <code>true</code> if <var>obj</var> is a valid value
439: * for the parameter described by this
440: * <code>OpenMBeanParameterInfo</code> instance,
441: * <code>false</code> otherwise.
442: */
443: public boolean isValue(Object obj) {
444:
445: boolean result;
446:
447: if (hasDefaultValue() && obj == null) {
448: result = true;
449: } else if (!openType.isValue(obj)) {
450: result = false;
451: } else if (hasLegalValues() && !legalValues.contains(obj)) {
452: result = false;
453: } else if (hasMinValue() && (minValue.compareTo(obj) > 0)) {
454: result = false;
455: } else if (hasMaxValue() && (maxValue.compareTo(obj) < 0)) {
456: result = false;
457: } else {
458: result = true;
459: }
460:
461: return result;
462: }
463:
464: /* *** Commodity methods from java.lang.Object *** */
465:
466: /**
467: * Compares the specified <var>obj</var> parameter with this <code>OpenMBeanParameterInfoSupport</code> instance for equality.
468: * <p>
469: * Returns <tt>true</tt> if and only if all of the following statements are true:
470: * <ul>
471: * <li><var>obj</var> is non null,</li>
472: * <li><var>obj</var> also implements the <code>OpenMBeanParameterInfo</code> interface,</li>
473: * <li>their names are equal</li>
474: * <li>their open types are equal</li>
475: * <li>their default, min, max and legal values are equal.</li>
476: * </ul>
477: * This ensures that this <tt>equals</tt> method works properly for <var>obj</var> parameters which are
478: * different implementations of the <code>OpenMBeanParameterInfo</code> interface.
479: * <br>
480: * @param obj the object to be compared for equality with this <code>OpenMBeanParameterInfoSupport</code> instance;
481: *
482: * @return <code>true</code> if the specified object is equal to this <code>OpenMBeanParameterInfoSupport</code> instance.
483: */
484: public boolean equals(Object obj) {
485:
486: // if obj is null, return false
487: //
488: if (obj == null) {
489: return false;
490: }
491:
492: // if obj is not a OpenMBeanParameterInfo, return false
493: //
494: OpenMBeanParameterInfo other;
495: try {
496: other = (OpenMBeanParameterInfo) obj;
497: } catch (ClassCastException e) {
498: return false;
499: }
500:
501: // Now, really test for equality between this OpenMBeanParameterInfo implementation and the other:
502: //
503:
504: // their Name should be equal
505: if (!this .getName().equals(other.getName())) {
506: return false;
507: }
508:
509: // their OpenType should be equal
510: if (!this .getOpenType().equals(other.getOpenType())) {
511: return false;
512: }
513:
514: // their DefaultValue should be equal
515: if (this .hasDefaultValue()) {
516: if (!this .defaultValue.equals(other.getDefaultValue())) {
517: return false;
518: }
519: } else {
520: if (other.hasDefaultValue()) {
521: return false;
522: }
523: }
524:
525: // their MinValue should be equal
526: if (this .hasMinValue()) {
527: if (!this .minValue.equals(other.getMinValue())) {
528: return false;
529: }
530: } else {
531: if (other.hasMinValue()) {
532: return false;
533: }
534: }
535:
536: // their MaxValue should be equal
537: if (this .hasMaxValue()) {
538: if (!this .maxValue.equals(other.getMaxValue())) {
539: return false;
540: }
541: } else {
542: if (other.hasMaxValue()) {
543: return false;
544: }
545: }
546:
547: // their LegalValues should be equal
548: if (this .hasLegalValues()) {
549: if (!this .legalValues.equals(other.getLegalValues())) {
550: return false;
551: }
552: } else {
553: if (other.hasLegalValues()) {
554: return false;
555: }
556: }
557:
558: // All tests for equality were successfull
559: //
560: return true;
561: }
562:
563: /**
564: * Returns the hash code value for this <code>OpenMBeanParameterInfoSupport</code> instance.
565: * <p>
566: * The hash code of an <code>OpenMBeanParameterInfoSupport</code> instance is the sum of the hash codes
567: * of all elements of information used in <code>equals</code> comparisons
568: * (ie: its name, its <i>open type</i>, and its default, min, max and legal values).
569: * <p>
570: * This ensures that <code> t1.equals(t2) </code> implies that <code> t1.hashCode()==t2.hashCode() </code>
571: * for any two <code>OpenMBeanParameterInfoSupport</code> instances <code>t1</code> and <code>t2</code>,
572: * as required by the general contract of the method
573: * {@link <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/Object.html#hashCode()">
574: * <code>Object.hashCode</code> </a>}.
575: * <p>
576: * However, note that another instance of a class implementing the <code>OpenMBeanParameterInfo</code> interface
577: * may be equal to this <code>OpenMBeanParameterInfoSupport</code> instance as defined by {@link #equals(java.lang.Object)},
578: * but may have a different hash code if it is calculated differently.
579: * <p>
580: * As <code>OpenMBeanParameterInfoSupport</code> instances are immutable, the hash code for this instance is calculated once,
581: * on the first call to <code>hashCode</code>, and then the same value is returned for subsequent calls.
582: *
583: * @return the hash code value for this <code>OpenMBeanParameterInfoSupport</code> instance
584: */
585: public int hashCode() {
586:
587: // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
588: //
589: if (myHashCode == null) {
590: int value = 0;
591: value += this .getName().hashCode();
592: value += this .openType.hashCode();
593: if (this .hasDefaultValue()) {
594: value += this .defaultValue.hashCode();
595: }
596: if (this .hasMinValue()) {
597: value += this .minValue.hashCode();
598: }
599: if (this .hasMaxValue()) {
600: value += this .maxValue.hashCode();
601: }
602: if (this .hasLegalValues()) {
603: value += this .legalValues.hashCode();
604: }
605: myHashCode = new Integer(value);
606: }
607:
608: // return always the same hash code for this instance (immutable)
609: //
610: return myHashCode.intValue();
611: }
612:
613: /**
614: * Returns a string representation of this <code>OpenMBeanParameterInfoSupport</code> instance.
615: * <p>
616: * The string representation consists of the name of this class (ie <code>javax.management.openmbean.OpenMBeanParameterInfoSupport</code>),
617: * the string representation of the name and open type of the described parameter,
618: * and the string representation of its default, min, max and legal values.
619: * <p>
620: * As <code>OpenMBeanParameterInfoSupport</code> instances are immutable, the string representation for this instance is calculated once,
621: * on the first call to <code>toString</code>, and then the same value is returned for subsequent calls.
622: *
623: * @return a string representation of this <code>OpenMBeanParameterInfoSupport</code> instance
624: */
625: public String toString() {
626:
627: // Calculate the hash code value if it has not yet been done (ie 1st call to hashCode())
628: //
629: if (myToString == null) {
630: myToString = new StringBuffer().append(
631: this .getClass().getName()).append("(name=").append(
632: this .getName()).append(",openType=").append(
633: this .openType.toString()).append(",default=")
634: .append(String.valueOf(this .defaultValue)).append(
635: ",min=").append(
636: String.valueOf(this .minValue)).append(
637: ",max=").append(
638: String.valueOf(this .maxValue)).append(
639: ",legals=").append(
640: String.valueOf(this .legalValues)).append(
641: ")").toString();
642: }
643:
644: // return always the same string representation for this instance (immutable)
645: //
646: return myToString;
647: }
648:
649: }
|