/*
* @(#)OpenMBeanInfoSupport.java 3.29 06/03/15
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package javax.management.openmbean;
// java import
//
import java.util.Arrays;
import java.util.HashSet;
import javax.management.Descriptor;
import javax.management.MBeanInfo;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanNotificationInfo;
/**
* The {@code OpenMBeanInfoSupport} class describes the management
* information of an <i>open MBean</i>: it is a subclass of {@link
* javax.management.MBeanInfo}, and it implements the {@link
* OpenMBeanInfo} interface. Note that an <i>open MBean</i> is
* recognized as such if its {@code getMBeanInfo()} method returns an
* instance of a class which implements the OpenMBeanInfo interface,
* typically {@code OpenMBeanInfoSupport}.
*
* @version 3.29 06/03/15
* @author Sun Microsystems, Inc.
*
* @since 1.5
* @since.unbundled JMX 1.1
*/
public class OpenMBeanInfoSupport extends MBeanInfo
implements OpenMBeanInfo {
/* Serial version */
static final long serialVersionUID = 4349395935420511492L;
// As this instance is immutable, these two values
// need only be calculated once.
private transient Integer myHashCode = null;
private transient String myToString = null;
/**
* <p>Constructs an {@code OpenMBeanInfoSupport} instance, which
* describes a class of open MBeans with the specified {@code
* className}, {@code description}, {@code openAttributes}, {@code
* openConstructors} , {@code openOperations} and {@code
* notifications}.</p>
*
* <p>The {@code openAttributes}, {@code openConstructors},
* {@code openOperations} and {@code notifications}
* array parameters are internally copied, so that subsequent changes
* to the arrays referenced by these parameters have no effect on this
* instance.</p>
*
* @param className The fully qualified Java class name of the
* open MBean described by this <CODE>OpenMBeanInfoSupport</CODE>
* instance.
*
* @param description A human readable description of the open
* MBean described by this <CODE>OpenMBeanInfoSupport</CODE>
* instance.
*
* @param openAttributes The list of exposed attributes of the
* described open MBean; Must be an array of instances of a
* subclass of {@code MBeanAttributeInfo}, typically {@code
* OpenMBeanAttributeInfoSupport}.
*
* @param openConstructors The list of exposed public constructors
* of the described open MBean; Must be an array of instances of a
* subclass of {@code MBeanConstructorInfo}, typically {@code
* OpenMBeanConstructorInfoSupport}.
*
* @param openOperations The list of exposed operations of the
* described open MBean. Must be an array of instances of a
* subclass of {@code MBeanOperationInfo}, typically {@code
* OpenMBeanOperationInfoSupport}.
*
* @param notifications The list of notifications emitted by the
* described open MBean.
*
* @throws ArrayStoreException If {@code openAttributes}, {@code
* openConstructors} or {@code openOperations} is not an array of
* instances of a subclass of {@code MBeanAttributeInfo}, {@code
* MBeanConstructorInfo} or {@code MBeanOperationInfo}
* respectively.
*/
public OpenMBeanInfoSupport(String className,
String description,
OpenMBeanAttributeInfo[] openAttributes,
OpenMBeanConstructorInfo[] openConstructors,
OpenMBeanOperationInfo[] openOperations,
MBeanNotificationInfo[] notifications) {
this(className, description,
openAttributes, openConstructors, openOperations, notifications,
(Descriptor) null);
}
/**
* <p>Constructs an {@code OpenMBeanInfoSupport} instance, which
* describes a class of open MBeans with the specified {@code
* className}, {@code description}, {@code openAttributes}, {@code
* openConstructors} , {@code openOperations}, {@code
* notifications}, and {@code descriptor}.</p>
*
* <p>The {@code openAttributes}, {@code openConstructors}, {@code
* openOperations} and {@code notifications} array parameters are
* internally copied, so that subsequent changes to the arrays
* referenced by these parameters have no effect on this
* instance.</p>
*
* @param className The fully qualified Java class name of the
* open MBean described by this <CODE>OpenMBeanInfoSupport</CODE>
* instance.
*
* @param description A human readable description of the open
* MBean described by this <CODE>OpenMBeanInfoSupport</CODE>
* instance.
*
* @param openAttributes The list of exposed attributes of the
* described open MBean; Must be an array of instances of a
* subclass of {@code MBeanAttributeInfo}, typically {@code
* OpenMBeanAttributeInfoSupport}.
*
* @param openConstructors The list of exposed public constructors
* of the described open MBean; Must be an array of instances of a
* subclass of {@code MBeanConstructorInfo}, typically {@code
* OpenMBeanConstructorInfoSupport}.
*
* @param openOperations The list of exposed operations of the
* described open MBean. Must be an array of instances of a
* subclass of {@code MBeanOperationInfo}, typically {@code
* OpenMBeanOperationInfoSupport}.
*
* @param notifications The list of notifications emitted by the
* described open MBean.
*
* @param descriptor The descriptor for the MBean. This may be null
* which is equivalent to an empty descriptor.
*
* @throws ArrayStoreException If {@code openAttributes}, {@code
* openConstructors} or {@code openOperations} is not an array of
* instances of a subclass of {@code MBeanAttributeInfo}, {@code
* MBeanConstructorInfo} or {@code MBeanOperationInfo}
* respectively.
*
* @since 1.6
*/
public OpenMBeanInfoSupport(String className,
String description,
OpenMBeanAttributeInfo[] openAttributes,
OpenMBeanConstructorInfo[] openConstructors,
OpenMBeanOperationInfo[] openOperations,
MBeanNotificationInfo[] notifications,
Descriptor descriptor) {
super(className,
description,
attributeArray(openAttributes),
constructorArray(openConstructors),
operationArray(openOperations),
(notifications == null) ? null : notifications.clone(),
descriptor);
}
private static MBeanAttributeInfo[]
attributeArray(OpenMBeanAttributeInfo[] src) {
if (src == null)
return null;
MBeanAttributeInfo[] dst = new MBeanAttributeInfo[src.length];
System.arraycopy(src, 0, dst, 0, src.length);
// may throw an ArrayStoreException
return dst;
}
private static MBeanConstructorInfo[]
constructorArray(OpenMBeanConstructorInfo[] src) {
if (src == null)
return null;
MBeanConstructorInfo[] dst = new MBeanConstructorInfo[src.length];
System.arraycopy(src, 0, dst, 0, src.length);
// may throw an ArrayStoreException
return dst;
}
private static MBeanOperationInfo[]
operationArray(OpenMBeanOperationInfo[] src) {
if (src == null)
return null;
MBeanOperationInfo[] dst = new MBeanOperationInfo[src.length];
System.arraycopy(src, 0, dst, 0, src.length);
return dst;
}
/* *** Commodity methods from java.lang.Object *** */
/**
* <p>Compares the specified {@code obj} parameter with this
* {@code OpenMBeanInfoSupport} instance for equality.</p>
*
* <p>Returns {@code true} if and only if all of the following
* statements are true:
*
* <ul>
* <li>{@code obj} is non null,</li>
* <li>{@code obj} also implements the {@code OpenMBeanInfo}
* interface,</li>
* <li>their class names are equal</li>
* <li>their infos on attributes, constructors, operations and
* notifications are equal</li>
* </ul>
*
* This ensures that this {@code equals} method works properly for
* {@code obj} parameters which are different implementations of
* the {@code OpenMBeanInfo} interface.
*
* @param obj the object to be compared for equality with this
* {@code OpenMBeanInfoSupport} instance;
*
* @return {@code true} if the specified object is equal to this
* {@code OpenMBeanInfoSupport} instance.
*/
public boolean equals(Object obj) {
// if obj is null, return false
//
if (obj == null) {
return false;
}
// if obj is not a OpenMBeanInfo, return false
//
OpenMBeanInfo other;
try {
other = (OpenMBeanInfo) obj;
} catch (ClassCastException e) {
return false;
}
// Now, really test for equality between this OpenMBeanInfo
// implementation and the other:
//
// their MBean className should be equal
if ( ! this.getClassName().equals(other.getClassName()) )
return false;
// their infos on attributes should be equal (order not
// significant => equality between sets, not arrays or lists)
if (!sameArrayContents(this.getAttributes(), other.getAttributes()))
return false;
// their infos on constructors should be equal (order not
// significant => equality between sets, not arrays or lists)
if (!sameArrayContents(this.getConstructors(), other.getConstructors()))
return false;
// their infos on operations should be equal (order not
// significant => equality between sets, not arrays or lists)
if (!sameArrayContents(this.getOperations(), other.getOperations()))
return false;
// their infos on notifications should be equal (order not
// significant => equality between sets, not arrays or lists)
if (!sameArrayContents(this.getNotifications(), other.getNotifications()))
return false;
// All tests for equality were successful
//
return true;
}
private static <T> boolean sameArrayContents(T[] a1, T[] a2) {
return (new HashSet<T>(Arrays.asList(a1))
.equals(new HashSet<T>(Arrays.asList(a2))));
}
/**
* <p>Returns the hash code value for this {@code
* OpenMBeanInfoSupport} instance.</p>
*
* <p>The hash code of an {@code OpenMBeanInfoSupport} instance is
* the sum of the hash codes of all elements of information used
* in {@code equals} comparisons (ie: its class name, and its
* infos on attributes, constructors, operations and
* notifications, where the hashCode of each of these arrays is
* calculated by a call to {@code new
* java.util.HashSet(java.util.Arrays.asList(this.getSignature)).hashCode()}).</p>
*
* <p>This ensures that {@code t1.equals(t2)} implies that {@code
* t1.hashCode()==t2.hashCode()} for any two {@code
* OpenMBeanInfoSupport} instances {@code t1} and {@code t2}, as
* required by the general contract of the method {@link
* Object#hashCode() Object.hashCode()}.</p>
*
* <p>However, note that another instance of a class implementing
* the {@code OpenMBeanInfo} interface may be equal to this {@code
* OpenMBeanInfoSupport} instance as defined by {@link
* #equals(java.lang.Object)}, but may have a different hash code
* if it is calculated differently.</p>
*
* <p>As {@code OpenMBeanInfoSupport} instances are immutable, the
* hash code for this instance is calculated once, on the first
* call to {@code hashCode}, and then the same value is returned
* for subsequent calls.</p>
*
* @return the hash code value for this {@code
* OpenMBeanInfoSupport} instance
*/
public int hashCode() {
// Calculate the hash code value if it has not yet been done
// (ie 1st call to hashCode())
//
if (myHashCode == null) {
int value = 0;
value += this.getClassName().hashCode();
value += arraySetHash(this.getAttributes());
value += arraySetHash(this.getConstructors());
value += arraySetHash(this.getOperations());
value += arraySetHash(this.getNotifications());
myHashCode = new Integer(value);
}
// return always the same hash code for this instance (immutable)
//
return myHashCode.intValue();
}
private static <T> int arraySetHash(T[] a) {
return new HashSet<T>(Arrays.asList(a)).hashCode();
}
/**
* <p>Returns a string representation of this {@code
* OpenMBeanInfoSupport} instance.</p>
*
* <p>The string representation consists of the name of this class
* (ie {@code javax.management.openmbean.OpenMBeanInfoSupport}),
* the MBean class name, the string representation of infos on
* attributes, constructors, operations and notifications of the
* described MBean and the string representation of the descriptor.</p>
*
* <p>As {@code OpenMBeanInfoSupport} instances are immutable, the
* string representation for this instance is calculated once, on
* the first call to {@code toString}, and then the same value is
* returned for subsequent calls.</p>
*
* @return a string representation of this {@code
* OpenMBeanInfoSupport} instance
*/
public String toString() {
// Calculate the string value if it has not yet been done (ie
// 1st call to toString())
//
if (myToString == null) {
myToString = new StringBuffer()
.append(this.getClass().getName())
.append("(mbean_class_name=")
.append(this.getClassName())
.append(",attributes=")
.append(Arrays.asList(this.getAttributes()).toString())
.append(",constructors=")
.append(Arrays.asList(this.getConstructors()).toString())
.append(",operations=")
.append(Arrays.asList(this.getOperations()).toString())
.append(",notifications=")
.append(Arrays.asList(this.getNotifications()).toString())
.append(",descriptor=")
.append(this.getDescriptor())
.append(")")
.toString();
}
// return always the same string representation for this
// instance (immutable)
//
return myToString;
}
}