blob: 5b41bb4b63c8d63d6da82b87c2bee7855a9216d9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.management;
27
28import java.lang.reflect.Method;
29import java.security.AccessController;
30
31import com.sun.jmx.mbeanserver.GetPropertyAction;
32import com.sun.jmx.mbeanserver.Introspector;
33
34
35/**
36 * Describes an MBean attribute exposed for management. Instances of
37 * this class are immutable. Subclasses may be mutable but this is
38 * not recommended.
39 *
40 * @since 1.5
41 */
42@SuppressWarnings("serial") // serialVersionUID not constant
43public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable {
44
45 /* Serial version */
46 private static final long serialVersionUID;
47 static {
48 /* For complicated reasons, the serialVersionUID changed
49 between JMX 1.0 and JMX 1.1, even though JMX 1.1 did not
50 have compatibility code for this class. So the
51 serialization produced by this class with JMX 1.2 and
52 jmx.serial.form=1.0 is not the same as that produced by
53 this class with JMX 1.1 and jmx.serial.form=1.0. However,
54 the serialization without that property is the same, and
55 that is the only form required by JMX 1.2.
56 */
57 long uid = 8644704819898565848L;
58 try {
59 GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
60 String form = AccessController.doPrivileged(act);
61 if ("1.0".equals(form))
62 uid = 7043855487133450673L;
63 } catch (Exception e) {
64 // OK: exception means no compat with 1.0, too bad
65 }
66 serialVersionUID = uid;
67 }
68
69 static final MBeanAttributeInfo[] NO_ATTRIBUTES =
70 new MBeanAttributeInfo[0];
71
72 /**
73 * @serial The actual attribute type.
74 */
75 private final String attributeType;
76
77 /**
78 * @serial The attribute write right.
79 */
80 private final boolean isWrite;
81
82 /**
83 * @serial The attribute read right.
84 */
85 private final boolean isRead;
86
87 /**
88 * @serial Indicates if this method is a "is"
89 */
90 private final boolean is;
91
92
93 /**
94 * Constructs an <CODE>MBeanAttributeInfo</CODE> object.
95 *
96 * @param name The name of the attribute.
97 * @param type The type or class name of the attribute.
98 * @param description A human readable description of the attribute.
99 * @param isReadable True if the attribute has a getter method, false otherwise.
100 * @param isWritable True if the attribute has a setter method, false otherwise.
101 * @param isIs True if this attribute has an "is" getter, false otherwise.
102 *
103 * @throws IllegalArgumentException if {@code isIs} is true but
104 * {@code isReadable} is not, or if {@code isIs} is true and
105 * {@code type} is not {@code boolean} or {@code java.lang.Boolean}.
106 * (New code should always use {@code boolean} rather than
107 * {@code java.lang.Boolean}.)
108 */
109 public MBeanAttributeInfo(String name,
110 String type,
111 String description,
112 boolean isReadable,
113 boolean isWritable,
114 boolean isIs) {
115 this(name, type, description, isReadable, isWritable, isIs,
116 (Descriptor) null);
117 }
118
119 /**
120 * Constructs an <CODE>MBeanAttributeInfo</CODE> object.
121 *
122 * @param name The name of the attribute.
123 * @param type The type or class name of the attribute.
124 * @param description A human readable description of the attribute.
125 * @param isReadable True if the attribute has a getter method, false otherwise.
126 * @param isWritable True if the attribute has a setter method, false otherwise.
127 * @param isIs True if this attribute has an "is" getter, false otherwise.
128 * @param descriptor The descriptor for the attribute. This may be null
129 * which is equivalent to an empty descriptor.
130 *
131 * @throws IllegalArgumentException if {@code isIs} is true but
132 * {@code isReadable} is not, or if {@code isIs} is true and
133 * {@code type} is not {@code boolean} or {@code java.lang.Boolean}.
134 * (New code should always use {@code boolean} rather than
135 * {@code java.lang.Boolean}.)
136 *
137 * @since 1.6
138 */
139 public MBeanAttributeInfo(String name,
140 String type,
141 String description,
142 boolean isReadable,
143 boolean isWritable,
144 boolean isIs,
145 Descriptor descriptor) {
146 super(name, description, descriptor);
147
148 this.attributeType = type;
149 this.isRead = isReadable;
150 this.isWrite = isWritable;
151 if (isIs && !isReadable) {
152 throw new IllegalArgumentException("Cannot have an \"is\" getter " +
153 "for a non-readable attribute");
154 }
155 if (isIs && !type.equals("java.lang.Boolean") &&
156 !type.equals("boolean")) {
157 throw new IllegalArgumentException("Cannot have an \"is\" getter " +
158 "for a non-boolean attribute");
159 }
160 this.is = isIs;
161 }
162
163 /**
164 * <p>This constructor takes the name of a simple attribute, and Method
165 * objects for reading and writing the attribute. The {@link Descriptor}
166 * of the constructed object will include fields contributed by any
167 * annotations on the {@code Method} objects that contain the
168 * {@link DescriptorKey} meta-annotation.
169 *
170 * @param name The programmatic name of the attribute.
171 * @param description A human readable description of the attribute.
172 * @param getter The method used for reading the attribute value.
173 * May be null if the property is write-only.
174 * @param setter The method used for writing the attribute value.
175 * May be null if the attribute is read-only.
176 * @exception IntrospectionException There is a consistency
177 * problem in the definition of this attribute.
178 */
179 public MBeanAttributeInfo(String name,
180 String description,
181 Method getter,
182 Method setter) throws IntrospectionException {
183 this(name,
184 attributeType(getter, setter),
185 description,
186 (getter != null),
187 (setter != null),
188 isIs(getter),
189 ImmutableDescriptor.union(Introspector.descriptorForElement(getter),
190 Introspector.descriptorForElement(setter)));
191 }
192
193 /**
194 * <p>Returns a shallow clone of this instance.
195 * The clone is obtained by simply calling <tt>super.clone()</tt>,
196 * thus calling the default native shallow cloning mechanism
197 * implemented by <tt>Object.clone()</tt>.
198 * No deeper cloning of any internal field is made.</p>
199 *
200 * <p>Since this class is immutable, cloning is chiefly of
201 * interest to subclasses.</p>
202 */
203 public Object clone () {
204 try {
205 return super.clone() ;
206 } catch (CloneNotSupportedException e) {
207 // should not happen as this class is cloneable
208 return null;
209 }
210 }
211
212 /**
213 * Returns the class name of the attribute.
214 *
215 * @return the class name.
216 */
217 public String getType() {
218 return attributeType;
219 }
220
221 /**
222 * Whether the value of the attribute can be read.
223 *
224 * @return True if the attribute can be read, false otherwise.
225 */
226 public boolean isReadable() {
227 return isRead;
228 }
229
230 /**
231 * Whether new values can be written to the attribute.
232 *
233 * @return True if the attribute can be written to, false otherwise.
234 */
235 public boolean isWritable() {
236 return isWrite;
237 }
238
239 /**
240 * Indicates if this attribute has an "is" getter.
241 *
242 * @return true if this attribute has an "is" getter.
243 */
244 public boolean isIs() {
245 return is;
246 }
247
248 public String toString() {
249 String access;
250 if (isReadable()) {
251 if (isWritable())
252 access = "read/write";
253 else
254 access = "read-only";
255 } else if (isWritable())
256 access = "write-only";
257 else
258 access = "no-access";
259
260 return
261 getClass().getName() + "[" +
262 "description=" + getDescription() + ", " +
263 "name=" + getName() + ", " +
264 "type=" + getType() + ", " +
265 access + ", " +
266 (isIs() ? "isIs, " : "") +
267 "descriptor=" + getDescriptor() +
268 "]";
269 }
270
271 /**
272 * Compare this MBeanAttributeInfo to another.
273 *
274 * @param o the object to compare to.
275 *
276 * @return true if and only if <code>o</code> is an MBeanAttributeInfo such
277 * that its {@link #getName()}, {@link #getType()}, {@link
278 * #getDescription()}, {@link #isReadable()}, {@link
279 * #isWritable()}, and {@link #isIs()} values are equal (not
280 * necessarily identical) to those of this MBeanAttributeInfo.
281 */
282 public boolean equals(Object o) {
283 if (o == this)
284 return true;
285 if (!(o instanceof MBeanAttributeInfo))
286 return false;
287 MBeanAttributeInfo p = (MBeanAttributeInfo) o;
288 return (p.getName().equals(getName()) &&
289 p.getType().equals(getType()) &&
290 p.getDescription().equals(getDescription()) &&
291 p.getDescriptor().equals(getDescriptor()) &&
292 p.isReadable() == isReadable() &&
293 p.isWritable() == isWritable() &&
294 p.isIs() == isIs());
295 }
296
297 /* We do not include everything in the hashcode. We assume that
298 if two operations are different they'll probably have different
299 names or types. The penalty we pay when this assumption is
300 wrong should be less than the penalty we would pay if it were
301 right and we needlessly hashed in the description and parameter
302 array. */
303 public int hashCode() {
304 return getName().hashCode() ^ getType().hashCode();
305 }
306
307 private static boolean isIs(Method getter) {
308 return (getter != null &&
309 getter.getName().startsWith("is") &&
310 (getter.getReturnType().equals(Boolean.TYPE) ||
311 getter.getReturnType().equals(Boolean.class)));
312 }
313
314 /**
315 * Finds the type of the attribute.
316 */
317 private static String attributeType(Method getter, Method setter)
318 throws IntrospectionException {
319 Class type = null;
320
321 if (getter != null) {
322 if (getter.getParameterTypes().length != 0) {
323 throw new IntrospectionException("bad getter arg count");
324 }
325 type = getter.getReturnType();
326 if (type == Void.TYPE) {
327 throw new IntrospectionException("getter " + getter.getName() +
328 " returns void");
329 }
330 }
331
332 if (setter != null) {
333 Class params[] = setter.getParameterTypes();
334 if (params.length != 1) {
335 throw new IntrospectionException("bad setter arg count");
336 }
337 if (type == null)
338 type = params[0];
339 else if (type != params[0]) {
340 throw new IntrospectionException("type mismatch between " +
341 "getter and setter");
342 }
343 }
344
345 if (type == null) {
346 throw new IntrospectionException("getter and setter cannot " +
347 "both be null");
348 }
349
350 return type.getName();
351 }
352
353}