001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management.modelmbean;
023:
024: import java.io.IOException;
025: import java.io.ObjectInputStream;
026: import java.io.ObjectOutputStream;
027: import java.io.ObjectStreamField;
028: import java.io.StreamCorruptedException;
029: import java.lang.reflect.Method;
030:
031: import javax.management.Descriptor;
032: import javax.management.DescriptorAccess;
033: import javax.management.IntrospectionException;
034: import javax.management.MBeanAttributeInfo;
035: import javax.management.RuntimeOperationsException;
036:
037: import org.jboss.mx.modelmbean.ModelMBeanConstants;
038: import org.jboss.mx.util.Serialization;
039:
040: /**
041: * Represents a Model MBean's management attribute.
042: *
043: * @see javax.management.MBeanAttributeInfo
044: *
045: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
046: * @author <a href="mailto:adrian.brock@happeningtimes.com">Adrian Brock</a>.
047: * @author <a href="mailto:thomas.diesler@jboss.com">Thomas Diesler</a>.
048: * @version $Revision: 57200 $
049: *
050: * <p><b>Revisions:</b>
051: *
052: * <p><b>20020320 Juha Lindfors:</b>
053: * <ul>
054: * <li>toString() implementation</li>
055: *
056: * <li>Changed the default descriptor to include field <tt>currencyTimeLimit</tt>
057: * with a value -1. Since default descriptors do not include method mapping
058: * this automatically caches attribute values in the Model MBean.
059: * </li>
060: * </ul>
061: *
062: * <p><b>20020715 Adrian Brock:</b>
063: * <ul>
064: * <li> Serialization
065: * </ul>
066: */
067: public class ModelMBeanAttributeInfo extends MBeanAttributeInfo
068: implements DescriptorAccess, Cloneable {
069:
070: // Attributes ----------------------------------------------------
071: /**
072: * The descriptor associated with this attribute.
073: */
074: private Descriptor descriptor = null;
075:
076: // Static --------------------------------------------------------
077:
078: private static final long serialVersionUID;
079: private static final ObjectStreamField[] serialPersistentFields;
080:
081: static {
082: switch (Serialization.version) {
083: case Serialization.V1R0:
084: serialVersionUID = 7098036920755973145L;
085: break;
086: default:
087: serialVersionUID = 6181543027787327345L;
088: }
089: serialPersistentFields = new ObjectStreamField[] { new ObjectStreamField(
090: "attrDescriptor", Descriptor.class) };
091: }
092:
093: // Constructors --------------------------------------------------
094: /**
095: * Creates a new attribute info with a default descriptor.
096: *
097: * @param name name of the attribute
098: * @param description human readable description string
099: * @param getter a <tt>Method</tt> instance representing a read method for this attribute
100: * @param setter a <tt>Method</tt> instance representing a write method for this attribute
101: *
102: * @throws IntrospectionException if the accessor methods are not valid for this attribute
103: */
104: public ModelMBeanAttributeInfo(String name, String description,
105: Method getter, Method setter) throws IntrospectionException {
106: // NOTE: This constructor provides the method mapping for
107: // a Model MBean attribute so the 'setMethod' and 'getMethod'
108: // descriptor field should be set, but the javadoc dictates a
109: // default descriptor...?
110:
111: super (name, description, getter, setter);
112: setDescriptor(createDefaultDescriptor());
113: }
114:
115: /**
116: * Creates a new attribute info object. If a <tt>null</tt> or
117: * invalid descriptor is passed as a parameter, a default descriptor will be created
118: * for the attribute.
119: *
120: * @param name name of the attribute
121: * @param description human readable description string
122: * @param getter a <tt>Method</tt> instance representing a read method for this attribute
123: * @param setter a <tt>Method</tt> instance representing a write method for this attribute
124: * @param descriptor a descriptor to associate with this attribute
125: *
126: * @throws IntrospectionException if the accessor methods are not valid for this attribute
127: */
128: public ModelMBeanAttributeInfo(String name, String description,
129: Method getter, Method setter, Descriptor descriptor)
130: throws IntrospectionException {
131: super (name, description, getter, setter);
132: setDescriptor(descriptor);
133: }
134:
135: /**
136: * Creates a new attribute info object with a default descriptor.
137: *
138: * @param name name of the attribute
139: * @param type fully qualified class name of the attribute's type
140: * @param description human readable description string
141: * @param isReadable true if attribute is readable; false otherwise
142: * @param isWritable true if attribute is writable; false otherwise
143: * @param isIs (not used for Model MBeans; false)
144: */
145: public ModelMBeanAttributeInfo(String name, String type,
146: String description, boolean isReadable, boolean isWritable,
147: boolean isIs) {
148: super (name, type, description, isReadable, isWritable, isIs);
149: setDescriptor(createDefaultDescriptor());
150: }
151:
152: /**
153: * Creates a new attribute info object with a given descriptor. If a <tt>null</tt> or invalid
154: * descriptor is passed as a parameter, a default descriptor will be created for the attribute.
155: *
156: * @param name name of the attribute
157: * @param type fully qualified class name of the attribute's type
158: * @param description human readable description string
159: * @param isReadable true if the attribute is readable; false otherwise
160: * @param isWritable true if the attribute is writable; false otherwise
161: * @param isIs (not used for Model MBeans; false)
162: */
163: public ModelMBeanAttributeInfo(String name, String type,
164: String description, boolean isReadable, boolean isWritable,
165: boolean isIs, Descriptor descriptor) {
166: super (name, type, description, isReadable, isWritable, isIs);
167: setDescriptor(descriptor);
168: }
169:
170: /**
171: * Copy constructor.
172: *
173: * @param info the attribute info to copy
174: */
175: public ModelMBeanAttributeInfo(ModelMBeanAttributeInfo info) {
176: // THS - javadoc says a default descriptor will be created but that's not
177: // consistent with the other *Info classes.
178: // I'm also assuming that getDescriptor returns a clone.
179: this (info.getName(), info.getType(), info.getDescription(),
180: info.isReadable(), info.isWritable(), info.isIs(), info
181: .getDescriptor());
182: }
183:
184: // DescriptorAccess implementation -------------------------------
185: /**
186: * Returns a copy of the descriptor associated with this attribute.
187: *
188: * @return a copy of this attribute's descriptor
189: */
190: public Descriptor getDescriptor() {
191: return (Descriptor) descriptor.clone();
192: }
193:
194: /**
195: * Replaces the descriptor associated with this attribute. If the <tt>inDescriptor</tt>
196: * argument is <tt>null</tt> then the existing descriptor is replaced with a default
197: * descriptor.
198: *
199: * @param inDescriptor descriptor used for replacing the existing operation descriptor
200: * @throws IllegalArgumentException if the new descriptor is not valid
201: */
202: public void setDescriptor(Descriptor inDescriptor) {
203: if (inDescriptor == null)
204: inDescriptor = createDefaultDescriptor();
205:
206: if (inDescriptor.isValid()
207: && isAttributeDescriptorValid(inDescriptor))
208: this .descriptor = inDescriptor;
209: }
210:
211: /**
212: * Validate the descriptor in the context of an attribute
213: */
214: private boolean isAttributeDescriptorValid(Descriptor inDescriptor) {
215: String name = (String) inDescriptor
216: .getFieldValue(ModelMBeanConstants.NAME);
217: if (name.equals(getName()) == false)
218: throw new RuntimeOperationsException(
219: new IllegalArgumentException(
220: "Invalid name, expected '" + getName()
221: + "' but got: " + name));
222:
223: String descriptorType = (String) inDescriptor
224: .getFieldValue(ModelMBeanConstants.DESCRIPTOR_TYPE);
225: if (ModelMBeanConstants.ATTRIBUTE_DESCRIPTOR
226: .equalsIgnoreCase(descriptorType) == false)
227: throw new RuntimeOperationsException(
228: new IllegalArgumentException(
229: "Invalid descriptorType, for attribute '"
230: + name
231: + "' expected 'attribute' but got: "
232: + descriptorType));
233:
234: return true;
235: }
236:
237: // Cloneable implementation --------------------------------------
238: /**
239: * Creates a copy of this object.
240: *
241: * @return clone of this object
242: */
243: public synchronized Object clone() {
244: ModelMBeanAttributeInfo clone = (ModelMBeanAttributeInfo) super
245: .clone();
246: clone.descriptor = (Descriptor) this .descriptor.clone();
247:
248: return clone;
249: }
250:
251: // Object override -----------------------------------------------
252: /**
253: * Returns a string representation of this Model MBean attribute info object.
254: * The returned string is in the form: <pre>
255: *
256: * ModelMBeanAttributeInfo[Name=<attribute name>,
257: * Type=<class name of the attribute type>,
258: * Access= RW | RO | WO,
259: * Descriptor=(fieldName1=fieldValue1, ... , fieldName<n>=fieldValue<n>)]
260: *
261: * </pre>
262: *
263: * @return string representation of this object
264: */
265: public String toString() {
266: return "ModelMBeanAttributeInfo["
267: + "Name="
268: + getName()
269: + ",Type="
270: + getType()
271: + ",Access="
272: + ((isReadable() && isWritable()) ? "RW"
273: : (isReadable()) ? "RO" : "WO")
274: + ",Descriptor(" + getDescriptor() + ")]";
275: }
276:
277: // Private -------------------------------------------------------
278:
279: /**
280: * Creates a default descriptor.
281: */
282: private Descriptor createDefaultDescriptor() {
283: DescriptorSupport descr = new DescriptorSupport();
284: descr.setField(ModelMBeanConstants.NAME, super .getName());
285: descr.setField(ModelMBeanConstants.DESCRIPTOR_TYPE,
286: ModelMBeanConstants.ATTRIBUTE_DESCRIPTOR);
287: descr.setField(ModelMBeanConstants.DISPLAY_NAME, super
288: .getName());
289: return descr;
290: }
291:
292: private void readObject(ObjectInputStream ois) throws IOException,
293: ClassNotFoundException {
294: ObjectInputStream.GetField getField = ois.readFields();
295: descriptor = (Descriptor) getField.get("attrDescriptor", null);
296: if (descriptor == null)
297: throw new StreamCorruptedException("Null descriptor?");
298: if (descriptor
299: .getFieldValue(ModelMBeanConstants.ATTRIBUTE_VALUE) == null) {
300: // Check for 3.2.x legacy "value"
301: Object value = descriptor.getFieldValue("value");
302: if (value != null)
303: descriptor.setField(
304: ModelMBeanConstants.ATTRIBUTE_VALUE, value);
305: }
306: }
307:
308: private void writeObject(ObjectOutputStream oos) throws IOException {
309: ObjectOutputStream.PutField putField = oos.putFields();
310: putField.put("attrDescriptor", descriptor);
311: oos.writeFields();
312: }
313:
314: }
|