From b528abcf682439b8ed719152c1fa6c2cb57dbcbe Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Sat, 11 Dec 2010 08:48:43 +0000 Subject: [PATCH] INT-1675: work a bit harder to expose existing handlers if they are @ManagedResources --- .../integration/handler/LoggingHandler.java | 2 +- .../history/TrackableComponent.java | 4 + .../router/ExpressionEvaluatingRouter.java | 2 +- .../jmx/config/MBeanExporterParser.java | 12 ++ .../monitor/DirectChannelMetrics.java | 11 +- .../monitor/IntegrationMBeanExporter.java | 152 +++++++++++++++--- .../monitor/PollableChannelMetrics.java | 9 +- .../monitor/QueueChannelMetrics.java | 7 +- .../MBeanAutoDetectFirstTests-context.xml | 22 +++ .../MBeanAutoDetectSecondTests-context.xml | 22 +++ .../jmx/config/MBeanAutoDetectTests.java | 66 ++++++++ .../RouterMBeanGatewayTests-context.xml | 29 ++++ ...t.xml => RouterMBeanNoneTests-context.xml} | 0 ...xml => RouterMBeanSwitchTests-context.xml} | 0 .../jmx/config/RouterMBeanTests.java | 54 ++++++- .../RouterMBeanVanillaTests-context.xml | 24 +++ .../jmx/config/RouterMBeanVanillaTests.java | 54 +++++++ 17 files changed, 429 insertions(+), 41 deletions(-) create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectFirstTests-context.xml create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectSecondTests-context.xml create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectTests.java create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanGatewayTests-context.xml rename spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/{RouterMBeanTestsNone-context.xml => RouterMBeanNoneTests-context.xml} (100%) rename spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/{RouterMBeanTestsSwitch-context.xml => RouterMBeanSwitchTests-context.xml} (100%) create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests-context.xml create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java index 14e1aa18df..475f04dcad 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/LoggingHandler.java @@ -66,7 +66,7 @@ public class LoggingHandler extends AbstractMessageHandler { this.evaluationContext = evaluationContext; this.expression = EXPRESSION_PARSER.parseExpression("payload"); } - + public void setExpression(String expressionString) { this.expression = EXPRESSION_PARSER.parseExpression(expressionString); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/history/TrackableComponent.java b/spring-integration-core/src/main/java/org/springframework/integration/history/TrackableComponent.java index 6e040ceaf4..000f7c2762 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/history/TrackableComponent.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/history/TrackableComponent.java @@ -17,13 +17,17 @@ package org.springframework.integration.history; import org.springframework.integration.context.NamedComponent; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; /** * @author Mark Fisher * @since 2.0 */ +@ManagedResource public interface TrackableComponent extends NamedComponent { + @ManagedOperation void setShouldTrack(boolean shouldTrack); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java index ec1810ef5a..fa13f2752c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/ExpressionEvaluatingRouter.java @@ -32,5 +32,5 @@ public class ExpressionEvaluatingRouter extends AbstractMessageProcessingRouter public ExpressionEvaluatingRouter(Expression expression) { super(new ExpressionEvaluatingMessageProcessor(expression)); } - + } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java index f34b3cab30..814cedff28 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterParser.java @@ -53,6 +53,18 @@ public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-domain"); builder.addPropertyValue("server", mbeanServer); +// if (!parserContext.getRegistry().containsBeanDefinition(MBEAN_EXPORTER_NAME)) { +// /* +// * Vanilla MBeanExporter not yet registered - need to hack this in to ensure if it is subsequently +// * registered, then it gets initialized before the IntegrationMBeanExporter. +// */ +// BeanDefinitionBuilder dummy = BeanDefinitionBuilder.genericBeanDefinition(String.class); +// dummy.addConstructorArgValue("Dummy " + MBEAN_EXPORTER_NAME +// + " will be overridden by a "); +// parserContext.getRegistry().registerBeanDefinition(MBEAN_EXPORTER_NAME, dummy.getBeanDefinition()); +// } +// // Force vanilla MBeanExporter to initialize first if it exists to prevent problems with Proxies +// builder.getRawBeanDefinition().setDependsOn(new String[] { MBEAN_EXPORTER_NAME }); } private Object getMBeanServer(Element element, ParserContext parserContext) { diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DirectChannelMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DirectChannelMetrics.java index 520fb81b47..a9401fb370 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DirectChannelMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/DirectChannelMetrics.java @@ -19,7 +19,6 @@ import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.jmx.export.annotation.ManagedResource; @@ -63,8 +62,11 @@ public class DirectChannelMetrics implements MethodInterceptor, MessageChannelMe private final String name; + private final MessageChannel messageChannel; - public DirectChannelMetrics(String name) { + + public DirectChannelMetrics(MessageChannel messageChannel, String name) { + this.messageChannel = messageChannel; this.name = name; } @@ -75,6 +77,10 @@ public class DirectChannelMetrics implements MethodInterceptor, MessageChannelMe } } + public MessageChannel getMessageChannel() { + return messageChannel; + } + public String getName() { return name; } @@ -196,4 +202,5 @@ public class DirectChannelMetrics implements MethodInterceptor, MessageChannelMe public String toString() { return String.format("MessageChannelMonitor: [name=%s, sends=%d]", name, sendCount.get()); } + } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java index 1315fe0b1e..9bfcd6ea87 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/IntegrationMBeanExporter.java @@ -21,6 +21,11 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; +import javax.management.DynamicMBean; +import javax.management.JMException; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; + import org.aopalliance.aop.Advice; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -46,6 +51,7 @@ import org.springframework.integration.core.MessageSource; import org.springframework.integration.core.PollableChannel; import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.jmx.export.MBeanExporter; +import org.springframework.jmx.export.UnableToRegisterMBeanException; import org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedMetric; @@ -104,6 +110,8 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP private Set channels = new HashSet(); + private Map exposedBeans = new HashMap(); + private Map channelsByName = new HashMap(); private Map handlersByName = new HashMap(); @@ -122,14 +130,24 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP private String domain = DEFAULT_DOMAIN; + private boolean initialized = false; + private final Map objectNameStaticProperties = new HashMap(); + private final MetadataMBeanInfoAssembler assembler = new MetadataMBeanInfoAssembler(attributeSource); + + private final MetadataNamingStrategy namingStrategy = new MetadataNamingStrategy(attributeSource); + + private final Set mbeanExporters = new HashSet(); + + private final Set excludedBeansForOtherExporters = new HashSet(); + public IntegrationMBeanExporter() { super(); // Shouldn't be necessary, but to be on the safe side... setAutodetect(false); - setNamingStrategy(new MetadataNamingStrategy(attributeSource)); - setAssembler(new MetadataMBeanInfoAssembler(attributeSource)); + setNamingStrategy(namingStrategy); + setAssembler(assembler); } @Override @@ -155,6 +173,7 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP */ public void setDefaultDomain(String domain) { this.domain = domain; + this.namingStrategy.setDefaultDomain(domain); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { @@ -164,6 +183,12 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + + if (!initialized) { + initialized = true; + collectMBeanExporters(); + } + if (bean instanceof Advised) { for (Advisor advisor : ((Advised) bean).getAdvisors()) { Advice advice = advisor.getAdvice(); @@ -179,40 +204,97 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP SimpleMessageHandlerMetrics monitor = new SimpleMessageHandlerMetrics((MessageHandler) bean); Object advised = applyHandlerInterceptor(bean, monitor, beanClassLoader); handlers.add(monitor); + excludeBeanInOtherExporters(beanName); return advised; - } else if (bean instanceof MessageSource) { + } + + if (bean instanceof MessageSource) { SimpleMessageSourceMetrics monitor = new SimpleMessageSourceMetrics((MessageSource) bean); Object advised = applySourceInterceptor(bean, monitor, beanClassLoader); sources.add(monitor); + excludeBeanInOtherExporters(beanName); return advised; } if (bean instanceof MessageChannel) { DirectChannelMetrics monitor; + MessageChannel target = (MessageChannel) extractTarget(bean); if (bean instanceof PollableChannel) { - Object target = extractTarget(bean); if (target instanceof QueueChannel) { monitor = new QueueChannelMetrics((QueueChannel) target, beanName); } else { - monitor = new PollableChannelMetrics(beanName); + monitor = new PollableChannelMetrics(target, beanName); } } else { - monitor = new DirectChannelMetrics(beanName); + monitor = new DirectChannelMetrics(target, beanName); } Object advised = applyChannelInterceptor(bean, monitor, beanClassLoader); channels.add(monitor); + excludeBeanInOtherExporters(beanName); return advised; } return bean; } - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - return bean; + /** + * Make sure the named bean is not exposed in any other MBean exporters in the context. Called for beans that are + * being directly monitored by this exporter, but are wrapped in a proxy so cannot be directly exposed by a normal + * exporter. + * + * @param beanName the bean name to exclude + */ + private void excludeBeanInOtherExporters(String beanName) { + excludedBeansForOtherExporters.add(beanName); + String[] excluded = excludedBeansForOtherExporters.toArray(new String[0]); + for (MBeanExporter exporter : mbeanExporters) { + exporter.setExcludedBeans(excluded); + } } - @Override - protected void registerBeans() { - // Completely disable super class registration to avoid duplicates + /** + * Copy of private method in super class. Needed so we can avoid using the bean factory to extract the bean again, + * and risk it being a proxy (which it almost certainly is by now). + * + * @param bean the bean instance to register + * @param beanKey the bean name or human readable version if autogenerated + * @return the JMX object name of the MBean that was registered + */ + private ObjectName registerBeanInstance(Object bean, String beanKey) { + try { + ObjectName objectName = getObjectName(bean, beanKey); + Object mbeanToExpose = null; + if (isMBean(bean.getClass())) { + mbeanToExpose = bean; + } else { + DynamicMBean adaptedBean = adaptMBeanIfPossible(bean); + if (adaptedBean != null) { + mbeanToExpose = adaptedBean; + } + } + if (mbeanToExpose != null) { + if (logger.isInfoEnabled()) { + logger.info("Located MBean '" + beanKey + "': registering with JMX server as MBean [" + objectName + + "]"); + } + doRegister(mbeanToExpose, objectName); + } else { + if (logger.isInfoEnabled()) { + logger.info("Located managed bean '" + beanKey + "': registering with JMX server as MBean [" + + objectName + "]"); + } + ModelMBean mbean = createAndConfigureMBean(bean, beanKey); + doRegister(mbean, objectName); + // injectNotificationPublisherIfNecessary(bean, mbean, objectName); + } + return objectName; + } catch (JMException e) { + throw new UnableToRegisterMBeanException("Unable to register MBean [" + bean + "] with key '" + beanKey + + "'", e); + } + } + + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; } public final boolean isAutoStartup() { @@ -285,14 +367,18 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP registerSources(); } - @Override - public void afterPropertiesSet() { - super.afterPropertiesSet(); - /* - * Force early initialization of other MBeanExporters. Workaround for possible bug in Spring (see INT-1675) for - * more details. - */ - beanFactory.getBeansOfType(MBeanExporter.class); + /** + * Force early initialization of other MBean exporters and collect them for later use to ensure that they don't try + * to register the same beans that this exporter is covering. + */ + private void collectMBeanExporters() { + String[] beanNames = beanFactory.getBeanNamesForType(MBeanExporter.class, false, false); + for (String beanName : beanNames) { + MBeanExporter bean = beanFactory.getBean(beanName, MBeanExporter.class); + if (bean != this) { + mbeanExporters.add((MBeanExporter) bean); + } + } } @Override @@ -381,6 +467,14 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP return null; } + @Override + protected void registerBeans() { + if (!exposedBeans.isEmpty()) { + super.setBeans(exposedBeans); + super.registerBeans(); + } + } + private void registerChannels() { for (DirectChannelMetrics monitor : channels) { String name = monitor.getName(); @@ -392,6 +486,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP channelsByName.put(name, monitor); } registerBeanNameOrInstance(monitor, beanKey); + // Expose the raw bean if it is managed + MessageChannel bean = monitor.getMessageChannel(); + if (assembler.includeBean(bean.getClass(), monitor.getName())) { + registerBeanInstance(bean, monitor.getName()); + } } } } @@ -407,6 +506,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP handlersByName.put(name, monitor); } registerBeanNameOrInstance(monitor, beanKey); + // Expose the raw bean if it is managed + MessageHandler bean = source.getMessageHandler(); + if (assembler.includeBean(bean.getClass(), source.getName())) { + registerBeanInstance(bean, monitor.getName()); + } } } } @@ -422,6 +526,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP sourcesByName.put(name, monitor); } registerBeanNameOrInstance(monitor, beanKey); + // Expose the raw bean if it is managed + MessageSource bean = source.getMessageSource(); + if (assembler.includeBean(bean.getClass(), source.getName())) { + registerBeanInstance(bean, monitor.getName()); + } } } } @@ -472,6 +581,11 @@ public class IntegrationMBeanExporter extends MBeanExporter implements BeanPostP } else { ProxyFactory proxyFactory = new ProxyFactory(bean); proxyFactory.addAdvisor(advisor); + /** + * N.B. it's not a good idea to use proxyFactory.setProxyTargetClass(true) here because it forces all + * the integration components to be cglib proxyable (i.e. have a default constructor etc.), which they + * are not in general (usually for good reason). + */ return proxyFactory.getProxy(beanClassLoader); } } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/PollableChannelMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/PollableChannelMetrics.java index 2386945c52..c3538e240f 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/PollableChannelMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/PollableChannelMetrics.java @@ -19,7 +19,6 @@ package org.springframework.integration.monitor; import java.util.concurrent.atomic.AtomicInteger; import org.aopalliance.intercept.MethodInvocation; - import org.springframework.integration.MessageChannel; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.export.annotation.ManagedOperation; @@ -36,14 +35,10 @@ public class PollableChannelMetrics extends DirectChannelMetrics { private final AtomicInteger receiveErrorCount = new AtomicInteger(); - /** - * @param name - */ - public PollableChannelMetrics(String name) { - super(name); + public PollableChannelMetrics(MessageChannel messageChannel, String name) { + super(messageChannel, name); } - @Override protected Object doInvoke(MethodInvocation invocation, String method, MessageChannel channel) throws Throwable { if ("receive".equals(method)) { diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/QueueChannelMetrics.java b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/QueueChannelMetrics.java index 5c7e844a41..48a22d5026 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/QueueChannelMetrics.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/monitor/QueueChannelMetrics.java @@ -29,16 +29,11 @@ public class QueueChannelMetrics extends PollableChannelMetrics { private final QueueChannel channel; - /** - * @param channel - * @param name - */ public QueueChannelMetrics(QueueChannel channel, String name) { - super(name); + super(channel, name); this.channel = channel; } - @ManagedMetric(metricType = MetricType.GAUGE, displayName = "QueueChannel Queue Size") public int getQueueSize() { return channel.getQueueSize(); diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectFirstTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectFirstTests-context.xml new file mode 100644 index 0000000000..0a0e87081d --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectFirstTests-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectSecondTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectSecondTests-context.xml new file mode 100644 index 0000000000..e3b5d4edf7 --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectSecondTests-context.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectTests.java new file mode 100644 index 0000000000..a14042e08f --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanAutoDetectTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2010 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.integration.jmx.config; + +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.After; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * @author Dave Syer + * @since 2.0 + */ +public class MBeanAutoDetectTests { + + private MBeanServer server; + + private ClassPathXmlApplicationContext context; + + @After + public void close() { + if (context != null) { + context.close(); + } + } + + @Test + public void testRouterMBeanExistsWhenDefinedFirst() throws Exception { + context = new ClassPathXmlApplicationContext("MBeanAutoDetectFirstTests-context.xml", getClass()); + server = context.getBean(MBeanServer.class); + // System.err.println(server.queryNames(new ObjectName("test.MBeanAutoDetectFirst:*"), null)); + Set names = server.queryNames( + new ObjectName("test.MBeanAutoDetectFirst:type=ExpressionEvaluatingRouter,*"), null); + assertEquals(1, names.size()); + } + + @Test + @Ignore // Fails because the MBeanExporter is created before the router + public void testRouterMBeanExistsWhenDefinedSecond() throws Exception { + context = new ClassPathXmlApplicationContext("MBeanAutoDetectSecondTests-context.xml", getClass()); + server = context.getBean(MBeanServer.class); + // System.err.println(server.queryNames(new ObjectName("test.MBeanAutoDetectFirst:*"), null)); + Set names = server.queryNames( + new ObjectName("test.MBeanAutoDetectFirst:type=ExpressionEvaluatingRouter,*"), null); + assertEquals(1, names.size()); + } + +} diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanGatewayTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanGatewayTests-context.xml new file mode 100644 index 0000000000..96f478f0f3 --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanGatewayTests-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTestsNone-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanNoneTests-context.xml similarity index 100% rename from spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTestsNone-context.xml rename to spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanNoneTests-context.xml diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTestsSwitch-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanSwitchTests-context.xml similarity index 100% rename from spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTestsSwitch-context.xml rename to spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanSwitchTests-context.xml diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTests.java index 5caae68c2b..1b22c8f075 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanTests.java @@ -14,11 +14,15 @@ package org.springframework.integration.jmx.config; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; import javax.management.ObjectName; @@ -48,9 +52,10 @@ public class RouterMBeanTests { @Parameters public static List getParameters() { return Arrays.asList( - new Object[] { RouterMBeanTests.class.getSimpleName() + "-context.xml" }, - new Object[] { RouterMBeanTests.class.getSimpleName() + "None-context.xml" }, - new Object[] { RouterMBeanTests.class.getSimpleName() + "Switch-context.xml" }); + new Object[] { "RouterMBeanTests-context.xml" }, + new Object[] { "RouterMBeanGatewayTests-context.xml" }, + new Object[] { "RouterMBeanNoneTests-context.xml" }, + new Object[] { "RouterMBeanSwitchTests-context.xml" }); } @After @@ -68,11 +73,50 @@ public class RouterMBeanTests { assertEquals(1, names.size()); } + @Test + public void testInputChannelMBeanExists() throws Exception { + // System.err.println(server.queryNames(new ObjectName("test.RouterMBean:type=MessageChannel,*"), null)); + Set names = server.queryNames( + new ObjectName("test.RouterMBean:type=MessageChannel,name=testChannel,*"), null); + assertEquals(1, names.size()); + } + + @Test + public void testErrorChannelMBeanExists() throws Exception { + Set names = server.queryNames( + new ObjectName("test.RouterMBean:type=MessageChannel,name=errorChannel,*"), null); + assertEquals(1, names.size()); + } + @Test public void testRouterMBeanOnlyRegisteredOnce() throws Exception { // System.err.println(server.queryNames(new ObjectName("*:type=MessageHandler,*"), null)); - // The errorLogger and the router - assertEquals(2, server.queryNames(new ObjectName("test.RouterMBean:type=MessageHandler,*"), null).size()); + Set names = server.queryNames(new ObjectName("test.RouterMBean:type=MessageHandler,name=ptRouter,*"), null); + assertEquals(1, names.size()); + } + + @Test + public void testRouterMBeanHasTrackableComponent() throws Exception { + // System.err.println(server.queryNames(new ObjectName("test.RouterMBean:*"), null)); + Set names = server.queryNames(new ObjectName("test.RouterMBean:type=ExpressionEvaluatingRouter,*"), null); + Map infos = new HashMap(); + for (MBeanOperationInfo info : server.getMBeanInfo(names.iterator().next()).getOperations()) { + infos.put(info.getName(), info); + } + // System.err.println(infos); + assertNotNull(infos.get("setShouldTrack")); + } + + @Test + public void testVanillaRouterMBeanRegistration() throws Exception { + // System.err.println(server.queryNames(new ObjectName("test.RouterMBean:*"), null)); + Set names = server.queryNames(new ObjectName("test.RouterMBean:type=ExpressionEvaluatingRouter,*"), null); + // The router is exposed... + assertEquals(1, names.size()); + } + + public static interface Service { + void send(String input); } } diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests-context.xml new file mode 100644 index 0000000000..f22c5d6ebd --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests.java new file mode 100644 index 0000000000..bc3445b6db --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/RouterMBeanVanillaTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2010 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.integration.jmx.config; + +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Dave Syer + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class RouterMBeanVanillaTests { + + @Autowired + private MBeanServer server; + + @Test + public void testHandlerMBeanRegistration() throws Exception { + // System.err.println(server.queryNames(new ObjectName("test.RouterMBeanVanilla:*"), null)); + Set names = server.queryNames(new ObjectName("test.RouterMBeanVanilla:type=ExpressionEvaluatingRouter,*"), null); + // The router is exposed... + assertEquals(1, names.size()); + } + + public static class Source { + public String get() { + return "foo"; + } + } + +}