MBeanClientInterceptor understands CompositeData/TabularData arrays (SPR-6548)
This commit is contained in:
parent
2e032889ef
commit
1ff99f2569
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue