1. /*
  2. * @(#)MBeanAttributeInfo.java 1.36 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.management;
  8. import java.lang.reflect.Method;
  9. import java.security.AccessController;
  10. import java.security.PrivilegedAction;
  11. import com.sun.jmx.mbeanserver.GetPropertyAction;
  12. /**
  13. * Describes an MBean attribute exposed for management. Instances of
  14. * this class are immutable. Subclasses may be mutable but this is
  15. * not recommended.
  16. *
  17. * @since 1.5
  18. */
  19. public class MBeanAttributeInfo extends MBeanFeatureInfo implements java.io.Serializable, Cloneable {
  20. /* Serial version */
  21. private static final long serialVersionUID;
  22. static {
  23. /* For complicated reasons, the serialVersionUID changed
  24. between JMX 1.0 and JMX 1.1, even though JMX 1.1 did not
  25. have compatibility code for this class. So the
  26. serialization produced by this class with JMX 1.2 and
  27. jmx.serial.form=1.0 is not the same as that produced by
  28. this class with JMX 1.1 and jmx.serial.form=1.0. However,
  29. the serialization without that property is the same, and
  30. that is the only form required by JMX 1.2.
  31. */
  32. long uid = 8644704819898565848L;
  33. try {
  34. PrivilegedAction act = new GetPropertyAction("jmx.serial.form");
  35. String form = (String) AccessController.doPrivileged(act);
  36. if ("1.0".equals(form))
  37. uid = 7043855487133450673L;
  38. } catch (Exception e) {
  39. // OK: exception means no compat with 1.0, too bad
  40. }
  41. serialVersionUID = uid;
  42. }
  43. static final MBeanAttributeInfo[] NO_ATTRIBUTES =
  44. new MBeanAttributeInfo[0];
  45. /**
  46. * @serial The actual attribute type.
  47. */
  48. private final String attributeType;
  49. /**
  50. * @serial The attribute write right.
  51. */
  52. private final boolean isWrite;
  53. /**
  54. * @serial The attribute read right.
  55. */
  56. private final boolean isRead;
  57. /**
  58. * @serial Indicates if this method is a "is"
  59. */
  60. private final boolean is;
  61. /**
  62. * Constructs an <CODE>MBeanAttributeInfo</CODE> object.
  63. *
  64. * @param name The name of the attribute.
  65. * @param type The type or class name of the attribute.
  66. * @param description A human readable description of the attribute.
  67. * @param isReadable True if the attribute has a getter method, false otherwise.
  68. * @param isWritable True if the attribute has a setter method, false otherwise.
  69. * @param isIs True if this attribute has an "is" getter, false otherwise.
  70. */
  71. public MBeanAttributeInfo(String name,
  72. String type,
  73. String description,
  74. boolean isReadable,
  75. boolean isWritable,
  76. boolean isIs)
  77. throws IllegalArgumentException {
  78. super(name, description);
  79. this.attributeType = type;
  80. this.isRead= isReadable;
  81. this.isWrite = isWritable;
  82. if (isIs && !isReadable) {
  83. throw new IllegalArgumentException("Cannot have an \"is\" getter for a non-readable attribute.");
  84. }
  85. if (isIs && (!type.equals("java.lang.Boolean") && (!type.equals("boolean")))) {
  86. throw new IllegalArgumentException("Cannot have an \"is\" getter for a non-boolean attribute.");
  87. }
  88. this.is = isIs;
  89. }
  90. /**
  91. * This constructor takes the name of a simple attribute, and Method
  92. * objects for reading and writing the attribute.
  93. *
  94. * @param name The programmatic name of the attribute.
  95. * @param description A human readable description of the attribute.
  96. * @param getter The method used for reading the attribute value.
  97. * May be null if the property is write-only.
  98. * @param setter The method used for writing the attribute value.
  99. * May be null if the attribute is read-only.
  100. * @exception IntrospectionException There is a consistency
  101. * problem in the definition of this attribute.
  102. */
  103. public MBeanAttributeInfo(String name,
  104. String description,
  105. Method getter,
  106. Method setter) throws IntrospectionException {
  107. this(name,
  108. attributeType(getter, setter),
  109. description,
  110. (getter != null),
  111. (setter != null),
  112. isIs(getter));
  113. }
  114. /**
  115. * <p>Returns a shallow clone of this instance.
  116. * The clone is obtained by simply calling <tt>super.clone()</tt>,
  117. * thus calling the default native shallow cloning mechanism
  118. * implemented by <tt>Object.clone()</tt>.
  119. * No deeper cloning of any internal field is made.</p>
  120. *
  121. * <p>Since this class is immutable, cloning is chiefly of
  122. * interest to subclasses.</p>
  123. */
  124. public Object clone () {
  125. try {
  126. return super.clone() ;
  127. } catch (CloneNotSupportedException e) {
  128. // should not happen as this class is cloneable
  129. return null;
  130. }
  131. }
  132. /**
  133. * Returns the class name of the attribute.
  134. *
  135. * @return the class name.
  136. */
  137. public String getType() {
  138. return attributeType;
  139. }
  140. /**
  141. * Whether the value of the attribute can be read.
  142. *
  143. * @return True if the attribute can be read, false otherwise.
  144. */
  145. public boolean isReadable() {
  146. return isRead;
  147. }
  148. /**
  149. * Whether new values can be written to the attribute.
  150. *
  151. * @return True if the attribute can be written to, false otherwise.
  152. */
  153. public boolean isWritable() {
  154. return isWrite;
  155. }
  156. /**
  157. * Indicates if this attribute has an "is" getter.
  158. *
  159. * @return true if this attribute has an "is" getter.
  160. */
  161. public boolean isIs() {
  162. return is;
  163. }
  164. /**
  165. * Compare this MBeanAttributeInfo to another.
  166. *
  167. * @param o the object to compare to.
  168. *
  169. * @return true iff <code>o</code> is an MBeanAttributeInfo such
  170. * that its {@link #getName()}, {@link #getType()}, {@link
  171. * #getDescription()}, {@link #isReadable()}, {@link
  172. * #isWritable()}, and {@link #isIs()} values are equal (not
  173. * necessarily identical) to those of this MBeanAttributeInfo.
  174. */
  175. public boolean equals(Object o) {
  176. if (o == this)
  177. return true;
  178. if (!(o instanceof MBeanAttributeInfo))
  179. return false;
  180. MBeanAttributeInfo p = (MBeanAttributeInfo) o;
  181. return (p.getName().equals(getName()) &&
  182. p.getType().equals(getType()) &&
  183. p.getDescription().equals(getDescription()) &&
  184. p.isReadable() == isReadable() &&
  185. p.isWritable() == isWritable() &&
  186. p.isIs() == isIs());
  187. }
  188. /* We do not include everything in the hashcode. We assume that
  189. if two operations are different they'll probably have different
  190. names or types. The penalty we pay when this assumption is
  191. wrong should be less than the penalty we would pay if it were
  192. right and we needlessly hashed in the description and parameter
  193. array. */
  194. public int hashCode() {
  195. return getName().hashCode() ^ getType().hashCode();
  196. }
  197. private static boolean isIs(Method getter) {
  198. return (getter != null &&
  199. getter.getName().startsWith("is") &&
  200. (getter.getReturnType().equals(Boolean.TYPE) ||
  201. getter.getReturnType().equals(Boolean.class)));
  202. }
  203. /**
  204. * Finds the type of the attribute.
  205. */
  206. private static String attributeType(Method getter, Method setter)
  207. throws IntrospectionException {
  208. Class type = null;
  209. if (getter != null) {
  210. if (getter.getParameterTypes().length != 0) {
  211. throw new IntrospectionException("bad getter arg count");
  212. }
  213. type = getter.getReturnType();
  214. if (type == Void.TYPE) {
  215. throw new IntrospectionException("getter " + getter.getName() +
  216. " returns void");
  217. }
  218. }
  219. if (setter != null) {
  220. Class params[] = setter.getParameterTypes();
  221. if (params.length != 1) {
  222. throw new IntrospectionException("bad setter arg count");
  223. }
  224. if (type == null)
  225. type = params[0];
  226. else if (type != params[0]) {
  227. throw new IntrospectionException("type mismatch between " +
  228. "getter and setter");
  229. }
  230. }
  231. if (type == null) {
  232. throw new IntrospectionException("getter and setter cannot " +
  233. "both be null");
  234. }
  235. return type.getName();
  236. }
  237. }