blob: 9ce17ea8f0d07685f86adf7675a0cb061d6a0858 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package javax.management.openmbean;
28
29
30// java import
31//
32import java.util.Arrays;
33
34import javax.management.Descriptor;
35import javax.management.ImmutableDescriptor;
36import javax.management.MBeanOperationInfo;
37import javax.management.MBeanParameterInfo;
38
39
40/**
41 * Describes an operation of an Open MBean.
42 *
43 *
44 * @since 1.5
45 */
46public class OpenMBeanOperationInfoSupport
47 extends MBeanOperationInfo
48 implements OpenMBeanOperationInfo {
49
50 /* Serial version */
51 static final long serialVersionUID = 4996859732565369366L;
52
53 /**
54 * @serial The <i>open type</i> of the values returned by the operation
55 * described by this {@link OpenMBeanOperationInfo} instance
56 *
57 */
58 private OpenType<?> returnOpenType;
59
60
61 // As this instance is immutable,
62 // these two values need only be calculated once.
63 private transient Integer myHashCode = null;
64 private transient String myToString = null;
65
66
67 /**
68 * <p>Constructs an {@code OpenMBeanOperationInfoSupport}
69 * instance, which describes the operation of a class of open
70 * MBeans, with the specified {@code name}, {@code description},
71 * {@code signature}, {@code returnOpenType} and {@code
72 * impact}.</p>
73 *
74 * <p>The {@code signature} array parameter is internally copied,
75 * so that subsequent changes to the array referenced by {@code
76 * signature} have no effect on this instance.</p>
77 *
78 * @param name cannot be a null or empty string.
79 *
80 * @param description cannot be a null or empty string.
81 *
82 * @param signature can be null or empty if there are no
83 * parameters to describe.
84 *
85 * @param returnOpenType cannot be null: use {@code
86 * SimpleType.VOID} for operations that return nothing.
87 *
88 * @param impact must be one of {@code ACTION}, {@code
89 * ACTION_INFO}, {@code INFO}, or {@code UNKNOWN}.
90 *
91 * @throws IllegalArgumentException if {@code name} or {@code
92 * description} are null or empty string, or {@code
93 * returnOpenType} is null, or {@code impact} is not one of {@code
94 * ACTION}, {@code ACTION_INFO}, {@code INFO}, or {@code UNKNOWN}.
95 *
96 * @throws ArrayStoreException If {@code signature} is not an
97 * array of instances of a subclass of {@code MBeanParameterInfo}.
98 */
99 public OpenMBeanOperationInfoSupport(String name,
100 String description,
101 OpenMBeanParameterInfo[] signature,
102 OpenType<?> returnOpenType,
103 int impact) {
104 this(name, description, signature, returnOpenType, impact,
105 (Descriptor) null);
106 }
107
108 /**
109 * <p>Constructs an {@code OpenMBeanOperationInfoSupport}
110 * instance, which describes the operation of a class of open
111 * MBeans, with the specified {@code name}, {@code description},
112 * {@code signature}, {@code returnOpenType}, {@code
113 * impact}, and {@code descriptor}.</p>
114 *
115 * <p>The {@code signature} array parameter is internally copied,
116 * so that subsequent changes to the array referenced by {@code
117 * signature} have no effect on this instance.</p>
118 *
119 * @param name cannot be a null or empty string.
120 *
121 * @param description cannot be a null or empty string.
122 *
123 * @param signature can be null or empty if there are no
124 * parameters to describe.
125 *
126 * @param returnOpenType cannot be null: use {@code
127 * SimpleType.VOID} for operations that return nothing.
128 *
129 * @param impact must be one of {@code ACTION}, {@code
130 * ACTION_INFO}, {@code INFO}, or {@code UNKNOWN}.
131 *
132 * @param descriptor The descriptor for the operation. This may
133 * be null, which is equivalent to an empty descriptor.
134 *
135 * @throws IllegalArgumentException if {@code name} or {@code
136 * description} are null or empty string, or {@code
137 * returnOpenType} is null, or {@code impact} is not one of {@code
138 * ACTION}, {@code ACTION_INFO}, {@code INFO}, or {@code UNKNOWN}.
139 *
140 * @throws ArrayStoreException If {@code signature} is not an
141 * array of instances of a subclass of {@code MBeanParameterInfo}.
142 *
143 * @since 1.6
144 */
145 public OpenMBeanOperationInfoSupport(String name,
146 String description,
147 OpenMBeanParameterInfo[] signature,
148 OpenType<?> returnOpenType,
149 int impact,
150 Descriptor descriptor) {
151 super(name,
152 description,
153 arrayCopyCast(signature),
154 // must prevent NPE here - we will throw IAE later on if
155 // returnOpenType is null
156 (returnOpenType == null) ? null : returnOpenType.getClassName(),
157 impact,
158 ImmutableDescriptor.union(descriptor,
159 // must prevent NPE here - we will throw IAE later on if
160 // returnOpenType is null
161 (returnOpenType==null) ? null :returnOpenType.getDescriptor()));
162
163 // check parameters that should not be null or empty
164 // (unfortunately it is not done in superclass :-( ! )
165 //
166 if (name == null || name.trim().equals("")) {
167 throw new IllegalArgumentException("Argument name cannot " +
168 "be null or empty");
169 }
170 if (description == null || description.trim().equals("")) {
171 throw new IllegalArgumentException("Argument description cannot " +
172 "be null or empty");
173 }
174 if (returnOpenType == null) {
175 throw new IllegalArgumentException("Argument returnOpenType " +
176 "cannot be null");
177 }
178
179 if (impact != ACTION && impact != ACTION_INFO && impact != INFO &&
180 impact != UNKNOWN) {
181 throw new IllegalArgumentException("Argument impact can only be " +
182 "one of ACTION, ACTION_INFO, " +
183 "INFO, or UNKNOWN: " + impact);
184 }
185
186 this.returnOpenType = returnOpenType;
187 }
188
189
190 // Converts an array of OpenMBeanParameterInfo objects extending
191 // MBeanParameterInfo into an array of MBeanParameterInfo.
192 //
193 private static MBeanParameterInfo[]
194 arrayCopyCast(OpenMBeanParameterInfo[] src) {
195 if (src == null)
196 return null;
197
198 MBeanParameterInfo[] dst = new MBeanParameterInfo[src.length];
199 System.arraycopy(src, 0, dst, 0, src.length);
200 // may throw an ArrayStoreException
201 return dst;
202 }
203
204 // Converts an array of MBeanParameterInfo objects implementing
205 // OpenMBeanParameterInfo into an array of OpenMBeanParameterInfo.
206 //
207 private static OpenMBeanParameterInfo[]
208 arrayCopyCast(MBeanParameterInfo[] src) {
209 if (src == null)
210 return null;
211
212 OpenMBeanParameterInfo[] dst = new OpenMBeanParameterInfo[src.length];
213 System.arraycopy(src, 0, dst, 0, src.length);
214 // may throw an ArrayStoreException
215 return dst;
216 }
217
218
219 // [JF]: should we add constructor with java.lang.reflect.Method
220 // method parameter ? would need to add consistency check between
221 // OpenType<?> returnOpenType and method.getReturnType().
222
223
224 /**
225 * Returns the <i>open type</i> of the values returned by the
226 * operation described by this {@code OpenMBeanOperationInfo}
227 * instance.
228 */
229 public OpenType<?> getReturnOpenType() {
230
231 return returnOpenType;
232 }
233
234
235
236 /* *** Commodity methods from java.lang.Object *** */
237
238
239 /**
240 * <p>Compares the specified {@code obj} parameter with this
241 * {@code OpenMBeanOperationInfoSupport} instance for
242 * equality.</p>
243 *
244 * <p>Returns {@code true} if and only if all of the following
245 * statements are true:
246 *
247 * <ul>
248 * <li>{@code obj} is non null,</li>
249 * <li>{@code obj} also implements the {@code
250 * OpenMBeanOperationInfo} interface,</li>
251 * <li>their names are equal</li>
252 * <li>their signatures are equal</li>
253 * <li>their return open types are equal</li>
254 * <li>their impacts are equal</li>
255 * </ul>
256 *
257 * This ensures that this {@code equals} method works properly for
258 * {@code obj} parameters which are different implementations of
259 * the {@code OpenMBeanOperationInfo} interface.
260 *
261 * @param obj the object to be compared for equality with this
262 * {@code OpenMBeanOperationInfoSupport} instance;
263 *
264 * @return {@code true} if the specified object is equal to this
265 * {@code OpenMBeanOperationInfoSupport} instance.
266 */
267 public boolean equals(Object obj) {
268
269 // if obj is null, return false
270 //
271 if (obj == null) {
272 return false;
273 }
274
275 // if obj is not a OpenMBeanOperationInfo, return false
276 //
277 OpenMBeanOperationInfo other;
278 try {
279 other = (OpenMBeanOperationInfo) obj;
280 } catch (ClassCastException e) {
281 return false;
282 }
283
284 // Now, really test for equality between this
285 // OpenMBeanOperationInfo implementation and the other:
286 //
287
288 // their Name should be equal
289 if ( ! this.getName().equals(other.getName()) ) {
290 return false;
291 }
292
293 // their Signatures should be equal
294 if ( ! Arrays.equals(this.getSignature(), other.getSignature()) ) {
295 return false;
296 }
297
298 // their return open types should be equal
299 if ( ! this.getReturnOpenType().equals(other.getReturnOpenType()) ) {
300 return false;
301 }
302
303 // their impacts should be equal
304 if ( this.getImpact() != other.getImpact() ) {
305 return false;
306 }
307
308 // All tests for equality were successfull
309 //
310 return true;
311 }
312
313 /**
314 * <p>Returns the hash code value for this {@code
315 * OpenMBeanOperationInfoSupport} instance.</p>
316 *
317 * <p>The hash code of an {@code OpenMBeanOperationInfoSupport}
318 * instance is the sum of the hash codes of all elements of
319 * information used in {@code equals} comparisons (ie: its name,
320 * return open type, impact and signature, where the signature
321 * hashCode is calculated by a call to {@code
322 * java.util.Arrays.asList(this.getSignature).hashCode()}).</p>
323 *
324 * <p>This ensures that {@code t1.equals(t2) } implies that {@code
325 * t1.hashCode()==t2.hashCode() } for any two {@code
326 * OpenMBeanOperationInfoSupport} instances {@code t1} and {@code
327 * t2}, as required by the general contract of the method {@link
328 * Object#hashCode() Object.hashCode()}.</p>
329 *
330 * <p>However, note that another instance of a class implementing
331 * the {@code OpenMBeanOperationInfo} interface may be equal to
332 * this {@code OpenMBeanOperationInfoSupport} instance as defined
333 * by {@link #equals(java.lang.Object)}, but may have a different
334 * hash code if it is calculated differently.</p>
335 *
336 * <p>As {@code OpenMBeanOperationInfoSupport} instances are
337 * immutable, the hash code for this instance is calculated once,
338 * on the first call to {@code hashCode}, and then the same value
339 * is returned for subsequent calls.</p>
340 *
341 * @return the hash code value for this {@code
342 * OpenMBeanOperationInfoSupport} instance
343 */
344 public int hashCode() {
345
346 // Calculate the hash code value if it has not yet been done
347 // (ie 1st call to hashCode())
348 //
349 if (myHashCode == null) {
350 int value = 0;
351 value += this.getName().hashCode();
352 value += Arrays.asList(this.getSignature()).hashCode();
353 value += this.getReturnOpenType().hashCode();
354 value += this.getImpact();
355 myHashCode = new Integer(value);
356 }
357
358 // return always the same hash code for this instance (immutable)
359 //
360 return myHashCode.intValue();
361 }
362
363 /**
364 * <p>Returns a string representation of this {@code
365 * OpenMBeanOperationInfoSupport} instance.</p>
366 *
367 * <p>The string representation consists of the name of this class
368 * (ie {@code
369 * javax.management.openmbean.OpenMBeanOperationInfoSupport}), and
370 * the name, signature, return open type and impact of the
371 * described operation and the string representation of its descriptor.</p>
372 *
373 * <p>As {@code OpenMBeanOperationInfoSupport} instances are
374 * immutable, the string representation for this instance is
375 * calculated once, on the first call to {@code toString}, and
376 * then the same value is returned for subsequent calls.</p>
377 *
378 * @return a string representation of this {@code
379 * OpenMBeanOperationInfoSupport} instance
380 */
381 public String toString() {
382
383 // Calculate the hash code value if it has not yet been done
384 // (ie 1st call to toString())
385 //
386 if (myToString == null) {
387 myToString = new StringBuilder()
388 .append(this.getClass().getName())
389 .append("(name=")
390 .append(this.getName())
391 .append(",signature=")
392 .append(Arrays.asList(this.getSignature()).toString())
393 .append(",return=")
394 .append(this.getReturnOpenType().toString())
395 .append(",impact=")
396 .append(this.getImpact())
397 .append(",descriptor=")
398 .append(this.getDescriptor())
399 .append(")")
400 .toString();
401 }
402
403 // return always the same string representation for this
404 // instance (immutable)
405 //
406 return myToString;
407 }
408
409 /**
410 * An object serialized in a version of the API before Descriptors were
411 * added to this class will have an empty or null Descriptor.
412 * For consistency with our
413 * behavior in this version, we must replace the object with one
414 * where the Descriptors reflect the same value of returned openType.
415 **/
416 private Object readResolve() {
417 if (getDescriptor().getFieldNames().length == 0) {
418 // This constructor will construct the expected default Descriptor.
419 //
420 return new OpenMBeanOperationInfoSupport(
421 name, description, arrayCopyCast(getSignature()),
422 returnOpenType, getImpact());
423 } else
424 return this;
425 }
426
427}