001 /*
002 * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.management;
027
028 import java.lang.reflect.Method;
029 import java.security.AccessController;
030
031 import com.sun.jmx.mbeanserver.GetPropertyAction;
032 import com.sun.jmx.mbeanserver.Introspector;
033
034 /**
035 * Describes an MBean attribute exposed for management. Instances of
036 * this class are immutable. Subclasses may be mutable but this is
037 * not recommended.
038 *
039 * @since 1.5
040 */
041 @SuppressWarnings("serial")
042 // serialVersionUID not constant
043 public class MBeanAttributeInfo extends MBeanFeatureInfo implements
044 Cloneable {
045
046 /* Serial version */
047 private static final long serialVersionUID;
048 static {
049 /* For complicated reasons, the serialVersionUID changed
050 between JMX 1.0 and JMX 1.1, even though JMX 1.1 did not
051 have compatibility code for this class. So the
052 serialization produced by this class with JMX 1.2 and
053 jmx.serial.form=1.0 is not the same as that produced by
054 this class with JMX 1.1 and jmx.serial.form=1.0. However,
055 the serialization without that property is the same, and
056 that is the only form required by JMX 1.2.
057 */
058 long uid = 8644704819898565848L;
059 try {
060 GetPropertyAction act = new GetPropertyAction(
061 "jmx.serial.form");
062 String form = AccessController.doPrivileged(act);
063 if ("1.0".equals(form))
064 uid = 7043855487133450673L;
065 } catch (Exception e) {
066 // OK: exception means no compat with 1.0, too bad
067 }
068 serialVersionUID = uid;
069 }
070
071 static final MBeanAttributeInfo[] NO_ATTRIBUTES = new MBeanAttributeInfo[0];
072
073 /**
074 * @serial The actual attribute type.
075 */
076 private final String attributeType;
077
078 /**
079 * @serial The attribute write right.
080 */
081 private final boolean isWrite;
082
083 /**
084 * @serial The attribute read right.
085 */
086 private final boolean isRead;
087
088 /**
089 * @serial Indicates if this method is a "is"
090 */
091 private final boolean is;
092
093 /**
094 * Constructs an <CODE>MBeanAttributeInfo</CODE> object.
095 *
096 * @param name The name of the attribute.
097 * @param type The type or class name of the attribute.
098 * @param description A human readable description of the attribute.
099 * @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, String type,
110 String description, boolean isReadable, boolean isWritable,
111 boolean isIs) {
112 this (name, type, description, isReadable, isWritable, isIs,
113 (Descriptor) null);
114 }
115
116 /**
117 * Constructs an <CODE>MBeanAttributeInfo</CODE> object.
118 *
119 * @param name The name of the attribute.
120 * @param type The type or class name of the attribute.
121 * @param description A human readable description of the attribute.
122 * @param isReadable True if the attribute has a getter method, false otherwise.
123 * @param isWritable True if the attribute has a setter method, false otherwise.
124 * @param isIs True if this attribute has an "is" getter, false otherwise.
125 * @param descriptor The descriptor for the attribute. This may be null
126 * which is equivalent to an empty descriptor.
127 *
128 * @throws IllegalArgumentException if {@code isIs} is true but
129 * {@code isReadable} is not, or if {@code isIs} is true and
130 * {@code type} is not {@code boolean} or {@code java.lang.Boolean}.
131 * (New code should always use {@code boolean} rather than
132 * {@code java.lang.Boolean}.)
133 *
134 * @since 1.6
135 */
136 public MBeanAttributeInfo(String name, String type,
137 String description, boolean isReadable, boolean isWritable,
138 boolean isIs, Descriptor descriptor) {
139 super (name, description, descriptor);
140
141 this .attributeType = type;
142 this .isRead = isReadable;
143 this .isWrite = isWritable;
144 if (isIs && !isReadable) {
145 throw new IllegalArgumentException(
146 "Cannot have an \"is\" getter "
147 + "for a non-readable attribute");
148 }
149 if (isIs && !type.equals("java.lang.Boolean")
150 && !type.equals("boolean")) {
151 throw new IllegalArgumentException(
152 "Cannot have an \"is\" getter "
153 + "for a non-boolean attribute");
154 }
155 this .is = isIs;
156 }
157
158 /**
159 * <p>This constructor takes the name of a simple attribute, and Method
160 * objects for reading and writing the attribute. The {@link Descriptor}
161 * of the constructed object will include fields contributed by any
162 * annotations on the {@code Method} objects that contain the
163 * {@link DescriptorKey} meta-annotation.
164 *
165 * @param name The programmatic name of the attribute.
166 * @param description A human readable description of the attribute.
167 * @param getter The method used for reading the attribute value.
168 * May be null if the property is write-only.
169 * @param setter The method used for writing the attribute value.
170 * May be null if the attribute is read-only.
171 * @exception IntrospectionException There is a consistency
172 * problem in the definition of this attribute.
173 */
174 public MBeanAttributeInfo(String name, String description,
175 Method getter, Method setter) throws IntrospectionException {
176 this (name, attributeType(getter, setter), description,
177 (getter != null), (setter != null), isIs(getter),
178 ImmutableDescriptor.union(Introspector
179 .descriptorForElement(getter), Introspector
180 .descriptorForElement(setter)));
181 }
182
183 /**
184 * <p>Returns a shallow clone of this instance.
185 * The clone is obtained by simply calling <tt>super.clone()</tt>,
186 * thus calling the default native shallow cloning mechanism
187 * implemented by <tt>Object.clone()</tt>.
188 * No deeper cloning of any internal field is made.</p>
189 *
190 * <p>Since this class is immutable, cloning is chiefly of
191 * interest to subclasses.</p>
192 */
193 public Object clone() {
194 try {
195 return super .clone();
196 } catch (CloneNotSupportedException e) {
197 // should not happen as this class is cloneable
198 return null;
199 }
200 }
201
202 /**
203 * Returns the class name of the attribute.
204 *
205 * @return the class name.
206 */
207 public String getType() {
208 return attributeType;
209 }
210
211 /**
212 * Whether the value of the attribute can be read.
213 *
214 * @return True if the attribute can be read, false otherwise.
215 */
216 public boolean isReadable() {
217 return isRead;
218 }
219
220 /**
221 * Whether new values can be written to the attribute.
222 *
223 * @return True if the attribute can be written to, false otherwise.
224 */
225 public boolean isWritable() {
226 return isWrite;
227 }
228
229 /**
230 * Indicates if this attribute has an "is" getter.
231 *
232 * @return true if this attribute has an "is" getter.
233 */
234 public boolean isIs() {
235 return is;
236 }
237
238 public String toString() {
239 String access;
240 if (isReadable()) {
241 if (isWritable())
242 access = "read/write";
243 else
244 access = "read-only";
245 } else if (isWritable())
246 access = "write-only";
247 else
248 access = "no-access";
249
250 return getClass().getName() + "[" + "description="
251 + getDescription() + ", " + "name=" + getName() + ", "
252 + "type=" + getType() + ", " + access + ", "
253 + (isIs() ? "isIs, " : "") + "descriptor="
254 + getDescriptor() + "]";
255 }
256
257 /**
258 * Compare this MBeanAttributeInfo to another.
259 *
260 * @param o the object to compare to.
261 *
262 * @return true if and only if <code>o</code> is an MBeanAttributeInfo such
263 * that its {@link #getName()}, {@link #getType()}, {@link
264 * #getDescription()}, {@link #isReadable()}, {@link
265 * #isWritable()}, and {@link #isIs()} values are equal (not
266 * necessarily identical) to those of this MBeanAttributeInfo.
267 */
268 public boolean equals(Object o) {
269 if (o == this )
270 return true;
271 if (!(o instanceof MBeanAttributeInfo))
272 return false;
273 MBeanAttributeInfo p = (MBeanAttributeInfo) o;
274 return (p.getName().equals(getName())
275 && p.getType().equals(getType())
276 && p.getDescription().equals(getDescription())
277 && p.getDescriptor().equals(getDescriptor())
278 && p.isReadable() == isReadable()
279 && p.isWritable() == isWritable() && p.isIs() == isIs());
280 }
281
282 /* We do not include everything in the hashcode. We assume that
283 if two operations are different they'll probably have different
284 names or types. The penalty we pay when this assumption is
285 wrong should be less than the penalty we would pay if it were
286 right and we needlessly hashed in the description and parameter
287 array. */
288 public int hashCode() {
289 return getName().hashCode() ^ getType().hashCode();
290 }
291
292 private static boolean isIs(Method getter) {
293 return (getter != null && getter.getName().startsWith("is") && (getter
294 .getReturnType().equals(Boolean.TYPE) || getter
295 .getReturnType().equals(Boolean.class)));
296 }
297
298 /**
299 * Finds the type of the attribute.
300 */
301 private static String attributeType(Method getter, Method setter)
302 throws IntrospectionException {
303 Class type = null;
304
305 if (getter != null) {
306 if (getter.getParameterTypes().length != 0) {
307 throw new IntrospectionException("bad getter arg count");
308 }
309 type = getter.getReturnType();
310 if (type == Void.TYPE) {
311 throw new IntrospectionException("getter "
312 + getter.getName() + " returns void");
313 }
314 }
315
316 if (setter != null) {
317 Class params[] = setter.getParameterTypes();
318 if (params.length != 1) {
319 throw new IntrospectionException("bad setter arg count");
320 }
321 if (type == null)
322 type = params[0];
323 else if (type != params[0]) {
324 throw new IntrospectionException(
325 "type mismatch between " + "getter and setter");
326 }
327 }
328
329 if (type == null) {
330 throw new IntrospectionException(
331 "getter and setter cannot " + "both be null");
332 }
333
334 return type.getName();
335 }
336
337 }
|