MBeanClientInterceptor understands CompositeData/TabularData arrays (SPR-6548)

This commit is contained in:
Juergen Hoeller 2010-01-12 15:10:07 +00:00
parent 2e032889ef
commit 1ff99f2569
2 changed files with 79 additions and 24 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,9 +18,11 @@ package org.springframework.jmx.access;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.management.Attribute; import javax.management.Attribute;
@ -54,6 +56,9 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.CollectionFactory;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.jmx.support.JmxUtils; import org.springframework.jmx.support.JmxUtils;
import org.springframework.jmx.support.ObjectNameManager; import org.springframework.jmx.support.ObjectNameManager;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -408,7 +413,7 @@ public class MBeanClientInterceptor
result = invokeOperation(method, invocation.getArguments()); result = invokeOperation(method, invocation.getArguments());
} }
} }
return convertResultValueIfNecessary(result, method.getReturnType()); return convertResultValueIfNecessary(result, new MethodParameter(method, -1));
} }
catch (MBeanException ex) { catch (MBeanException ex) {
throw ex.getTargetException(); throw ex.getTargetException();
@ -525,7 +530,8 @@ public class MBeanClientInterceptor
* @return the converted result object, or the passed-in object if no conversion * @return the converted result object, or the passed-in object if no conversion
* is necessary * is necessary
*/ */
protected Object convertResultValueIfNecessary(Object result, Class targetClass) { protected Object convertResultValueIfNecessary(Object result, MethodParameter parameter) {
Class targetClass = parameter.getParameterType();
try { try {
if (result == null) { if (result == null) {
return null; return null;
@ -534,30 +540,74 @@ public class MBeanClientInterceptor
return result; return result;
} }
if (result instanceof CompositeData) { if (result instanceof CompositeData) {
Method fromMethod = targetClass.getMethod("from", new Class[] {CompositeData.class}); Method fromMethod = targetClass.getMethod("from", CompositeData.class);
return ReflectionUtils.invokeMethod(fromMethod, null, new Object[] {result}); return ReflectionUtils.invokeMethod(fromMethod, null, result);
}
else if (result instanceof CompositeData[]) {
CompositeData[] array = (CompositeData[]) result;
if (targetClass.isArray()) {
return convertDataArrayToTargetArray(array, targetClass);
}
else if (Collection.class.isAssignableFrom(targetClass)) {
Class elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
if (elementType != null) {
return convertDataArrayToTargetCollection(array, targetClass, elementType);
}
}
} }
else if (result instanceof TabularData) { else if (result instanceof TabularData) {
Method fromMethod = targetClass.getMethod("from", new Class[] {TabularData.class}); Method fromMethod = targetClass.getMethod("from", TabularData.class);
return ReflectionUtils.invokeMethod(fromMethod, null, new Object[] {result}); return ReflectionUtils.invokeMethod(fromMethod, null, result);
} }
else { else if (result instanceof TabularData[]) {
throw new InvocationFailureException( TabularData[] array = (TabularData[]) result;
"Incompatible result value [" + result + "] for target type [" + targetClass.getName() + "]"); if (targetClass.isArray()) {
return convertDataArrayToTargetArray(array, targetClass);
}
else if (Collection.class.isAssignableFrom(targetClass)) {
Class elementType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
if (elementType != null) {
return convertDataArrayToTargetCollection(array, targetClass, elementType);
}
}
} }
throw new InvocationFailureException(
"Incompatible result value [" + result + "] for target type [" + targetClass.getName() + "]");
} }
catch (NoSuchMethodException ex) { catch (NoSuchMethodException ex) {
throw new InvocationFailureException( throw new InvocationFailureException(
"Could not obtain 'find(CompositeData)' / 'find(TabularData)' method on target type [" + "Could not obtain 'from(CompositeData)' / 'from(TabularData)' method on target type [" +
targetClass.getName() + "] for conversion of MXBean data structure [" + result + "]"); targetClass.getName() + "] for conversion of MXBean data structure [" + result + "]");
} }
} }
private Object convertDataArrayToTargetArray(Object[] array, Class targetClass) throws NoSuchMethodException {
Class targetType = targetClass.getComponentType();
Method fromMethod = targetType.getMethod("from", array.getClass().getComponentType());
Object resultArray = Array.newInstance(targetType, array.length);
for (int i = 0; i < array.length; i++) {
Array.set(resultArray, i, ReflectionUtils.invokeMethod(fromMethod, null, array[i]));
}
return resultArray;
}
@SuppressWarnings("unchecked")
private Collection convertDataArrayToTargetCollection(Object[] array, Class collectionType, Class elementType)
throws NoSuchMethodException {
Method fromMethod = elementType.getMethod("from", array.getClass().getComponentType());
Collection resultColl = CollectionFactory.createCollection(collectionType, Array.getLength(array));
for (int i = 0; i < array.length; i++) {
resultColl.add(ReflectionUtils.invokeMethod(fromMethod, null, array[i]));
}
return resultColl;
}
public void destroy() { public void destroy() {
this.connector.close(); this.connector.close();
} }
/** /**
* Simple wrapper class around a method name and its signature. * Simple wrapper class around a method name and its signature.
* Used as the key when caching methods. * Used as the key when caching methods.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of * use this file except in compliance with the License. You may obtain a copy of
@ -19,6 +19,9 @@ package org.springframework.jmx.access;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.management.MemoryMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.net.BindException; import java.net.BindException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -36,6 +39,9 @@ import org.springframework.jmx.JmxException;
import org.springframework.jmx.JmxTestBean; import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.MBeanExporter; import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.assembler.AbstractReflectiveMBeanInfoAssembler; import org.springframework.jmx.export.assembler.AbstractReflectiveMBeanInfoAssembler;
import org.springframework.aop.framework.ProxyFactory;
import com.sun.management.HotSpotDiagnosticMXBean;
/** /**
* @author Rob Harrop * @author Rob Harrop
@ -239,32 +245,31 @@ public class MBeanClientInterceptorTests extends AbstractMBeanServerTests {
} }
} }
// Commented out because of a side effect with the the started platform MBeanServer.
/* /*
public void testMXBeanAttributeAccess() throws Exception { public void testMXBeanAttributeAccess() throws Exception {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) {
return;
}
MBeanClientInterceptor interceptor = new MBeanClientInterceptor(); MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(ManagementFactory.getPlatformMBeanServer()); interceptor.setServer(ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("java.lang:type=Memory"); interceptor.setObjectName("java.lang:type=Memory");
interceptor.setManagementInterface(MemoryMXBean.class); interceptor.setManagementInterface(MemoryMXBean.class);
MemoryMXBean proxy = (MemoryMXBean) ProxyFactory.getProxy(MemoryMXBean.class, interceptor); MemoryMXBean proxy = ProxyFactory.getProxy(MemoryMXBean.class, interceptor);
assertTrue(proxy.getHeapMemoryUsage().getMax() > 0); assertTrue(proxy.getHeapMemoryUsage().getMax() > 0);
} }
public void testMXBeanOperationAccess() throws Exception { public void testMXBeanOperationAccess() throws Exception {
if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) {
return;
}
MBeanClientInterceptor interceptor = new MBeanClientInterceptor(); MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(ManagementFactory.getPlatformMBeanServer()); interceptor.setServer(ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("java.lang:type=Threading"); interceptor.setObjectName("java.lang:type=Threading");
ThreadMXBean proxy = (ThreadMXBean) ProxyFactory.getProxy(ThreadMXBean.class, interceptor); ThreadMXBean proxy = ProxyFactory.getProxy(ThreadMXBean.class, interceptor);
assertTrue(proxy.getThreadInfo(Thread.currentThread().getId()).getStackTrace() != null); assertTrue(proxy.getThreadInfo(Thread.currentThread().getId()).getStackTrace() != null);
} }
public void testMXBeanAttributeListAccess() throws Exception {
MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("com.sun.management:type=HotSpotDiagnostic");
HotSpotDiagnosticMXBean proxy = ProxyFactory.getProxy(HotSpotDiagnosticMXBean.class, interceptor);
assertFalse(proxy.getDiagnosticOptions().isEmpty());
}
*/ */