001: // $Id: IntrospectionBasedDynamicBean.java 1037 2007-03-20 06:45:01Z grro $
002: /*
003: * Copyright (c) xsocket.org, 2006 - 2007. All rights reserved.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
020: * The latest copy of this software may be found on http://www.xsocket.org/
021: */
022: package distributedcache.management;
023:
024: import java.lang.reflect.Method;
025: import java.util.HashMap;
026: import java.util.List;
027: import java.util.Map;
028:
029: import javax.management.Attribute;
030: import javax.management.AttributeList;
031: import javax.management.AttributeNotFoundException;
032: import javax.management.DynamicMBean;
033: import javax.management.InvalidAttributeValueException;
034: import javax.management.MBeanAttributeInfo;
035: import javax.management.MBeanException;
036: import javax.management.MBeanInfo;
037: import javax.management.ReflectionException;
038:
039: /**
040: * introspection based dynamic mbean, which exposes the getter and setter methods
041: * (all visibilities) of the underlying object by using introspection
042: *
043: * @author grro@xsocket.org
044: */
045: final class IntrospectionBasedDynamicBean implements DynamicMBean {
046:
047: private Object obj = null;
048:
049: private final Map<String, Info> properties = new HashMap<String, Info>();
050:
051: /**
052: * constructore
053: *
054: * @param obj the object to create a mbean for
055: */
056: IntrospectionBasedDynamicBean(Object obj) {
057: this .obj = obj;
058: }
059:
060: /**
061: * @see javax.management.DynamicMBean#getAttribute(java.lang.String)
062: */
063: public Object getAttribute(String attribute)
064: throws AttributeNotFoundException, MBeanException,
065: ReflectionException {
066: String methodName = "get" + attribute;
067: try {
068: Method method = getMethod(obj.getClass(), methodName,
069: new Class[0]);
070: method.setAccessible(true);
071: return method.invoke(obj, new Object[0]);
072: } catch (Exception e) {
073: throw new ReflectionException(e);
074: }
075: }
076:
077: @SuppressWarnings("unchecked")
078: private Method getMethod(Class clazz, String methodname,
079: Class[] params) {
080: do {
081: try {
082: Method method = clazz.getDeclaredMethod(methodname,
083: params);
084: method.setAccessible(true);
085: return method;
086: } catch (Exception ignore) {
087: }
088:
089: for (Class interf : clazz.getInterfaces()) {
090: getMethod(interf, methodname, params);
091: }
092:
093: clazz = clazz.getSuperclass();
094:
095: } while (clazz != null);
096:
097: return null;
098: }
099:
100: /**
101: * {@inheritDoc}
102: */
103: public AttributeList getAttributes(String[] attributes) {
104: AttributeList list = new AttributeList();
105: for (String attribute : attributes) {
106: try {
107: list.add(new Attribute(attribute,
108: getAttribute(attribute)));
109: } catch (Exception ignore) {
110: }
111: }
112: return list;
113: }
114:
115: /**
116: * {@inheritDoc}
117: */
118: public void setAttribute(Attribute attribute)
119: throws AttributeNotFoundException,
120: InvalidAttributeValueException, MBeanException,
121: ReflectionException {
122: String methodName = "set" + attribute.getName();
123:
124: Info info = getInfo(attribute.getName());
125:
126: try {
127: Method method = getMethod(obj.getClass(), methodName,
128: new Class[] { info.propertyType });
129: method.setAccessible(true);
130: method.invoke(obj, new Object[] { attribute.getValue() });
131: } catch (Exception e) {
132: throw new ReflectionException(e);
133: }
134: }
135:
136: /**
137: * {@inheritDoc}
138: */
139: public AttributeList setAttributes(AttributeList attributes) {
140: AttributeList result = new AttributeList();
141:
142: Attribute[] attrs = (Attribute[]) attributes
143: .toArray(new Attribute[attributes.size()]);
144: for (Attribute attr : attrs) {
145: try {
146: setAttribute(attr);
147: result.add(new Attribute(attr.getName(), attr
148: .getValue()));
149: } catch (Exception ignore) {
150: }
151: }
152: return result;
153: }
154:
155: /**
156: * {@inheritDoc}
157: */
158: public Object invoke(String actionName, Object[] params,
159: String[] signature) throws MBeanException,
160: ReflectionException {
161: // TODO Auto-generated method stub
162: return null;
163: }
164:
165: /**
166: * {@inheritDoc}
167: */
168: public synchronized MBeanInfo getMBeanInfo() {
169:
170: analyze(obj);
171:
172: String[] attributes = properties.keySet().toArray(
173: new String[properties.size()]);
174: MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[attributes.length];
175: for (int i = 0; i < attrs.length; i++) {
176: attrs[i] = properties.get(attributes[i])
177: .asbMBeanAttributeInfo();
178: }
179:
180: return new MBeanInfo(obj.getClass().getName(), "", attrs, null, // constructors
181: null, null); // notifications
182: }
183:
184: private void analyze(Object obj) {
185: Class clazz = obj.getClass();
186: do {
187: analyzeType(clazz);
188:
189: for (Class interf : clazz.getInterfaces()) {
190: analyzeType(interf);
191: }
192:
193: clazz = clazz.getSuperclass();
194:
195: } while (clazz != null);
196: }
197:
198: private void analyzeType(Class clazz) {
199: for (Method method : clazz.getDeclaredMethods()) {
200: String name = method.getName();
201:
202: if ((name.length() > 3) && name.startsWith("get")) {
203: if (method.getParameterTypes().length == 0) {
204: Class propertyType = method.getReturnType();
205:
206: if (isAcceptedPropertyType(propertyType)) {
207: Info info = registerInfo(name.substring(3, name
208: .length()));
209: info.isReadable = true;
210: info.propertyType = propertyType;
211: }
212: }
213: }
214:
215: if ((name.length() > 3) && name.startsWith("set")) {
216: if (method.getParameterTypes().length == 1) {
217: Class propertyType = method.getParameterTypes()[0];
218:
219: if (isAcceptedPropertyType(propertyType)) {
220: Info info = registerInfo(name.substring(3, name
221: .length()));
222: info.isWriteable = true;
223: info.propertyType = propertyType;
224: }
225: }
226: }
227: }
228: }
229:
230: private Info registerInfo(String name) {
231: Info info = properties.get(name);
232: if (info == null) {
233: info = new Info();
234: info.propertyName = name;
235: info.propertyDescription = "Property " + info.propertyName;
236: properties.put(name, info);
237: }
238: return info;
239: }
240:
241: private Info getInfo(String name) {
242: Info info = properties.get(name);
243: if (info == null) {
244: info = new Info();
245: info.propertyName = name;
246: info.propertyDescription = "Property " + info.propertyName;
247: }
248: return info;
249: }
250:
251: @SuppressWarnings("unchecked")
252: private boolean isAcceptedPropertyType(Class clazz) {
253: if (clazz.isAssignableFrom(List.class)) {
254: return true;
255: }
256: if (clazz.isArray()) {
257: return true;
258: }
259:
260: String name = clazz.getName();
261: return name.equals("int") || name.equals("java.lang.Integer")
262: || name.equals("long") || name.equals("java.lang.Long")
263: || name.equals("double")
264: || name.equals("java.lang.Double")
265: || name.equals("boolean")
266: || name.equals("java.lang.Boolean")
267: || name.equals("float")
268: || name.equals("java.lang.String")
269: || name.equals("java.lang.Float");
270: }
271:
272: private static class Info {
273: String propertyName = null;
274: Class propertyType = null;
275: String propertyDescription = null;
276: boolean isReadable = false;
277: boolean isWriteable = false;
278: boolean isIs = false;
279:
280: MBeanAttributeInfo asbMBeanAttributeInfo() {
281: return new MBeanAttributeInfo(propertyName, propertyType
282: .getName(), propertyDescription, isReadable,
283: isWriteable, isIs);
284: }
285: }
286: }
|