From 2e4f1e5b5ec49bed061b004d6cce9cf34c1fc292 Mon Sep 17 00:00:00 2001 From: David Syer Date: Fri, 3 Sep 2010 13:39:49 +0000 Subject: [PATCH] INT-1418: add control-bus --- .../AttributePollingChannelAdapterParser.java | 5 + .../jmx/config/ControlBusFactoryBean.java | 55 +++++++ .../jmx/config/ControlBusParser.java | 51 +++++++ .../jmx/config/JmxNamespaceHandler.java | 1 + .../jmx/config/MBeanExporterParser.java | 37 ++--- ...ficationListeningChannelAdapterParser.java | 5 + ...icationPublishingChannelAdapterParser.java | 5 + ...OperationInvokingChannelAdapterParser.java | 5 + ...perationInvokingOutboundGatewayParser.java | 2 +- .../jmx/config/spring-integration-jmx-2.0.xsd | 135 ++++++++++-------- .../config/ControlBusParserTests-context.xml | 24 ++++ .../jmx/config/ControlBusParserTests.java | 54 +++++++ .../MBeanExporterParserTests-context.xml | 2 +- .../jmx/config/MBeanExporterParserTests.java | 8 +- 14 files changed, 297 insertions(+), 92 deletions(-) create mode 100644 spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusFactoryBean.java create mode 100644 spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusParser.java create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests-context.xml create mode 100644 spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests.java diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/AttributePollingChannelAdapterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/AttributePollingChannelAdapterParser.java index 8be18ea15e..03bc5bfba8 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/AttributePollingChannelAdapterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/AttributePollingChannelAdapterParser.java @@ -30,6 +30,11 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils; */ public class AttributePollingChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + @Override protected String parseSource(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition( diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusFactoryBean.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusFactoryBean.java new file mode 100644 index 0000000000..9e7287f38f --- /dev/null +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusFactoryBean.java @@ -0,0 +1,55 @@ +/* + * 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 org.springframework.beans.factory.FactoryBean; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.control.ControlBus; +import org.springframework.integration.core.SubscribableChannel; +import org.springframework.integration.monitor.IntegrationMBeanExporter; + +/** + * @author Dave Syer + * @since 2.0 + * + */ +public class ControlBusFactoryBean implements FactoryBean { + + private final SubscribableChannel operationChannel; + private final IntegrationMBeanExporter exporter; + + public ControlBusFactoryBean(IntegrationMBeanExporter exporter, SubscribableChannel operationChannel) { + this.exporter = exporter; + this.operationChannel = operationChannel; + } + + public ControlBusFactoryBean(IntegrationMBeanExporter exporter) { + this(exporter, new DirectChannel()); + } + + public ControlBus getObject() throws Exception { + return new ControlBus(exporter, exporter.getServer(), operationChannel); + } + + public Class getObjectType() { + return ControlBus.class; + } + + public boolean isSingleton() { + return true; + } + +} diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusParser.java new file mode 100644 index 0000000000..4e1ed05dbe --- /dev/null +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/ControlBusParser.java @@ -0,0 +1,51 @@ +/* + * 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 org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * @author Mark Fisher + * @since 2.0 + */ +public class ControlBusParser extends AbstractSingleBeanDefinitionParser { + + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + + @Override + protected String getBeanClassName(Element element) { + return "org.springframework.integration.jmx.config.ControlBusFactoryBean"; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); + builder.addConstructorArgReference(element.getAttribute("mbean-exporter")); + if (StringUtils.hasLength(element.getAttribute("operation-channel"))) { + builder.addConstructorArgReference(element.getAttribute("operation-channel")); + + } + } + +} diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxNamespaceHandler.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxNamespaceHandler.java index a47d725e08..4ae2ece98b 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxNamespaceHandler.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxNamespaceHandler.java @@ -34,6 +34,7 @@ public class JmxNamespaceHandler extends AbstractIntegrationNamespaceHandler { this.registerBeanDefinitionParser("notification-listening-channel-adapter", new NotificationListeningChannelAdapterParser()); this.registerBeanDefinitionParser("notification-publishing-channel-adapter", new NotificationPublishingChannelAdapterParser()); this.registerBeanDefinitionParser("mbean-exporter", new MBeanExporterParser()); + this.registerBeanDefinitionParser("control-bus", new ControlBusParser()); } } 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 e3c6797000..1af4ef2837 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 @@ -19,9 +19,8 @@ package org.springframework.integration.jmx.config; import javax.management.MBeanServerFactory; import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.util.StringUtils; @@ -31,23 +30,24 @@ import org.w3c.dom.Element; * @author Mark Fisher * @since 2.0 */ -public class MBeanExporterParser extends AbstractBeanDefinitionParser { +public class MBeanExporterParser extends AbstractSingleBeanDefinitionParser { + + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } @Override - protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + protected String getBeanClassName(Element element) { + return "org.springframework.integration.monitor.IntegrationMBeanExporter"; + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { Object mbeanServer = getMBeanServer(element, parserContext); - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition("org.springframework.integration.monitor.IntegrationMBeanExporter"); builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "domain"); builder.addPropertyValue("server", mbeanServer); - if (StringUtils.hasText(element.getAttribute("operation-channel"))) { - AbstractBeanDefinition controlBus = getControlBus(element, parserContext, mbeanServer, builder - .getRawBeanDefinition()); - parserContext.getRegistry().registerBeanDefinition( - parserContext.getReaderContext().generateBeanName(controlBus), controlBus); - } - return builder.getBeanDefinition(); } private Object getMBeanServer(Element element, ParserContext parserContext) { @@ -60,15 +60,4 @@ public class MBeanExporterParser extends AbstractBeanDefinitionParser { } } - private AbstractBeanDefinition getControlBus(Element element, ParserContext parserContext, Object mbeanServer, - Object mbeanExporter) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition("org.springframework.integration.control.ControlBus"); - builder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); - builder.addConstructorArgValue(mbeanExporter); - builder.addConstructorArgValue(mbeanServer); - builder.addConstructorArgReference(element.getAttribute("operation-channel")); - return builder.getBeanDefinition(); - } - } diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationListeningChannelAdapterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationListeningChannelAdapterParser.java index 1ad7eb7859..36739b5257 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationListeningChannelAdapterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationListeningChannelAdapterParser.java @@ -30,6 +30,11 @@ import org.springframework.util.StringUtils; */ public class NotificationListeningChannelAdapterParser extends AbstractSimpleBeanDefinitionParser { + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + @Override protected String getBeanClassName(Element element) { return "org.springframework.integration.jmx.NotificationListeningMessageProducer"; diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParser.java index a2c95e35ba..501fbb80d0 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/NotificationPublishingChannelAdapterParser.java @@ -30,6 +30,11 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils; */ public class NotificationPublishingChannelAdapterParser extends AbstractOutboundChannelAdapterParser { + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + @Override protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition( diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParser.java index ba5739a305..ad1134798b 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingChannelAdapterParser.java @@ -30,6 +30,11 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils; */ public class OperationInvokingChannelAdapterParser extends AbstractOutboundChannelAdapterParser { + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + @Override protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition( diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java index 36de73a505..fd05a28fd5 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java @@ -25,7 +25,7 @@ import org.w3c.dom.Element; * @author Oleg Zhurakousky * @since 2.0 */ -public class OperationInvokingOutboundGatewayParser extends AbstractConsumerEndpointParser{ +public class OperationInvokingOutboundGatewayParser extends AbstractConsumerEndpointParser { @Override protected String getInputChannelAttributeName() { diff --git a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-2.0.xsd b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-2.0.xsd index f0d0305833..7ba105b519 100644 --- a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-2.0.xsd +++ b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-2.0.xsd @@ -1,17 +1,12 @@ - + - - - + + + - Defines an inbound Channel Adapter that polls for JMX attribute values. + Defines an inbound Channel Adapter that polls for JMX attribute values. - + - - - + + @@ -41,15 +35,15 @@ - Defines an outbound Gateway which allows for Message-driven invocation of managed operations that return values + Defines an outbound Gateway which allows for Message-driven invocation of managed operations that + return values - - - + + @@ -58,14 +52,13 @@ - Defines an outbound Channel Adapter for invoking JMX operations. + Defines an outbound Channel Adapter for invoking JMX operations. - - + @@ -74,16 +67,15 @@ - Defines an inbound Channel Adapter that listens for JMX notifications. + Defines an inbound Channel Adapter that listens for JMX notifications. - - - - + + + @@ -92,14 +84,13 @@ - Defines an outbound Channel Adapter that publishes JMX notifications. + Defines an outbound Channel Adapter that publishes JMX notifications. - - + @@ -108,40 +99,63 @@ - Exports Message Channels and Endpoints as MBeans - and optionally connects to an "operation channel". + Exports Message Channels and Endpoints as MBeans. - - The domain name for the MBeans exported by this Control Bus. + The domain name for the MBeans exported by this Exporter. - - - - If provided a control bus will be created and subscribed to the Message Channel. - The channel can then be used to send operation commands to - this Control Bus. It must implement SubscribableChannel. - - - - - - - - + + + + Control bus accepts control messages for channels and endpoints on an (optional) "operation + channel". + + + + + + + + A reference to the MBeanExporter created using <mbean-exporter/> in this namespace. + + + + + + + + + + + + If provided a control bus will be created and subscribed to the Message Channel. + The channel can + then be used to send operation commands to + this Control Bus. It must implement SubscribableChannel. + + + + + + + + + + + @@ -150,12 +164,12 @@ - - + + - + @@ -164,19 +178,20 @@ - - + + - + + - - - Defines the name of the MBeanServer bean to connect to. + + + Defines the name of the MBeanServer bean to connect to. - + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests-context.xml new file mode 100644 index 0000000000..f79bf94597 --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests.java new file mode 100644 index 0000000000..71c885450f --- /dev/null +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/ControlBusParserTests.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 javax.management.MBeanServer; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.integration.control.ControlBus; +import org.springframework.jmx.export.MBeanExporter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * @author Mark Fisher + * @since 2.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class ControlBusParserTests { + + @Autowired + private ApplicationContext context; + + @Test + public void test() throws InterruptedException { + ControlBus controlBus = this.context.getBean(ControlBus.class); + assertEquals(controlBus.getOperationChannel(), this.context.getBean("testChannel")); + MBeanServer server = this.context.getBean("mbs", MBeanServer.class); + MBeanExporter exporter = (MBeanExporter) new DirectFieldAccessor(controlBus).getPropertyValue("exporter"); + assertEquals(server, exporter.getServer()); + exporter.destroy(); + } + +} diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml index 9275d7da3d..c19acfc5d3 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests-context.xml @@ -17,6 +17,6 @@ - + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java index fab13d864f..6d76d6a468 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterParserTests.java @@ -22,11 +22,9 @@ import javax.management.MBeanServer; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.integration.control.ControlBus; -import org.springframework.jmx.export.MBeanExporter; +import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -43,10 +41,8 @@ public class MBeanExporterParserTests { @Test public void test() throws InterruptedException { - ControlBus controlBus = this.context.getBean(ControlBus.class); - assertEquals(controlBus.getOperationChannel(), this.context.getBean("testChannel")); + IntegrationMBeanExporter exporter = this.context.getBean(IntegrationMBeanExporter.class); MBeanServer server = this.context.getBean("mbs", MBeanServer.class); - MBeanExporter exporter = (MBeanExporter) new DirectFieldAccessor(controlBus).getPropertyValue("exporter"); assertEquals(server, exporter.getServer()); exporter.destroy(); }