001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.lang.management;
019:
020: import java.lang.reflect.Method;
021:
022: import javax.management.Attribute;
023: import javax.management.AttributeList;
024: import javax.management.AttributeNotFoundException;
025: import javax.management.DynamicMBean;
026: import javax.management.InvalidAttributeValueException;
027: import javax.management.MBeanAttributeInfo;
028: import javax.management.MBeanException;
029: import javax.management.MBeanInfo;
030: import javax.management.MBeanOperationInfo;
031: import javax.management.MBeanParameterInfo;
032: import javax.management.ReflectionException;
033:
034: /**
035: * Abstract implementation of the {@link DynamicMBean} interface that provides
036: * behaviour required by a dynamic MBean. This class is subclassed by all of the
037: * concrete MXBean types in this package.
038: */
039: public abstract class DynamicMXBeanImpl implements DynamicMBean {
040:
041: protected MBeanInfo info;
042:
043: /**
044: * @param info
045: */
046: protected void setMBeanInfo(MBeanInfo info) {
047: this .info = info;
048: }
049:
050: /*
051: * (non-Javadoc)
052: *
053: * @see javax.management.DynamicMBean#getAttributes(java.lang.String[])
054: */
055: public AttributeList getAttributes(String[] attributes) {
056: AttributeList result = new AttributeList();
057: for (int i = 0; i < attributes.length; i++) {
058: try {
059: Object value = getAttribute(attributes[i]);
060: result.add(new Attribute(attributes[i], value));
061: } catch (Exception e) {
062: // It is alright if the returned AttributeList is smaller in
063: // size than the length of the input array.
064: if (ManagementUtils.VERBOSE_MODE) {
065: e.printStackTrace(System.err);
066: }// end if
067: }
068: }// end for
069: return result;
070: }
071:
072: /*
073: * (non-Javadoc)
074: *
075: * @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList)
076: */
077: public AttributeList setAttributes(AttributeList attributes) {
078: AttributeList result = new AttributeList();
079:
080: for (int i = 0; i < attributes.size(); i++) {
081: Attribute attrib = (Attribute) attributes.get(i);
082: String attribName = null;
083: Object attribVal = null;
084: try {
085: this .setAttribute(attrib);
086: attribName = attrib.getName();
087: // Note that the below getAttribute call will throw an
088: // AttributeNotFoundException if the named attribute is not
089: // readable for this bean. This is perfectly alright - the set
090: // has worked as requested - it just means that the caller
091: // does not get this information returned to them in the
092: // result AttributeList.
093: attribVal = getAttribute(attribName);
094: result.add(new Attribute(attribName, attribVal));
095: } catch (Exception e) {
096: if (ManagementUtils.VERBOSE_MODE) {
097: e.printStackTrace(System.err);
098: }// end if
099: }
100: }// end for
101: return result;
102: }
103:
104: /*
105: * (non-Javadoc)
106: *
107: * @see javax.management.DynamicMBean#getMBeanInfo()
108: */
109: public MBeanInfo getMBeanInfo() {
110: return info;
111: }
112:
113: /**
114: * Simple enumeration of the different kinds of access that may be required
115: * of a dynamic MBean attribute.
116: */
117: enum AttributeAccessType {
118: READING, WRITING
119: };
120:
121: /**
122: * Tests to see if this <code>DynamicMXBean</code> has an attribute with
123: * the name <code>attributeName</code>. If the test is passed, the
124: * {@link MBeanAttributeInfo}representing the attribute is returned.
125: *
126: * @param attributeName
127: * the name of the attribute being queried
128: * @param access
129: * an {@link AttributeAccessType}indication of whether the
130: * caller is looking for a readable or writable attribute.
131: * @return if the named attribute exists and is readable or writable
132: * (depending on what was specified in <code>access</code>, an
133: * instance of <code>MBeanAttributeInfo</code> that describes the
134: * attribute, otherwise <code>null</code>.
135: */
136: protected MBeanAttributeInfo getPresentAttribute(
137: String attributeName, AttributeAccessType access) {
138: MBeanAttributeInfo[] attribs = info.getAttributes();
139: MBeanAttributeInfo result = null;
140:
141: for (int i = 0; i < attribs.length; i++) {
142: MBeanAttributeInfo attribInfo = attribs[i];
143: if (attribInfo.getName().equals(attributeName)) {
144: if (access.equals(AttributeAccessType.READING)) {
145: if (attribInfo.isReadable()) {
146: result = attribInfo;
147: break;
148: }
149: } else {
150: if (attribInfo.isWritable()) {
151: result = attribInfo;
152: break;
153: }
154: }
155: }// end if
156: }// end for
157: return result;
158: }
159:
160: /*
161: * (non-Javadoc)
162: *
163: * @see javax.management.DynamicMBean#getAttribute(java.lang.String)
164: */
165: public Object getAttribute(String attribute)
166: throws AttributeNotFoundException, MBeanException,
167: ReflectionException {
168: Object result = null;
169: Method getterMethod = null;
170: MBeanAttributeInfo attribInfo = getPresentAttribute(attribute,
171: AttributeAccessType.READING);
172: if (attribInfo == null) {
173: throw new AttributeNotFoundException("No such attribute : "
174: + attribute);
175: }
176:
177: try {
178: String getterPrefix = attribInfo.isIs() ? "is" : "get";
179: getterMethod = this .getClass().getMethod(
180: getterPrefix + attribute, (Class[]) null);
181: } catch (Exception e) {
182: if (ManagementUtils.VERBOSE_MODE) {
183: e.printStackTrace(System.err);
184: }// end if
185: throw new ReflectionException(e);
186: }
187:
188: String realReturnType = getterMethod.getReturnType().getName();
189: String openReturnType = attribInfo.getType();
190: result = invokeMethod(getterMethod, (Object[]) null);
191:
192: try {
193: if (!realReturnType.equals(openReturnType)) {
194: result = ManagementUtils.convertToOpenType(result,
195: Class.forName(openReturnType), Class
196: .forName(realReturnType));
197: }// end if conversion necessary
198: } catch (ClassNotFoundException e) {
199: if (ManagementUtils.VERBOSE_MODE) {
200: e.printStackTrace(System.err);
201: }// end if
202: throw new MBeanException(e);
203: }
204:
205: return result;
206: }
207:
208: /*
209: * (non-Javadoc)
210: *
211: * @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute)
212: */
213: public void setAttribute(Attribute attribute)
214: throws AttributeNotFoundException,
215: InvalidAttributeValueException, MBeanException,
216: ReflectionException {
217:
218: // In Java 5.0 platform MXBeans the following applies for all
219: // attribute setter methods :
220: // 1. no conversion to open MBean types necessary
221: // 2. all setter arguments are single value (i.e. not array or
222: // collection types).
223: // 3. all return null
224:
225: Class argType = null;
226:
227: // Validate the attribute
228: MBeanAttributeInfo attribInfo = getPresentAttribute(attribute
229: .getName(), AttributeAccessType.WRITING);
230: if (attribInfo == null) {
231: throw new AttributeNotFoundException("No such attribute : "
232: + attribute);
233: }
234:
235: try {
236: // Validate supplied parameter is of the expected type
237: argType = ManagementUtils.getClassMaybePrimitive(attribInfo
238: .getType());
239: } catch (ClassNotFoundException e) {
240: if (ManagementUtils.VERBOSE_MODE) {
241: e.printStackTrace(System.err);
242: }// end if
243: throw new ReflectionException(e);
244: }
245:
246: if (argType.isPrimitive()) {
247: if (!ManagementUtils.isWrapperClass(attribute.getValue()
248: .getClass(), argType)) {
249: throw new InvalidAttributeValueException(attribInfo
250: .getName()
251: + " is a "
252: + attribInfo.getType()
253: + " attribute");
254: }
255: } else if (!argType.equals(attribute.getValue().getClass())) {
256: throw new InvalidAttributeValueException(attribInfo
257: .getName()
258: + " is a " + attribInfo.getType() + " attribute");
259: }
260:
261: Method setterMethod = null;
262: try {
263: setterMethod = this .getClass().getMethod(
264: "set" + attribute.getName(),
265: new Class[] { argType });
266: } catch (Exception e) {
267: if (ManagementUtils.VERBOSE_MODE) {
268: e.printStackTrace(System.err);
269: }// end if
270: throw new ReflectionException(e);
271: }
272:
273: invokeMethod(setterMethod, attribute.getValue());
274: try {
275: setterMethod.invoke(this , attribute.getValue());
276: } catch (Exception e) {
277: if (ManagementUtils.VERBOSE_MODE) {
278: e.printStackTrace(System.err);
279: }// end if
280: Throwable root = e.getCause();
281: if (root instanceof RuntimeException) {
282: throw (RuntimeException) root;
283: } else {
284: throw new MBeanException((Exception) root);
285: }// end else
286: }// end catch
287: }
288:
289: /*
290: * (non-Javadoc)
291: *
292: * @see javax.management.DynamicMBean#invoke(java.lang.String,
293: * java.lang.Object[], java.lang.String[])
294: */
295: public Object invoke(String actionName, Object[] params,
296: String[] signature) throws MBeanException,
297: ReflectionException {
298: Object result = null;
299:
300: // If null is passed in for the signature argument (if invoking a
301: // method with no args for instance) then avoid any NPEs by working
302: // with a zero length String array instead.
303: String[] localSignature = signature;
304: if (localSignature == null) {
305: localSignature = new String[0];
306: }
307:
308: // Validate that we have the named action
309: MBeanOperationInfo opInfo = getPresentOperation(actionName,
310: localSignature);
311: if (opInfo == null) {
312: throw new ReflectionException(new NoSuchMethodException(
313: actionName), "No such operation : " + actionName);
314: }
315:
316: // For Java 5.0 platform MXBeans, no conversion
317: // to open MBean types is necessary for any of the arguments.
318: // i.e. they are all simple types.
319: Method operationMethod = null;
320: try {
321: Class[] argTypes = new Class[localSignature.length];
322: for (int i = 0; i < localSignature.length; i++) {
323: argTypes[i] = ManagementUtils
324: .getClassMaybePrimitive(localSignature[i]);
325: }// end for
326: operationMethod = this .getClass().getMethod(actionName,
327: argTypes);
328: } catch (Exception e) {
329: if (ManagementUtils.VERBOSE_MODE) {
330: e.printStackTrace(System.err);
331: }// end if
332: throw new ReflectionException(e);
333: }
334:
335: String realReturnType = operationMethod.getReturnType()
336: .getName();
337: String openReturnType = opInfo.getReturnType();
338: result = invokeMethod(operationMethod, params);
339:
340: try {
341: if (!realReturnType.equals(openReturnType)) {
342: result = ManagementUtils.convertToOpenType(result,
343: Class.forName(openReturnType), Class
344: .forName(realReturnType));
345: }
346: } catch (ClassNotFoundException e) {
347: if (ManagementUtils.VERBOSE_MODE) {
348: e.printStackTrace(System.err);
349: }// end if
350: throw new MBeanException(e);
351: }// end catch
352:
353: return result;
354: }
355:
356: /**
357: * Tests to see if this <code>DynamicMXBean</code> has an operation with
358: * the name <code>actionName</code>. If the test is passed, the
359: * {@link MBeanOperationInfo}representing the operation is returned to the
360: * caller.
361: *
362: * @param actionName
363: * the name of a possible method on this
364: * <code>DynamicMXBean</code>
365: * @param signature
366: * the list of parameter types for the named operation in the
367: * correct order
368: * @return if the named operation exists, an instance of
369: * <code>MBeanOperationInfo</code> that describes the operation,
370: * otherwise <code>null</code>.
371: */
372: protected MBeanOperationInfo getPresentOperation(String actionName,
373: String[] signature) {
374: MBeanOperationInfo[] operations = info.getOperations();
375: MBeanOperationInfo result = null;
376:
377: for (int i = 0; i < operations.length; i++) {
378: MBeanOperationInfo opInfo = operations[i];
379: if (opInfo.getName().equals(actionName)) {
380: // Do parameter numbers match ?
381: if (signature.length == opInfo.getSignature().length) {
382: // Do parameter types match ?
383: boolean match = true;
384: MBeanParameterInfo[] parameters = opInfo
385: .getSignature();
386: for (int j = 0; j < parameters.length; j++) {
387: MBeanParameterInfo paramInfo = parameters[j];
388: if (!paramInfo.getType().equals(signature[j])) {
389: match = false;
390: break;
391: }
392: }// end for all parameters
393: if (match) {
394: result = opInfo;
395: break;
396: }
397: }// end if parameter counts match
398: }// end if operation names match
399: }// end for all operations
400:
401: return result;
402: }
403:
404: /**
405: * @param params
406: * @param operationMethod
407: * @return the result of the reflective method invocation
408: * @throws MBeanException
409: */
410: private Object invokeMethod(Method operationMethod,
411: Object... params) throws MBeanException {
412: Object result = null;
413: try {
414: result = operationMethod.invoke(this , params);
415: } catch (Exception e) {
416: if (ManagementUtils.VERBOSE_MODE) {
417: e.printStackTrace(System.err);
418: }// end if
419: Throwable root = e.getCause();
420: if (root instanceof RuntimeException) {
421: throw (RuntimeException) root;
422: } else {
423: throw new MBeanException((Exception) root);
424: }// end else
425: }// end catch
426: return result;
427: }
428: }
|