1 /* 2 * Copyright (c) 2000, 2008, 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.Arrays; 33 import java.util.HashSet; 34 35 import javax.management.Descriptor; 36 import javax.management.MBeanAttributeInfo; 37 import javax.management.MBeanConstructorInfo; 38 import javax.management.MBeanInfo; 39 import javax.management.MBeanNotificationInfo; 40 import javax.management.MBeanOperationInfo; 41 42 /** 43 * The {@code OpenMBeanInfoSupport} class describes the management 44 * information of an <i>open MBean</i>: it is a subclass of {@link 45 * javax.management.MBeanInfo}, and it implements the {@link 46 * OpenMBeanInfo} interface. Note that an <i>open MBean</i> is 47 * recognized as such if its {@code getMBeanInfo()} method returns an 48 * instance of a class which implements the OpenMBeanInfo interface, 49 * typically {@code OpenMBeanInfoSupport}. 50 * 51 * 52 * @since 1.5 53 */ 54 public class OpenMBeanInfoSupport 55 extends MBeanInfo 56 implements OpenMBeanInfo { 57 58 /* Serial version */ 59 static final long serialVersionUID = 4349395935420511492L; 60 61 // As this instance is immutable, these two values 62 // 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 OpenMBeanInfoSupport} instance, which 69 * describes a class of open MBeans with the specified {@code 70 * className}, {@code description}, {@code openAttributes}, {@code 71 * openConstructors} , {@code openOperations} and {@code 72 * notifications}.</p> 73 * 74 * <p>The {@code openAttributes}, {@code openConstructors}, 75 * {@code openOperations} and {@code notifications} 76 * array parameters are internally copied, so that subsequent changes 77 * to the arrays referenced by these parameters have no effect on this 78 * instance.</p> 79 * 80 * @param className The fully qualified Java class name of the 81 * open MBean described by this <CODE>OpenMBeanInfoSupport</CODE> 82 * instance. 83 * 84 * @param description A human readable description of the open 85 * MBean described by this <CODE>OpenMBeanInfoSupport</CODE> 86 * instance. 87 * 88 * @param openAttributes The list of exposed attributes of the 89 * described open MBean; Must be an array of instances of a 90 * subclass of {@code MBeanAttributeInfo}, typically {@code 91 * OpenMBeanAttributeInfoSupport}. 92 * 93 * @param openConstructors The list of exposed public constructors 94 * of the described open MBean; Must be an array of instances of a 95 * subclass of {@code MBeanConstructorInfo}, typically {@code 96 * OpenMBeanConstructorInfoSupport}. 97 * 98 * @param openOperations The list of exposed operations of the 99 * described open MBean. Must be an array of instances of a 100 * subclass of {@code MBeanOperationInfo}, typically {@code 101 * OpenMBeanOperationInfoSupport}. 102 * 103 * @param notifications The list of notifications emitted by the 104 * described open MBean. 105 * 106 * @throws ArrayStoreException If {@code openAttributes}, {@code 107 * openConstructors} or {@code openOperations} is not an array of 108 * instances of a subclass of {@code MBeanAttributeInfo}, {@code 109 * MBeanConstructorInfo} or {@code MBeanOperationInfo} 110 * respectively. 111 */ 112 public OpenMBeanInfoSupport(String className, 113 String description, 114 OpenMBeanAttributeInfo[] openAttributes, 115 OpenMBeanConstructorInfo[] openConstructors, 116 OpenMBeanOperationInfo[] openOperations, 117 MBeanNotificationInfo[] notifications) { 118 this(className, description, 119 openAttributes, openConstructors, openOperations, notifications, 120 (Descriptor) null); 121 } 122 123 /** 124 * <p>Constructs an {@code OpenMBeanInfoSupport} instance, which 125 * describes a class of open MBeans with the specified {@code 126 * className}, {@code description}, {@code openAttributes}, {@code 127 * openConstructors} , {@code openOperations}, {@code 128 * notifications}, and {@code descriptor}.</p> 129 * 130 * <p>The {@code openAttributes}, {@code openConstructors}, {@code 131 * openOperations} and {@code notifications} array parameters are 132 * internally copied, so that subsequent changes to the arrays 133 * referenced by these parameters have no effect on this 134 * instance.</p> 135 * 136 * @param className The fully qualified Java class name of the 137 * open MBean described by this <CODE>OpenMBeanInfoSupport</CODE> 138 * instance. 139 * 140 * @param description A human readable description of the open 141 * MBean described by this <CODE>OpenMBeanInfoSupport</CODE> 142 * instance. 143 * 144 * @param openAttributes The list of exposed attributes of the 145 * described open MBean; Must be an array of instances of a 146 * subclass of {@code MBeanAttributeInfo}, typically {@code 147 * OpenMBeanAttributeInfoSupport}. 148 * 149 * @param openConstructors The list of exposed public constructors 150 * of the described open MBean; Must be an array of instances of a 151 * subclass of {@code MBeanConstructorInfo}, typically {@code 152 * OpenMBeanConstructorInfoSupport}. 153 * 154 * @param openOperations The list of exposed operations of the 155 * described open MBean. Must be an array of instances of a 156 * subclass of {@code MBeanOperationInfo}, typically {@code 157 * OpenMBeanOperationInfoSupport}. 158 * 159 * @param notifications The list of notifications emitted by the 160 * described open MBean. 161 * 162 * @param descriptor The descriptor for the MBean. This may be null 163 * which is equivalent to an empty descriptor. 164 * 165 * @throws ArrayStoreException If {@code openAttributes}, {@code 166 * openConstructors} or {@code openOperations} is not an array of 167 * instances of a subclass of {@code MBeanAttributeInfo}, {@code 168 * MBeanConstructorInfo} or {@code MBeanOperationInfo} 169 * respectively. 170 * 171 * @since 1.6 172 */ 173 public OpenMBeanInfoSupport(String className, 174 String description, 175 OpenMBeanAttributeInfo[] openAttributes, 176 OpenMBeanConstructorInfo[] openConstructors, 177 OpenMBeanOperationInfo[] openOperations, 178 MBeanNotificationInfo[] notifications, 179 Descriptor descriptor) { 180 super(className, 181 description, 182 attributeArray(openAttributes), 183 constructorArray(openConstructors), 184 operationArray(openOperations), 185 (notifications == null) ? null : notifications.clone(), 186 descriptor); 187 } 188 189 190 private static MBeanAttributeInfo[] 191 attributeArray(OpenMBeanAttributeInfo[] src) { 192 if (src == null) 193 return null; 194 MBeanAttributeInfo[] dst = new MBeanAttributeInfo[src.length]; 195 System.arraycopy(src, 0, dst, 0, src.length); 196 // may throw an ArrayStoreException 197 return dst; 198 } 199 200 private static MBeanConstructorInfo[] 201 constructorArray(OpenMBeanConstructorInfo[] src) { 202 if (src == null) 203 return null; 204 MBeanConstructorInfo[] dst = new MBeanConstructorInfo[src.length]; 205 System.arraycopy(src, 0, dst, 0, src.length); 206 // may throw an ArrayStoreException 207 return dst; 208 } 209 210 private static MBeanOperationInfo[] 211 operationArray(OpenMBeanOperationInfo[] src) { 212 if (src == null) 213 return null; 214 MBeanOperationInfo[] dst = new MBeanOperationInfo[src.length]; 215 System.arraycopy(src, 0, dst, 0, src.length); 216 return dst; 217 } 218 219 220 221 /* *** Commodity methods from java.lang.Object *** */ 222 223 224 /** 225 * <p>Compares the specified {@code obj} parameter with this 226 * {@code OpenMBeanInfoSupport} instance for equality.</p> 227 * 228 * <p>Returns {@code true} if and only if all of the following 229 * statements are true: 230 * 231 * <ul> 232 * <li>{@code obj} is non null,</li> 233 * <li>{@code obj} also implements the {@code OpenMBeanInfo} 234 * interface,</li> 235 * <li>their class names are equal</li> 236 * <li>their infos on attributes, constructors, operations and 237 * notifications are equal</li> 238 * </ul> 239 * 240 * This ensures that this {@code equals} method works properly for 241 * {@code obj} parameters which are different implementations of 242 * the {@code OpenMBeanInfo} interface. 243 * 244 * @param obj the object to be compared for equality with this 245 * {@code OpenMBeanInfoSupport} instance; 246 * 247 * @return {@code true} if the specified object is equal to this 248 * {@code OpenMBeanInfoSupport} instance. 249 */ 250 public boolean equals(Object obj) { 251 252 // if obj is null, return false 253 // 254 if (obj == null) { 255 return false; 256 } 257 258 // if obj is not a OpenMBeanInfo, return false 259 // 260 OpenMBeanInfo other; 261 try { 262 other = (OpenMBeanInfo) obj; 263 } catch (ClassCastException e) { 264 return false; 265 } 266 267 // Now, really test for equality between this OpenMBeanInfo 268 // implementation and the other: 269 // 270 271 // their MBean className should be equal 272 if ( ! this.getClassName().equals(other.getClassName()) ) 273 return false; 274 275 // their infos on attributes should be equal (order not 276 // significant => equality between sets, not arrays or lists) 277 if (!sameArrayContents(this.getAttributes(), other.getAttributes())) 278 return false; 279 280 // their infos on constructors should be equal (order not 281 // significant => equality between sets, not arrays or lists) 282 if (!sameArrayContents(this.getConstructors(), other.getConstructors())) 283 return false; 284 285 // their infos on operations should be equal (order not 286 // significant => equality between sets, not arrays or lists) 287 if (!sameArrayContents(this.getOperations(), other.getOperations())) 288 289 return false; 290 291 // their infos on notifications should be equal (order not 292 // significant => equality between sets, not arrays or lists) 293 if (!sameArrayContents(this.getNotifications(), other.getNotifications())) 294 return false; 295 296 // All tests for equality were successful 297 // 298 return true; 299 } 300 301 private static <T> boolean sameArrayContents(T[] a1, T[] a2) { 302 return (new HashSet<T>(Arrays.asList(a1)) 303 .equals(new HashSet<T>(Arrays.asList(a2)))); 304 } 305 306 /** 307 * <p>Returns the hash code value for this {@code 308 * OpenMBeanInfoSupport} instance.</p> 309 * 310 * <p>The hash code of an {@code OpenMBeanInfoSupport} instance is 311 * the sum of the hash codes of all elements of information used 312 * in {@code equals} comparisons (ie: its class name, and its 313 * infos on attributes, constructors, operations and 314 * notifications, where the hashCode of each of these arrays is 315 * calculated by a call to {@code new 316 * java.util.HashSet(java.util.Arrays.asList(this.getSignature)).hashCode()}).</p> 317 * 318 * <p>This ensures that {@code t1.equals(t2)} implies that {@code 319 * t1.hashCode()==t2.hashCode()} for any two {@code 320 * OpenMBeanInfoSupport} instances {@code t1} and {@code t2}, as 321 * required by the general contract of the method {@link 322 * Object#hashCode() Object.hashCode()}.</p> 323 * 324 * <p>However, note that another instance of a class implementing 325 * the {@code OpenMBeanInfo} interface may be equal to this {@code 326 * OpenMBeanInfoSupport} instance as defined by {@link 327 * #equals(java.lang.Object)}, but may have a different hash code 328 * if it is calculated differently.</p> 329 * 330 * <p>As {@code OpenMBeanInfoSupport} instances are immutable, the 331 * hash code for this instance is calculated once, on the first 332 * call to {@code hashCode}, and then the same value is returned 333 * for subsequent calls.</p> 334 * 335 * @return the hash code value for this {@code 336 * OpenMBeanInfoSupport} instance 337 */ 338 public int hashCode() { 339 340 // Calculate the hash code value if it has not yet been done 341 // (ie 1st call to hashCode()) 342 // 343 if (myHashCode == null) { 344 int value = 0; 345 value += this.getClassName().hashCode(); 346 value += arraySetHash(this.getAttributes()); 347 value += arraySetHash(this.getConstructors()); 348 value += arraySetHash(this.getOperations()); 349 value += arraySetHash(this.getNotifications()); 350 myHashCode = Integer.valueOf(value); 351 } 352 353 // return always the same hash code for this instance (immutable) 354 // 355 return myHashCode.intValue(); 356 } 357 358 private static <T> int arraySetHash(T[] a) { 359 return new HashSet<T>(Arrays.asList(a)).hashCode(); 360 } 361 362 363 364 /** 365 * <p>Returns a string representation of this {@code 366 * OpenMBeanInfoSupport} instance.</p> 367 * 368 * <p>The string representation consists of the name of this class 369 * (ie {@code javax.management.openmbean.OpenMBeanInfoSupport}), 370 * the MBean class name, the string representation of infos on 371 * attributes, constructors, operations and notifications of the 372 * described MBean and the string representation of the descriptor.</p> 373 * 374 * <p>As {@code OpenMBeanInfoSupport} instances are immutable, the 375 * string representation for this instance is calculated once, on 376 * the first call to {@code toString}, and then the same value is 377 * returned for subsequent calls.</p> 378 * 379 * @return a string representation of this {@code 380 * OpenMBeanInfoSupport} instance 381 */ 382 public String toString() { 383 384 // Calculate the string value if it has not yet been done (ie 385 // 1st call to toString()) 386 // 387 if (myToString == null) { 388 myToString = new StringBuilder() 389 .append(this.getClass().getName()) 390 .append("(mbean_class_name=") 391 .append(this.getClassName()) 392 .append(",attributes=") 393 .append(Arrays.asList(this.getAttributes()).toString()) 394 .append(",constructors=") 395 .append(Arrays.asList(this.getConstructors()).toString()) 396 .append(",operations=") 397 .append(Arrays.asList(this.getOperations()).toString()) 398 .append(",notifications=") 399 .append(Arrays.asList(this.getNotifications()).toString()) 400 .append(",descriptor=") 401 .append(this.getDescriptor()) 402 .append(")") 403 .toString(); 404 } 405 406 // return always the same string representation for this 407 // instance (immutable) 408 // 409 return myToString; 410 } 411 412 }