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