1 /*
2 * Portions Copyright 2000-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 /*
26 * @author IBM Corp.
27 *
28 * Copyright IBM Corp. 1999-2000. All rights reserved.
29 */
30
31 package javax.management.modelmbean;
32
33 import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
34 import com.sun.jmx.mbeanserver.GetPropertyAction;
35
36 import java.io.IOException;
37 import java.io.ObjectInputStream;
38 import java.io.ObjectOutputStream;
39 import java.io.ObjectStreamField;
40 import java.lang.reflect.Method;
41 import java.security.AccessController;
42 import java.security.PrivilegedAction;
43 import java.util.logging.Level;
44
45 import javax.management.Descriptor;
46 import javax.management.DescriptorKey;
47 import javax.management.DescriptorAccess;
48 import javax.management.MBeanAttributeInfo;
49 import javax.management.RuntimeOperationsException;
50
51 /**
52 * The ModelMBeanAttributeInfo object describes an attribute of the ModelMBean.
53 * It is a subclass of MBeanAttributeInfo with the addition of an associated Descriptor
54 * and an implementation of the DescriptorAccess interface.
55 * <P>
56 * The fields in the descriptor are defined, but not limited to, the following: <P>
57 * <PRE>
58 * name : attribute name
59 * descriptorType : must be "attribute"
60 * value : current value for attribute
61 * default : default value for attribute
62 * displayName : name of attribute to be used in displays
63 * getMethod : name of operation descriptor for get method
64 * setMethod : name of operation descriptor for set method
65 * protocolMap : object which implements the Descriptor interface: mappings
66 * must be appropriate for the attribute
67 * and entries can be updated or augmented at runtime.
68 * persistPolicy : OnUpdate|OnTimer|NoMoreOftenThan|OnUnregister|Always|Never
69 * persistPeriod : seconds - frequency of persist cycle. Used when persistPolicy
70 * is "OnTimer" or "NoMoreOftenThan".
71 * currencyTimeLimit : how long value is valid, <0 never, =0 always, >0 seconds
72 * lastUpdatedTimeStamp : when value was set
73 * visibility : 1-4 where 1: always visible, 4: rarely visible
74 * presentationString : xml formatted string to allow presentation of data
75 * </PRE>
76 * The default descriptor contains the name, descriptorType and displayName fields.
77 * The default value of the name and displayName fields is the name of the attribute.
78 *
79 * <p><b>Note:</b> because of inconsistencies in previous versions of
80 * this specification, it is recommended not to use negative or zero
81 * values for <code>currencyTimeLimit</code>. To indicate that a
82 * cached value is never valid, omit the
83 * <code>currencyTimeLimit</code> field. To indicate that it is
84 * always valid, use a very large number for this field.</p>
85 *
86 * <p>The <b>serialVersionUID</b> of this class is <code>6181543027787327345L</code>.
87 *
88 * @since 1.5
89 */
90
91 @SuppressWarnings("serial") // serialVersionUID is not constant
92 public class ModelMBeanAttributeInfo
93 extends MBeanAttributeInfo
94 implements DescriptorAccess {
95
96 // Serialization compatibility stuff:
97 // Two serial forms are supported in this class. The selected form depends
98 // on system property "jmx.serial.form":
99 // - "1.0" for JMX 1.0
100 // - any other value for JMX 1.1 and higher
101 //
102 // Serial version for old serial form
103 private static final long oldSerialVersionUID = 7098036920755973145L;
104 //
105 // Serial version for new serial form
106 private static final long newSerialVersionUID = 6181543027787327345L;
107 //
108 // Serializable fields in old serial form
109 private static final ObjectStreamField[] oldSerialPersistentFields =
110 {
111 new ObjectStreamField("attrDescriptor", Descriptor.class),
112 new ObjectStreamField("currClass", String.class)
113 };
114 //
115 // Serializable fields in new serial form
116 private static final ObjectStreamField[] newSerialPersistentFields =
117 {
118 new ObjectStreamField("attrDescriptor", Descriptor.class)
119 };
120 //
121 // Actual serial version and serial form
122 private static final long serialVersionUID;
123 /**
124 * @serialField attrDescriptor Descriptor The {@link Descriptor}
125 * containing the metadata corresponding to this attribute
126 */
127 private static final ObjectStreamField[] serialPersistentFields;
128 private static boolean compat = false;
129 static {
130 try {
131 GetPropertyAction act = new GetPropertyAction("jmx.serial.form");
132 String form = AccessController.doPrivileged(act);
133 compat = (form != null && form.equals("1.0"));
134 } catch (Exception e) {
135 // OK: No compat with 1.0
136 }
137 if (compat) {
138 serialPersistentFields = oldSerialPersistentFields;
139 serialVersionUID = oldSerialVersionUID;
140 } else {
141 serialPersistentFields = newSerialPersistentFields;
142 serialVersionUID = newSerialVersionUID;
143 }
144 }
145 //
146 // END Serialization compatibility stuff
147
148 /**
149 * @serial The {@link Descriptor} containing the metadata corresponding to
150 * this attribute
151 */
152 private Descriptor attrDescriptor = validDescriptor(null);
153
154 private final static String currClass = "ModelMBeanAttributeInfo";
155
156 /**
157 * Constructs a ModelMBeanAttributeInfo object with a default
158 * descriptor. The {@link Descriptor} of the constructed
159 * object will include fields contributed by any annotations
160 * on the {@code Method} objects that contain the {@link
161 * DescriptorKey} meta-annotation.
162 *
163 * @param name The name of the attribute.
164 * @param description A human readable description of the attribute. Optional.
165 * @param getter The method used for reading the attribute value.
166 * May be null if the property is write-only.
167 * @param setter The method used for writing the attribute value.
168 * May be null if the attribute is read-only.
169 * @exception IntrospectionException There is a consistency
170 * problem in the definition of this attribute.
171 *
172 */
173
174 public ModelMBeanAttributeInfo(String name,
175 String description,
176 Method getter,
177 Method setter)
178 throws javax.management.IntrospectionException {
179 super(name, description, getter, setter);
180
181 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
182 MODELMBEAN_LOGGER.logp(Level.FINER,
183 ModelMBeanAttributeInfo.class.getName(),
184 "ModelMBeanAttributeInfo(" +
185 "String,String,Method,Method)",
186 "Entry", name);
187 }
188
189 attrDescriptor = validDescriptor(null);
190 // put getter and setter methods in operations list
191 // create default descriptor
192
193 }
194
195 /**
196 * Constructs a ModelMBeanAttributeInfo object. The {@link
197 * Descriptor} of the constructed object will include fields
198 * contributed by any annotations on the {@code Method}
199 * objects that contain the {@link DescriptorKey}
200 * meta-annotation.
201 *
202 * @param name The name of the attribute.
203 * @param description A human readable description of the attribute. Optional.
204 * @param getter The method used for reading the attribute value.
205 * May be null if the property is write-only.
206 * @param setter The method used for writing the attribute value.
207 * May be null if the attribute is read-only.
208 * @param descriptor An instance of Descriptor containing the
209 * appropriate metadata for this instance of the Attribute. If
210 * it is null, then a default descriptor will be created. If
211 * the descriptor does not contain all the following fields,
212 * the missing ones are added with their default values:
213 * displayName, name, descriptorType.
214 * @exception IntrospectionException There is a consistency
215 * problem in the definition of this attribute.
216 * @exception RuntimeOperationsException Wraps an
217 * IllegalArgumentException. The descriptor is invalid, or
218 * descriptor field "name" is present but not equal to name
219 * parameter, or descriptor field "descriptorType" is present
220 * but not equal to "attribute".
221 *
222 */
223
224 public ModelMBeanAttributeInfo(String name,
225 String description,
226 Method getter,
227 Method setter,
228 Descriptor descriptor)
229 throws javax.management.IntrospectionException {
230
231 super(name, description, getter, setter);
232 // put getter and setter methods in operations list
233 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
234 MODELMBEAN_LOGGER.logp(Level.FINER,
235 ModelMBeanAttributeInfo.class.getName(),
236 "ModelMBeanAttributeInfo(" +
237 "String,String,Method,Method,Descriptor)",
238 "Entry", name);
239 }
240 attrDescriptor = validDescriptor(descriptor);
241 }
242
243 /**
244 * Constructs a ModelMBeanAttributeInfo object with a default descriptor.
245 *
246 * @param name The name of the attribute
247 * @param type The type or class name of the attribute
248 * @param description A human readable description of the attribute.
249 * @param isReadable True if the attribute has a getter method, false otherwise.
250 * @param isWritable True if the attribute has a setter method, false otherwise.
251 * @param isIs True if the attribute has an "is" getter, false otherwise.
252 *
253 */
254 public ModelMBeanAttributeInfo(String name,
255 String type,
256 String description,
257 boolean isReadable,
258 boolean isWritable,
259 boolean isIs)
260 {
261
262 super(name, type, description, isReadable, isWritable, isIs);
263 // create default descriptor
264 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
265 MODELMBEAN_LOGGER.logp(Level.FINER,
266 ModelMBeanAttributeInfo.class.getName(),
267 "ModelMBeanAttributeInfo(" +
268 "String,String,String,boolean,boolean,boolean)",
269 "Entry", name);
270 }
271 attrDescriptor = validDescriptor(null);
272 }
273
274 /**
275 * Constructs a ModelMBeanAttributeInfo object with a default descriptor.
276 *
277 * @param name The name of the attribute
278 * @param type The type or class name of the attribute
279 * @param description A human readable description of the attribute.
280 * @param isReadable True if the attribute has a getter method, false otherwise.
281 * @param isWritable True if the attribute has a setter method, false otherwise.
282 * @param isIs True if the attribute has an "is" getter, false otherwise.
283 * @param descriptor An instance of Descriptor containing the
284 * appropriate metadata for this instance of the Attribute. If
285 * it is null then a default descriptor will be created. If
286 * the descriptor does not contain all the following fields,
287 * the missing ones are added with their default values:
288 * displayName, name, descriptorType.
289 * @exception RuntimeOperationsException Wraps an
290 * IllegalArgumentException. The descriptor is invalid, or
291 * descriptor field "name" is present but not equal to name
292 * parameter, or descriptor field "descriptorType" is present
293 * but not equal to "attribute".
294 *
295 */
296 public ModelMBeanAttributeInfo(String name,
297 String type,
298 String description,
299 boolean isReadable,
300 boolean isWritable,
301 boolean isIs,
302 Descriptor descriptor)
303 {
304 super(name, type, description, isReadable, isWritable, isIs);
305 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
306 MODELMBEAN_LOGGER.logp(Level.FINER,
307 ModelMBeanAttributeInfo.class.getName(),
308 "ModelMBeanAttributeInfo(String,String,String," +
309 "boolean,boolean,boolean,Descriptor)",
310 "Entry", name);
311 }
312 attrDescriptor = validDescriptor(descriptor);
313 }
314
315 /**
316 * Constructs a new ModelMBeanAttributeInfo object from this
317 * ModelMBeanAttributeInfo Object. A default descriptor will
318 * be created.
319 *
320 * @param inInfo the ModelMBeanAttributeInfo to be duplicated
321 */
322
323 public ModelMBeanAttributeInfo(ModelMBeanAttributeInfo inInfo)
324 {
325 super(inInfo.getName(),
326 inInfo.getType(),
327 inInfo.getDescription(),
328 inInfo.isReadable(),
329 inInfo.isWritable(),
330 inInfo.isIs());
331 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
332 MODELMBEAN_LOGGER.logp(Level.FINER,
333 ModelMBeanAttributeInfo.class.getName(),
334 "ModelMBeanAttributeInfo(ModelMBeanAttributeInfo)",
335 "Entry");
336 }
337 Descriptor newDesc = inInfo.getDescriptor();
338 attrDescriptor = validDescriptor(newDesc);
339 }
340
341 /**
342 * Gets a copy of the associated Descriptor for the
343 * ModelMBeanAttributeInfo.
344 *
345 * @return Descriptor associated with the
346 * ModelMBeanAttributeInfo object.
347 *
348 * @see #setDescriptor
349 */
350
351 public Descriptor getDescriptor() {
352 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
353 MODELMBEAN_LOGGER.logp(Level.FINER,
354 ModelMBeanAttributeInfo.class.getName(),
355 "getDescriptor()", "Entry");
356 }
357 if (attrDescriptor == null) {
358 attrDescriptor = validDescriptor(null);
359 }
360 return((Descriptor)attrDescriptor.clone());
361 }
362
363
364 /**
365 * Sets associated Descriptor (full replace) for the
366 * ModelMBeanAttributeDescriptor. If the new Descriptor is
367 * null, then the associated Descriptor reverts to a default
368 * descriptor. The Descriptor is validated before it is
369 * assigned. If the new Descriptor is invalid, then a
370 * RuntimeOperationsException wrapping an
371 * IllegalArgumentException is thrown.
372 * If the descriptor does not contain all the following fields, the
373 * missing ones are added with
374 * their default values: displayName, name, descriptorType.
375 * @param inDescriptor replaces the Descriptor associated with the
376 * ModelMBeanAttributeInfo
377 *
378 * @exception RuntimeOperationsException Wraps an
379 * IllegalArgumentException for an invalid Descriptor
380 *
381 * @see #getDescriptor
382 */
383 public void setDescriptor(Descriptor inDescriptor) {
384 attrDescriptor = validDescriptor(inDescriptor);
385 }
386
387 /**
388 * Creates and returns a new ModelMBeanAttributeInfo which is a duplicate of this ModelMBeanAttributeInfo.
389 *
390 * @exception RuntimeOperationsException for illegal value for
391 * field Names or field Values. If the descriptor construction
392 * fails for any reason, this exception will be thrown.
393 */
394
395 public Object clone()
396 {
397 if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
398 MODELMBEAN_LOGGER.logp(Level.FINER,
399 ModelMBeanAttributeInfo.class.getName(),
400 "clone()", "Entry");
401 }
402 return(new ModelMBeanAttributeInfo(this));
403 }
404
405 /**
406 * Returns a human-readable version of the
407 * ModelMBeanAttributeInfo instance.
408 */
409 public String toString()
410 {
411 return
412 "ModelMBeanAttributeInfo: " + this.getName() +
413 " ; Description: " + this.getDescription() +
414 " ; Types: " + this.getType() +
415 " ; isReadable: " + this.isReadable() +
416 " ; isWritable: " + this.isWritable() +
417 " ; Descriptor: " + this.getDescriptor();
418 }
419
420
421 /**
422 * Clones the passed in Descriptor, sets default values, and checks for validity.
423 * If the Descriptor is invalid (for instance by having the wrong "name"),
424 * this indicates programming error and a RuntimeOperationsException will be thrown.
425 *
426 * The following fields will be defaulted if they are not already set:
427 * displayName=this.getName(),name=this.getName(),descriptorType = "attribute"
428 *
429 * @param in Descriptor to be checked, or null which is equivalent to
430 * an empty Descriptor.
431 * @exception RuntimeOperationsException if Descriptor is invalid
432 */
433 private Descriptor validDescriptor(final Descriptor in) throws RuntimeOperationsException {
434
435 Descriptor clone;
436 if (in == null) {
437 clone = new DescriptorSupport();
438 MODELMBEAN_LOGGER.finer("Null Descriptor, creating new.");
439 } else {
440 clone = (Descriptor) in.clone();
441 }
442
443 //Setting defaults.
444 if (clone.getFieldValue("name")==null) {
445 clone.setField("name", this.getName());
446 MODELMBEAN_LOGGER.finer("Defaulting Descriptor name to " + this.getName());
447 }
448 if (clone.getFieldValue("descriptorType")==null) {
449 clone.setField("descriptorType", "attribute");
450 MODELMBEAN_LOGGER.finer("Defaulting descriptorType to \"attribute\"");
451 }
452 if (clone.getFieldValue("displayName") == null) {
453 clone.setField("displayName",this.getName());
454 MODELMBEAN_LOGGER.finer("Defaulting Descriptor displayName to " + this.getName());
455 }
456
457 //Checking validity
458 if (!clone.isValid()) {
459 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"),
460 "The isValid() method of the Descriptor object itself returned false,"+
461 "one or more required fields are invalid. Descriptor:" + clone.toString());
462 }
463 if (! ((String)clone.getFieldValue("name")).equalsIgnoreCase(this.getName())) {
464 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"),
465 "The Descriptor \"name\" field does not match the object described. " +
466 " Expected: "+ this.getName() + " , was: " + clone.getFieldValue("name"));
467 }
468
469 if (! ((String)clone.getFieldValue("descriptorType")).equalsIgnoreCase("attribute")) {
470 throw new RuntimeOperationsException(new IllegalArgumentException("Invalid Descriptor argument"),
471 "The Descriptor \"descriptorType\" field does not match the object described. " +
472 " Expected: \"attribute\" ," + " was: " + clone.getFieldValue("descriptorType"));
473 }
474
475 return clone;
476 }
477
478
479 /**
480 * Deserializes a {@link ModelMBeanAttributeInfo} from an {@link ObjectInputStream}.
481 */
482 private void readObject(ObjectInputStream in)
483 throws IOException, ClassNotFoundException {
484 // New serial form ignores extra field "currClass"
485 in.defaultReadObject();
486 }
487
488
489 /**
490 * Serializes a {@link ModelMBeanAttributeInfo} to an {@link ObjectOutputStream}.
491 */
492 private void writeObject(ObjectOutputStream out)
493 throws IOException {
494 if (compat)
495 {
496 // Serializes this instance in the old serial form
497 //
498 ObjectOutputStream.PutField fields = out.putFields();
499 fields.put("attrDescriptor", attrDescriptor);
500 fields.put("currClass", currClass);
501 out.writeFields();
502 }
503 else
504 {
505 // Serializes this instance in the new serial form
506 //
507 out.defaultWriteObject();
508 }
509 }
510
511 }