You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
12 KiB
355 lines
12 KiB
/*
|
|
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.management;
|
|
|
|
import java.lang.reflect.Method;
|
|
import java.security.AccessController;
|
|
|
|
import com.sun.jmx.mbeanserver.GetPropertyAction;
|
|
import com.sun.jmx.mbeanserver.Introspector;
|
|
import java.util.Objects;
|
|
|
|
|
|
/**
|
|
* Describes an MBean attribute exposed for management. Instances of
|
|
* this class are immutable. Subclasses may be mutable but this is
|
|
* not recommended.
|
|
*
|
|
* @since 1.5
|
|
*/
|
|
@SuppressWarnings("serial") // serialVersionUID not constant
|
|
public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable {
|
|
|
|
/* Serial version */
|
|
private static final long serialVersionUID;
|
|
static {
|
|
/* For complicated reasons, the serialVersionUID changed
|
|
between JMX 1.0 and JMX 1.1, even though JMX 1.1 did not
|
|
have compatibility code for this class. So the
|
|
serialization produced by this class with JMX 1.2 and
|
|
jmx.serial.form=1.0 is not the same as that produced by
|
|
this class with JMX 1.1 and jmx.serial.form=1.0. However,
|
|
the serialization without that property is the same, and
|
|
that is the only form required by JMX 1.2.
|
|
*/
|
|
long uid = 8644704819898565848L;
|
|
try {
|
|
GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
|
|
String form = AccessController.doPrivileged(act);
|
|
if ("1.0".equals(form))
|
|
uid = 7043855487133450673L;
|
|
} catch (Exception e) {
|
|
// OK: exception means no compat with 1.0, too bad
|
|
}
|
|
serialVersionUID = uid;
|
|
}
|
|
|
|
static final MBeanAttributeInfo[] NO_ATTRIBUTES =
|
|
new MBeanAttributeInfo[0];
|
|
|
|
/**
|
|
* @serial The actual attribute type.
|
|
*/
|
|
private final String attributeType;
|
|
|
|
/**
|
|
* @serial The attribute write right.
|
|
*/
|
|
private final boolean isWrite;
|
|
|
|
/**
|
|
* @serial The attribute read right.
|
|
*/
|
|
private final boolean isRead;
|
|
|
|
/**
|
|
* @serial Indicates if this method is a "is"
|
|
*/
|
|
private final boolean is;
|
|
|
|
|
|
/**
|
|
* Constructs an <CODE>MBeanAttributeInfo</CODE> object.
|
|
*
|
|
* @param name The name of the attribute.
|
|
* @param type The type or class name of the attribute.
|
|
* @param description A human readable description of the attribute.
|
|
* @param isReadable True if the attribute has a getter method, false otherwise.
|
|
* @param isWritable True if the attribute has a setter method, false otherwise.
|
|
* @param isIs True if this attribute has an "is" getter, false otherwise.
|
|
*
|
|
* @throws IllegalArgumentException if {@code isIs} is true but
|
|
* {@code isReadable} is not, or if {@code isIs} is true and
|
|
* {@code type} is not {@code boolean} or {@code java.lang.Boolean}.
|
|
* (New code should always use {@code boolean} rather than
|
|
* {@code java.lang.Boolean}.)
|
|
*/
|
|
public MBeanAttributeInfo(String name,
|
|
String type,
|
|
String description,
|
|
boolean isReadable,
|
|
boolean isWritable,
|
|
boolean isIs) {
|
|
this(name, type, description, isReadable, isWritable, isIs,
|
|
(Descriptor) null);
|
|
}
|
|
|
|
/**
|
|
* Constructs an <CODE>MBeanAttributeInfo</CODE> object.
|
|
*
|
|
* @param name The name of the attribute.
|
|
* @param type The type or class name of the attribute.
|
|
* @param description A human readable description of the attribute.
|
|
* @param isReadable True if the attribute has a getter method, false otherwise.
|
|
* @param isWritable True if the attribute has a setter method, false otherwise.
|
|
* @param isIs True if this attribute has an "is" getter, false otherwise.
|
|
* @param descriptor The descriptor for the attribute. This may be null
|
|
* which is equivalent to an empty descriptor.
|
|
*
|
|
* @throws IllegalArgumentException if {@code isIs} is true but
|
|
* {@code isReadable} is not, or if {@code isIs} is true and
|
|
* {@code type} is not {@code boolean} or {@code java.lang.Boolean}.
|
|
* (New code should always use {@code boolean} rather than
|
|
* {@code java.lang.Boolean}.)
|
|
*
|
|
* @since 1.6
|
|
*/
|
|
public MBeanAttributeInfo(String name,
|
|
String type,
|
|
String description,
|
|
boolean isReadable,
|
|
boolean isWritable,
|
|
boolean isIs,
|
|
Descriptor descriptor) {
|
|
super(name, description, descriptor);
|
|
|
|
this.attributeType = type;
|
|
this.isRead = isReadable;
|
|
this.isWrite = isWritable;
|
|
if (isIs && !isReadable) {
|
|
throw new IllegalArgumentException("Cannot have an \"is\" getter " +
|
|
"for a non-readable attribute");
|
|
}
|
|
if (isIs && !type.equals("java.lang.Boolean") &&
|
|
!type.equals("boolean")) {
|
|
throw new IllegalArgumentException("Cannot have an \"is\" getter " +
|
|
"for a non-boolean attribute");
|
|
}
|
|
this.is = isIs;
|
|
}
|
|
|
|
/**
|
|
* <p>This constructor takes the name of a simple attribute, and Method
|
|
* objects for reading and writing the attribute. The {@link Descriptor}
|
|
* of the constructed object will include fields contributed by any
|
|
* annotations on the {@code Method} objects that contain the
|
|
* {@link DescriptorKey} meta-annotation.
|
|
*
|
|
* @param name The programmatic name of the attribute.
|
|
* @param description A human readable description of the attribute.
|
|
* @param getter The method used for reading the attribute value.
|
|
* May be null if the property is write-only.
|
|
* @param setter The method used for writing the attribute value.
|
|
* May be null if the attribute is read-only.
|
|
* @exception IntrospectionException There is a consistency
|
|
* problem in the definition of this attribute.
|
|
*/
|
|
public MBeanAttributeInfo(String name,
|
|
String description,
|
|
Method getter,
|
|
Method setter) throws IntrospectionException {
|
|
this(name,
|
|
attributeType(getter, setter),
|
|
description,
|
|
(getter != null),
|
|
(setter != null),
|
|
isIs(getter),
|
|
ImmutableDescriptor.union(Introspector.descriptorForElement(getter),
|
|
Introspector.descriptorForElement(setter)));
|
|
}
|
|
|
|
/**
|
|
* <p>Returns a shallow clone of this instance.
|
|
* The clone is obtained by simply calling <tt>super.clone()</tt>,
|
|
* thus calling the default native shallow cloning mechanism
|
|
* implemented by <tt>Object.clone()</tt>.
|
|
* No deeper cloning of any internal field is made.</p>
|
|
*
|
|
* <p>Since this class is immutable, cloning is chiefly of
|
|
* interest to subclasses.</p>
|
|
*/
|
|
public Object clone () {
|
|
try {
|
|
return super.clone() ;
|
|
} catch (CloneNotSupportedException e) {
|
|
// should not happen as this class is cloneable
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the class name of the attribute.
|
|
*
|
|
* @return the class name.
|
|
*/
|
|
public String getType() {
|
|
return attributeType;
|
|
}
|
|
|
|
/**
|
|
* Whether the value of the attribute can be read.
|
|
*
|
|
* @return True if the attribute can be read, false otherwise.
|
|
*/
|
|
public boolean isReadable() {
|
|
return isRead;
|
|
}
|
|
|
|
/**
|
|
* Whether new values can be written to the attribute.
|
|
*
|
|
* @return True if the attribute can be written to, false otherwise.
|
|
*/
|
|
public boolean isWritable() {
|
|
return isWrite;
|
|
}
|
|
|
|
/**
|
|
* Indicates if this attribute has an "is" getter.
|
|
*
|
|
* @return true if this attribute has an "is" getter.
|
|
*/
|
|
public boolean isIs() {
|
|
return is;
|
|
}
|
|
|
|
public String toString() {
|
|
String access;
|
|
if (isReadable()) {
|
|
if (isWritable())
|
|
access = "read/write";
|
|
else
|
|
access = "read-only";
|
|
} else if (isWritable())
|
|
access = "write-only";
|
|
else
|
|
access = "no-access";
|
|
|
|
return
|
|
getClass().getName() + "[" +
|
|
"description=" + getDescription() + ", " +
|
|
"name=" + getName() + ", " +
|
|
"type=" + getType() + ", " +
|
|
access + ", " +
|
|
(isIs() ? "isIs, " : "") +
|
|
"descriptor=" + getDescriptor() +
|
|
"]";
|
|
}
|
|
|
|
/**
|
|
* Compare this MBeanAttributeInfo to another.
|
|
*
|
|
* @param o the object to compare to.
|
|
*
|
|
* @return true if and only if <code>o</code> is an MBeanAttributeInfo such
|
|
* that its {@link #getName()}, {@link #getType()}, {@link
|
|
* #getDescription()}, {@link #isReadable()}, {@link
|
|
* #isWritable()}, and {@link #isIs()} values are equal (not
|
|
* necessarily identical) to those of this MBeanAttributeInfo.
|
|
*/
|
|
public boolean equals(Object o) {
|
|
if (o == this)
|
|
return true;
|
|
if (!(o instanceof MBeanAttributeInfo))
|
|
return false;
|
|
MBeanAttributeInfo p = (MBeanAttributeInfo) o;
|
|
return (Objects.equals(p.getName(), getName()) &&
|
|
Objects.equals(p.getType(), getType()) &&
|
|
Objects.equals(p.getDescription(), getDescription()) &&
|
|
Objects.equals(p.getDescriptor(), getDescriptor()) &&
|
|
p.isReadable() == isReadable() &&
|
|
p.isWritable() == isWritable() &&
|
|
p.isIs() == isIs());
|
|
}
|
|
|
|
/* We do not include everything in the hashcode. We assume that
|
|
if two operations are different they'll probably have different
|
|
names or types. The penalty we pay when this assumption is
|
|
wrong should be less than the penalty we would pay if it were
|
|
right and we needlessly hashed in the description and parameter
|
|
array. */
|
|
public int hashCode() {
|
|
return Objects.hash(getName(), getType());
|
|
}
|
|
|
|
private static boolean isIs(Method getter) {
|
|
return (getter != null &&
|
|
getter.getName().startsWith("is") &&
|
|
(getter.getReturnType().equals(Boolean.TYPE) ||
|
|
getter.getReturnType().equals(Boolean.class)));
|
|
}
|
|
|
|
/**
|
|
* Finds the type of the attribute.
|
|
*/
|
|
private static String attributeType(Method getter, Method setter)
|
|
throws IntrospectionException {
|
|
Class<?> type = null;
|
|
|
|
if (getter != null) {
|
|
if (getter.getParameterTypes().length != 0) {
|
|
throw new IntrospectionException("bad getter arg count");
|
|
}
|
|
type = getter.getReturnType();
|
|
if (type == Void.TYPE) {
|
|
throw new IntrospectionException("getter " + getter.getName() +
|
|
" returns void");
|
|
}
|
|
}
|
|
|
|
if (setter != null) {
|
|
Class<?> params[] = setter.getParameterTypes();
|
|
if (params.length != 1) {
|
|
throw new IntrospectionException("bad setter arg count");
|
|
}
|
|
if (type == null)
|
|
type = params[0];
|
|
else if (type != params[0]) {
|
|
throw new IntrospectionException("type mismatch between " +
|
|
"getter and setter");
|
|
}
|
|
}
|
|
|
|
if (type == null) {
|
|
throw new IntrospectionException("getter and setter cannot " +
|
|
"both be null");
|
|
}
|
|
|
|
return type.getName();
|
|
}
|
|
|
|
}
|