1 /* 2 * Copyright (c) 1999, 2013, 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 package javax.management; 27 28 import com.sun.jmx.mbeanserver.Introspector; 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.Method; 31 import java.util.Arrays; 32 import java.util.Objects; 33 34 /** 35 * Describes a management operation exposed by an MBean. Instances of 36 * this class are immutable. Subclasses may be mutable but this is 37 * not recommended. 38 * 39 * @since 1.5 40 */ 41 public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable { 42 43 /* Serial version */ 44 static final long serialVersionUID = -6178860474881375330L; 45 46 static final MBeanOperationInfo[] NO_OPERATIONS = 47 new MBeanOperationInfo[0]; 48 49 /** 50 * Indicates that the operation is read-like: 51 * it returns information but does not change any state. 52 */ 53 public static final int INFO = 0; 54 55 /** 56 * Indicates that the operation is write-like: it has an effect but does 57 * not return any information from the MBean. 58 */ 59 public static final int ACTION = 1; 60 61 /** 62 * Indicates that the operation is both read-like and write-like: 63 * it has an effect, and it also returns information from the MBean. 64 */ 65 public static final int ACTION_INFO = 2; 66 67 /** 68 * Indicates that the impact of the operation is unknown or cannot be 69 * expressed using one of the other values. 70 */ 71 public static final int UNKNOWN = 3; 72 73 /** 74 * @serial The method's return value. 75 */ 76 private final String type; 77 78 /** 79 * @serial The signature of the method, that is, the class names 80 * of the arguments. 81 */ 82 private final MBeanParameterInfo[] signature; 83 84 /** 85 * @serial The impact of the method, one of 86 * {@code INFO, ACTION, ACTION_INFO, UNKNOWN}. 87 */ 88 private final int impact; 89 90 /** @see MBeanInfo#arrayGettersSafe */ 91 private final transient boolean arrayGettersSafe; 92 93 94 /** 95 * Constructs an {@code MBeanOperationInfo} object. The 96 * {@link Descriptor} of the constructed object will include 97 * fields contributed by any annotations on the {@code Method} 98 * object that contain the {@link DescriptorKey} meta-annotation. 99 * 100 * @param method The {@code java.lang.reflect.Method} object 101 * describing the MBean operation. 102 * @param description A human readable description of the operation. 103 */ 104 public MBeanOperationInfo(String description, Method method) { 105 this(method.getName(), 106 description, 107 methodSignature(method), 108 method.getReturnType().getName(), 109 UNKNOWN, 110 Introspector.descriptorForElement(method)); 111 } 112 113 /** 114 * Constructs an {@code MBeanOperationInfo} object. 115 * 116 * @param name The name of the method. 117 * @param description A human readable description of the operation. 118 * @param signature {@code MBeanParameterInfo} objects 119 * describing the parameters(arguments) of the method. This may be 120 * null with the same effect as a zero-length array. 121 * @param type The type of the method's return value. 122 * @param impact The impact of the method, one of 123 * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, 124 * {@link #UNKNOWN}. 125 */ 126 public MBeanOperationInfo(String name, 127 String description, 128 MBeanParameterInfo[] signature, 129 String type, 130 int impact) { 131 this(name, description, signature, type, impact, (Descriptor) null); 132 } 133 134 /** 135 * Constructs an {@code MBeanOperationInfo} object. 136 * 137 * @param name The name of the method. 138 * @param description A human readable description of the operation. 139 * @param signature {@code MBeanParameterInfo} objects 140 * describing the parameters(arguments) of the method. This may be 141 * null with the same effect as a zero-length array. 142 * @param type The type of the method's return value. 143 * @param impact The impact of the method, one of 144 * {@link #INFO}, {@link #ACTION}, {@link #ACTION_INFO}, 145 * {@link #UNKNOWN}. 146 * @param descriptor The descriptor for the operation. This may be null 147 * which is equivalent to an empty descriptor. 148 * 149 * @since 1.6 150 */ 151 public MBeanOperationInfo(String name, 152 String description, 153 MBeanParameterInfo[] signature, 154 String type, 155 int impact, 156 Descriptor descriptor) { 157 158 super(name, description, descriptor); 159 160 if (signature == null || signature.length == 0) 161 signature = MBeanParameterInfo.NO_PARAMS; 162 else 163 signature = signature.clone(); 164 this.signature = signature; 165 this.type = type; 166 this.impact = impact; 167 this.arrayGettersSafe = 168 MBeanInfo.arrayGettersSafe(this.getClass(), 169 MBeanOperationInfo.class); 170 } 171 172 /** 173 * <p>Returns a shallow clone of this instance. 174 * The clone is obtained by simply calling {@code super.clone()}, 175 * thus calling the default native shallow cloning mechanism 176 * implemented by {@code Object.clone()}. 177 * No deeper cloning of any internal field is made.</p> 178 * 179 * <p>Since this class is immutable, cloning is chiefly of interest 180 * to subclasses.</p> 181 */ 182 @Override 183 public Object clone () { 184 try { 185 return super.clone() ; 186 } catch (CloneNotSupportedException e) { 187 // should not happen as this class is cloneable 188 return null; 189 } 190 } 191 192 /** 193 * Returns the type of the method's return value. 194 * 195 * @return the return type. 196 */ 197 public String getReturnType() { 198 return type; 199 } 200 201 /** 202 * <p>Returns the list of parameters for this operation. Each 203 * parameter is described by an {@code MBeanParameterInfo} 204 * object.</p> 205 * 206 * <p>The returned array is a shallow copy of the internal array, 207 * which means that it is a copy of the internal array of 208 * references to the {@code MBeanParameterInfo} objects but 209 * that each referenced {@code MBeanParameterInfo} object is 210 * not copied.</p> 211 * 212 * @return An array of {@code MBeanParameterInfo} objects. 213 */ 214 public MBeanParameterInfo[] getSignature() { 215 // If MBeanOperationInfo was created in our implementation, 216 // signature cannot be null - because our constructors replace 217 // null with MBeanParameterInfo.NO_PARAMS; 218 // 219 // However, signature could be null if an MBeanOperationInfo is 220 // deserialized from a byte array produced by another implementation. 221 // This is not very likely but possible, since the serial form says 222 // nothing against it. (see 6373150) 223 // 224 if (signature == null) 225 // if signature is null simply return an empty array . 226 // 227 return MBeanParameterInfo.NO_PARAMS; 228 else if (signature.length == 0) 229 return signature; 230 else 231 return signature.clone(); 232 } 233 234 private MBeanParameterInfo[] fastGetSignature() { 235 if (arrayGettersSafe) { 236 // if signature is null simply return an empty array . 237 // see getSignature() above. 238 // 239 if (signature == null) 240 return MBeanParameterInfo.NO_PARAMS; 241 else return signature; 242 } else return getSignature(); 243 } 244 245 /** 246 * Returns the impact of the method, one of 247 * {@code INFO, ACTION, ACTION_INFO, UNKNOWN}. 248 * 249 * @return the impact code. 250 */ 251 public int getImpact() { 252 return impact; 253 } 254 255 @Override 256 public String toString() { 257 String impactString; 258 switch (getImpact()) { 259 case ACTION: impactString = "action"; break; 260 case ACTION_INFO: impactString = "action/info"; break; 261 case INFO: impactString = "info"; break; 262 case UNKNOWN: impactString = "unknown"; break; 263 default: impactString = "(" + getImpact() + ")"; 264 } 265 return getClass().getName() + "[" + 266 "description=" + getDescription() + ", " + 267 "name=" + getName() + ", " + 268 "returnType=" + getReturnType() + ", " + 269 "signature=" + Arrays.asList(fastGetSignature()) + ", " + 270 "impact=" + impactString + ", " + 271 "descriptor=" + getDescriptor() + 272 "]"; 273 } 274 275 /** 276 * Compare this MBeanOperationInfo to another. 277 * 278 * @param o the object to compare to. 279 * 280 * @return true if and only if {@code o} is an MBeanOperationInfo such 281 * that its {@link #getName()}, {@link #getReturnType()}, {@link 282 * #getDescription()}, {@link #getImpact()}, {@link #getDescriptor()} 283 * and {@link #getSignature()} values are equal (not necessarily identical) 284 * to those of this MBeanConstructorInfo. Two signature arrays 285 * are equal if their elements are pairwise equal. 286 */ 287 @Override 288 public boolean equals(Object o) { 289 if (o == this) 290 return true; 291 if (!(o instanceof MBeanOperationInfo)) 292 return false; 293 MBeanOperationInfo p = (MBeanOperationInfo) o; 294 return (Objects.equals(p.getName(), getName()) && 295 Objects.equals(p.getReturnType(), getReturnType()) && 296 Objects.equals(p.getDescription(), getDescription()) && 297 p.getImpact() == getImpact() && 298 Arrays.equals(p.fastGetSignature(), fastGetSignature()) && 299 Objects.equals(p.getDescriptor(), getDescriptor())); 300 } 301 302 /* We do not include everything in the hashcode. We assume that 303 if two operations are different they'll probably have different 304 names or types. The penalty we pay when this assumption is 305 wrong should be less than the penalty we would pay if it were 306 right and we needlessly hashed in the description and the 307 parameter array. */ 308 @Override 309 public int hashCode() { 310 return Objects.hash(getName(), getReturnType()); 311 } 312 313 private static MBeanParameterInfo[] methodSignature(Method method) { 314 final Class<?>[] classes = method.getParameterTypes(); 315 final Annotation[][] annots = method.getParameterAnnotations(); 316 return parameters(classes, annots); 317 } 318 319 static MBeanParameterInfo[] parameters(Class<?>[] classes, 320 Annotation[][] annots) { 321 final MBeanParameterInfo[] params = 322 new MBeanParameterInfo[classes.length]; 323 assert(classes.length == annots.length); 324 325 for (int i = 0; i < classes.length; i++) { 326 Descriptor d = Introspector.descriptorForAnnotations(annots[i]); 327 final String pn = "p" + (i + 1); 328 params[i] = 329 new MBeanParameterInfo(pn, classes[i].getName(), "", d); 330 } 331 332 return params; 333 } 334 }