/*
* Copyright 2002-2008 the original author or authors.
*
* 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
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.jmx.access;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.BindException;
import java.util.HashMap;
import java.util.Map;
import javax.management.Descriptor;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import org.springframework.jmx.AbstractMBeanServerTests;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.JmxException;
import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.assembler.AbstractReflectiveMBeanInfoAssembler;
/**
* @author Rob Harrop
* @author Juergen Hoeller
*/
public class MBeanClientInterceptorTests extends AbstractMBeanServerTests {
protected static final String OBJECT_NAME = "spring:test=proxy";
protected JmxTestBean target;
protected boolean runTests = true;
public void onSetUp() throws Exception {
target = new JmxTestBean();
target.setAge(100);
target.setName("Rob Harrop");
MBeanExporter adapter = new MBeanExporter();
Map beans = new HashMap();
beans.put(OBJECT_NAME, target);
adapter.setServer(getServer());
adapter.setBeans(beans);
adapter.setAssembler(new ProxyTestAssembler());
adapter.afterPropertiesSet();
}
protected MBeanServerConnection getServerConnection() throws Exception {
return getServer();
}
protected IJmxTestBean getProxy() throws Exception {
MBeanProxyFactoryBean factory = new MBeanProxyFactoryBean();
factory.setServer(getServerConnection());
factory.setProxyInterface(IJmxTestBean.class);
factory.setObjectName(OBJECT_NAME);
factory.afterPropertiesSet();
return (IJmxTestBean) factory.getObject();
}
public void testProxyClassIsDifferent() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
assertTrue("The proxy class should be different than the base class",
(proxy.getClass() != IJmxTestBean.class));
}
public void testDifferentProxiesSameClass() throws Exception {
if (!runTests) return;
IJmxTestBean proxy1 = getProxy();
IJmxTestBean proxy2 = getProxy();
assertNotSame("The proxies should NOT be the same", proxy1, proxy2);
assertSame("The proxy classes should be the same", proxy1.getClass(), proxy2.getClass());
}
public void testGetAttributeValue() throws Exception {
if (!runTests) return;
IJmxTestBean proxy1 = getProxy();
int age = proxy1.getAge();
assertEquals("The age should be 100", 100, age);
}
public void testSetAttributeValue() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
proxy.setName("Rob Harrop");
assertEquals("The name of the bean should have been updated", "Rob Harrop", target.getName());
}
public void testSetAttributeValueWithRuntimeException() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
try {
proxy.setName("Juergen");
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
public void testSetAttributeValueWithCheckedException() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
try {
proxy.setName("Juergen Class");
fail("Should have thrown ClassNotFoundException");
}
catch (ClassNotFoundException ex) {
// expected
}
}
public void testSetAttributeValueWithIOException() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
try {
proxy.setName("Juergen IO");
fail("Should have thrown IOException");
}
catch (IOException ex) {
// expected
}
}
public void testSetReadOnlyAttribute() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
try {
proxy.setAge(900);
fail("Should not be able to write to a read only attribute");
}
catch (InvalidInvocationException ex) {
// success
}
}
public void testInvokeNoArgs() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
long result = proxy.myOperation();
assertEquals("The operation should return 1", 1, result);
}
public void testInvokeArgs() throws Exception {
if (!runTests) return;
IJmxTestBean proxy = getProxy();
int result = proxy.add(1, 2);
assertEquals("The operation should return 3", 3, result);
}
public void testInvokeUnexposedMethodWithException() throws Exception {
if (!runTests) return;
IJmxTestBean bean = getProxy();
try {
bean.dontExposeMe();
fail("Method dontExposeMe should throw an exception");
}
catch (InvalidInvocationException desired) {
// success
}
}
public void testLazyConnectionToRemote() throws Exception {
if (!runTests) return;
JMXServiceURL url = new JMXServiceURL("service:jmx:jmxmp://localhost:9876");
JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, getServer());
MBeanProxyFactoryBean factory = new MBeanProxyFactoryBean();
factory.setServiceUrl(url.toString());
factory.setProxyInterface(IJmxTestBean.class);
factory.setObjectName(OBJECT_NAME);
factory.setConnectOnStartup(false);
factory.setRefreshOnConnectFailure(true);
// should skip connection to the server
factory.afterPropertiesSet();
IJmxTestBean bean = (IJmxTestBean) factory.getObject();
// now start the connector
try {
connector.start();
}
catch (BindException ex) {
// couldn't bind to local port 9876 - let's skip the remainder of this test
System.out.println(
"Skipping JMX LazyConnectionToRemote test because binding to local port 9876 failed: " +
ex.getMessage());
return;
}
// should now be able to access data via the lazy proxy
try {
assertEquals("Rob Harrop", bean.getName());
assertEquals(100, bean.getAge());
}
finally {
connector.stop();
}
try {
bean.getName();
}
catch (JmxException ex) {
// expected
}
connector = JMXConnectorServerFactory.newJMXConnectorServer(url, null, getServer());
connector.start();
// should now be able to access data via the lazy proxy
try {
assertEquals("Rob Harrop", bean.getName());
assertEquals(100, bean.getAge());
}
finally {
connector.stop();
}
}
// Commented out because of a side effect with the the started platform MBeanServer.
/*
public void testMXBeanAttributeAccess() throws Exception {
if (org.springframework.core.JdkVersion.getMajorJavaVersion() < org.springframework.core.JdkVersion.JAVA_15) {
return;
}
MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(java.lang.management.ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("java.lang:type=Memory");
interceptor.setManagementInterface(java.lang.management.MemoryMXBean.class);
java.lang.management.MemoryMXBean proxy =
(java.lang.management.MemoryMXBean) org.springframework.aop.framework.ProxyFactory.getProxy(java.lang.management.MemoryMXBean.class, interceptor);
assertTrue(proxy.getHeapMemoryUsage().getMax() > 0);
}
public void testMXBeanOperationAccess() throws Exception {
if (org.springframework.core.JdkVersion.getMajorJavaVersion() < org.springframework.core.JdkVersion.JAVA_15) {
return;
}
MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(java.lang.management.ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("java.lang:type=Threading");
java.lang.management.ThreadMXBean proxy =
(java.lang.management.ThreadMXBean) org.springframework.aop.framework.ProxyFactory.getProxy(java.lang.management.ThreadMXBean.class, interceptor);
assertTrue(proxy.getThreadInfo(Thread.currentThread().getId()).getStackTrace() != null);
}
// This test passes under Windows with JDK 1.6.0_18
// It fails on Mac OS X with JDK 1.6.0_17 (most recent as of Feb 24, 2010)
// with a "java.lang.InternalError: Unsupported VMGlobal Type 0" exception
public void testMXBeanAttributeListAccess() throws Exception {
MBeanClientInterceptor interceptor = new MBeanClientInterceptor();
interceptor.setServer(java.lang.management.ManagementFactory.getPlatformMBeanServer());
interceptor.setObjectName("com.sun.management:type=HotSpotDiagnostic");
com.sun.management.HotSpotDiagnosticMXBean proxy =
(com.sun.management.HotSpotDiagnosticMXBean) org.springframework.aop.framework.ProxyFactory.getProxy(com.sun.management.HotSpotDiagnosticMXBean.class, interceptor);
assertFalse(proxy.getDiagnosticOptions().isEmpty());
}
*/
private static class ProxyTestAssembler extends AbstractReflectiveMBeanInfoAssembler {
protected boolean includeReadAttribute(Method method, String beanKey) {
return true;
}
protected boolean includeWriteAttribute(Method method, String beanKey) {
if ("setAge".equals(method.getName())) {
return false;
}
return true;
}
protected boolean includeOperation(Method method, String beanKey) {
if ("dontExposeMe".equals(method.getName())) {
return false;
}
return true;
}
protected String getOperationDescription(Method method) {
return method.getName();
}
protected String getAttributeDescription(PropertyDescriptor propertyDescriptor) {
return propertyDescriptor.getDisplayName();
}
protected void populateAttributeDescriptor(Descriptor descriptor, Method getter, Method setter) {
}
protected void populateOperationDescriptor(Descriptor descriptor, Method method) {
}
protected String getDescription(String beanKey, Class beanClass) {
return "";
}
protected void populateMBeanDescriptor(Descriptor mbeanDescriptor, String beanKey, Class beanClass) {
}
}
}