diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java
index 36a430e56d..a2a21181b5 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/DefaultConfiguringBeanFactoryPostProcessor.java
@@ -31,9 +31,13 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.integration.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
+import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationProperties;
+import org.springframework.integration.handler.LoggingHandler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
* A {@link BeanFactoryPostProcessor} implementation that provides default beans for the error handling and task
@@ -126,21 +130,19 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
logger.info("No bean named '" + IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME +
"' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.");
}
- RootBeanDefinition errorChannelDef = new RootBeanDefinition();
- errorChannelDef.setBeanClassName(IntegrationConfigUtils.BASE_PACKAGE
- + ".channel.PublishSubscribeChannel");
- BeanDefinitionHolder errorChannelHolder = new BeanDefinitionHolder(errorChannelDef,
- IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
- BeanDefinitionReaderUtils.registerBeanDefinition(errorChannelHolder, registry);
- BeanDefinitionBuilder loggingHandlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationConfigUtils.BASE_PACKAGE + ".handler.LoggingHandler");
- loggingHandlerBuilder.addConstructorArgValue("ERROR");
- BeanDefinitionBuilder loggingEndpointBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationConfigUtils.BASE_PACKAGE + ".endpoint.EventDrivenConsumer");
- loggingEndpointBuilder.addConstructorArgReference(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
- loggingEndpointBuilder.addConstructorArgValue(loggingHandlerBuilder.getBeanDefinition());
- BeanComponentDefinition componentDefinition = new BeanComponentDefinition(
- loggingEndpointBuilder.getBeanDefinition(), ERROR_LOGGER_BEAN_NAME);
+ registry.registerBeanDefinition(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME,
+ new RootBeanDefinition(PublishSubscribeChannel.class));
+
+ BeanDefinitionBuilder loggingHandlerBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(LoggingHandler.class).addConstructorArgValue("ERROR");
+
+ BeanDefinitionBuilder loggingEndpointBuilder =
+ BeanDefinitionBuilder.genericBeanDefinition(ConsumerEndpointFactoryBean.class)
+ .addPropertyValue("handler", loggingHandlerBuilder.getBeanDefinition())
+ .addPropertyValue("inputChannelName", IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
+
+ BeanComponentDefinition componentDefinition =
+ new BeanComponentDefinition(loggingEndpointBuilder.getBeanDefinition(), ERROR_LOGGER_BEAN_NAME);
BeanDefinitionReaderUtils.registerBeanDefinition(componentDefinition, registry);
}
@@ -152,19 +154,14 @@ class DefaultConfiguringBeanFactoryPostProcessor implements BeanFactoryPostProce
logger.info("No bean named '" + IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME +
"' has been explicitly defined. Therefore, a default ThreadPoolTaskScheduler will be created.");
}
- BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler");
- String taskSchedulerPoolSizeExpression = IntegrationProperties.getExpressionFor(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE);
- schedulerBuilder.addPropertyValue("poolSize", taskSchedulerPoolSizeExpression);
- schedulerBuilder.addPropertyValue("threadNamePrefix", "task-scheduler-");
- schedulerBuilder.addPropertyValue("rejectedExecutionHandler", new CallerRunsPolicy());
- BeanDefinitionBuilder errorHandlerBuilder = BeanDefinitionBuilder.genericBeanDefinition(
- IntegrationConfigUtils.BASE_PACKAGE + ".channel.MessagePublishingErrorHandler");
- errorHandlerBuilder.addPropertyReference("defaultErrorChannel", IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
- schedulerBuilder.addPropertyValue("errorHandler", errorHandlerBuilder.getBeanDefinition());
- BeanComponentDefinition schedulerComponent = new BeanComponentDefinition(
- schedulerBuilder.getBeanDefinition(), IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
- BeanDefinitionReaderUtils.registerBeanDefinition(schedulerComponent, registry);
+ BeanDefinition scheduler = BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class)
+ .addPropertyValue("poolSize", IntegrationProperties.getExpressionFor(IntegrationProperties.TASK_SCHEDULER_POOL_SIZE))
+ .addPropertyValue("threadNamePrefix", "task-scheduler-")
+ .addPropertyValue("rejectedExecutionHandler", new CallerRunsPolicy())
+ .addPropertyValue("errorHandler", new RootBeanDefinition(MessagePublishingErrorHandler.class))
+ .getBeanDefinition();
+
+ registry.registerBeanDefinition(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, scheduler);
}
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
index 511f1f25c6..155f2a49d1 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java
@@ -80,6 +80,7 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
this.registerImplicitChannelCreator(registry);
+ this.registerIntegrationConfigurationBeanFactoryPostProcessor(registry);
this.registerIntegrationEvaluationContext(registry);
this.registerIntegrationProperties(registry);
this.registerHeaderChannelRegistry(registry);
@@ -89,7 +90,6 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
if (importingClassMetadata != null) {
this.registerMessagingAnnotationPostProcessors(importingClassMetadata, registry);
}
- this.registerIntegrationConfigurationBeanFactoryPostProcessor(registry);
this.registerMessageBuilderFactory(registry);
}
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessorTests.java
index 3354e9dc5c..faf8783012 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessorTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/DefaultConfiguringBeanFactoryPostProcessorTests.java
@@ -16,9 +16,13 @@
package org.springframework.integration.config.xml;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
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.context.support.ClassPathXmlApplicationContext;
@@ -26,13 +30,13 @@ import org.springframework.integration.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.test.util.TestUtils;
+import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import org.springframework.util.ErrorHandler;
/**
* @author Mark Fisher
@@ -64,18 +68,22 @@ public class DefaultConfiguringBeanFactoryPostProcessorTests {
public void taskSchedulerRegistered() {
Object taskScheduler = context.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
assertEquals(ThreadPoolTaskScheduler.class, taskScheduler.getClass());
- Object errorHandler = new DirectFieldAccessor(taskScheduler).getPropertyValue("errorHandler");
+ ErrorHandler errorHandler = TestUtils.getPropertyValue(taskScheduler, "errorHandler", ErrorHandler.class);
assertEquals(MessagePublishingErrorHandler.class, errorHandler.getClass());
- Object defaultErrorChannel = new DirectFieldAccessor(errorHandler).getPropertyValue("defaultErrorChannel");
+ MessageChannel defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNull(defaultErrorChannel);
+ errorHandler.handleError(new Throwable());
+ defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNotNull(defaultErrorChannel);
assertEquals(context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME), defaultErrorChannel);
}
-
+
@Test
public void taskSchedulerNotRegisteredMoreThanOnce() {
ClassPathXmlApplicationContext superParentApplicationContext = new ClassPathXmlApplicationContext("superParentApplicationContext.xml", this.getClass());
- ClassPathXmlApplicationContext parentApplicationContext =
+ ClassPathXmlApplicationContext parentApplicationContext =
new ClassPathXmlApplicationContext(new String[]{"org/springframework/integration/config/xml/parentApplicationContext.xml"}, superParentApplicationContext);
- ClassPathXmlApplicationContext childApplicationContext =
+ ClassPathXmlApplicationContext childApplicationContext =
new ClassPathXmlApplicationContext(new String[]{"org/springframework/integration/config/xml/childApplicationContext.xml"}, parentApplicationContext);
TaskScheduler parentScheduler = childApplicationContext.getParent().getBean("taskScheduler", TaskScheduler.class);
TaskScheduler childScheduler = childApplicationContext.getBean("taskScheduler", TaskScheduler.class);
diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/config/DefaultConfigurationTests.java b/spring-integration-file/src/test/java/org/springframework/integration/file/config/DefaultConfigurationTests.java
index 7a64ee3fa3..d8030386e5 100644
--- a/spring-integration-file/src/test/java/org/springframework/integration/file/config/DefaultConfigurationTests.java
+++ b/spring-integration-file/src/test/java/org/springframework/integration/file/config/DefaultConfigurationTests.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2014 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
+ * 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,
@@ -16,56 +16,65 @@
package org.springframework.integration.file.config;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
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.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.test.util.TestUtils;
+import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import org.springframework.util.ErrorHandler;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 1.0.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class DefaultConfigurationTests {
- @Autowired
- private ApplicationContext context;
+ @Autowired
+ private ApplicationContext context;
- @Test
- public void verifyErrorChannel() {
- Object errorChannel = context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
- assertNotNull(errorChannel);
- assertEquals(PublishSubscribeChannel.class, errorChannel.getClass());
- }
+ @Test
+ public void verifyErrorChannel() {
+ Object errorChannel = context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME);
+ assertNotNull(errorChannel);
+ assertEquals(PublishSubscribeChannel.class, errorChannel.getClass());
+ }
- @Test
- public void verifyNullChannel() {
- Object nullChannel = context.getBean(IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME);
- assertNotNull(nullChannel);
- assertEquals(NullChannel.class, nullChannel.getClass());
- }
+ @Test
+ public void verifyNullChannel() {
+ Object nullChannel = context.getBean(IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME);
+ assertNotNull(nullChannel);
+ assertEquals(NullChannel.class, nullChannel.getClass());
+ }
- @Test
- public void verifyTaskScheduler() {
- Object taskScheduler = context.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
- assertEquals(ThreadPoolTaskScheduler.class, taskScheduler.getClass());
- Object errorHandler = new DirectFieldAccessor(taskScheduler).getPropertyValue("errorHandler");
- assertEquals(MessagePublishingErrorHandler.class, errorHandler.getClass());
- Object defaultErrorChannel = new DirectFieldAccessor(errorHandler).getPropertyValue("defaultErrorChannel");
- assertEquals(context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME), defaultErrorChannel);
- }
+ @Test
+ public void verifyTaskScheduler() {
+ Object taskScheduler = context.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
+ assertEquals(ThreadPoolTaskScheduler.class, taskScheduler.getClass());
+ ErrorHandler errorHandler = TestUtils.getPropertyValue(taskScheduler, "errorHandler", ErrorHandler.class);
+ assertEquals(MessagePublishingErrorHandler.class, errorHandler.getClass());
+ MessageChannel defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNull(defaultErrorChannel);
+ errorHandler.handleError(new Throwable());
+ defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNotNull(defaultErrorChannel);
+ assertEquals(context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME), defaultErrorChannel);
+ }
}
diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/DefaultConfigurationTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/config/DefaultConfigurationTests.java
index dab26b32cc..bf2284963b 100644
--- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/DefaultConfigurationTests.java
+++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/DefaultConfigurationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2014 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.
@@ -18,23 +18,27 @@ package org.springframework.integration.http.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
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.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.test.util.TestUtils;
+import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.ErrorHandler;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 1.0.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -63,9 +67,13 @@ public class DefaultConfigurationTests {
public void verifyTaskScheduler() {
Object taskScheduler = context.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
assertEquals(ThreadPoolTaskScheduler.class, taskScheduler.getClass());
- Object errorHandler = new DirectFieldAccessor(taskScheduler).getPropertyValue("errorHandler");
+ ErrorHandler errorHandler = TestUtils.getPropertyValue(taskScheduler, "errorHandler", ErrorHandler.class);
assertEquals(MessagePublishingErrorHandler.class, errorHandler.getClass());
- Object defaultErrorChannel = new DirectFieldAccessor(errorHandler).getPropertyValue("defaultErrorChannel");
+ MessageChannel defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNull(defaultErrorChannel);
+ errorHandler.handleError(new Throwable());
+ defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNotNull(defaultErrorChannel);
assertEquals(context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME), defaultErrorChannel);
}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/DefaultConfigurationTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/DefaultConfigurationTests.java
index fea0cc00ef..ad1f37b16c 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/DefaultConfigurationTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/DefaultConfigurationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2014 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.
@@ -18,23 +18,27 @@ package org.springframework.integration.jms.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
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.channel.MessagePublishingErrorHandler;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.channel.PublishSubscribeChannel;
import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.test.util.TestUtils;
+import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.ErrorHandler;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 1.0.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@@ -63,9 +67,13 @@ public class DefaultConfigurationTests {
public void verifyTaskScheduler() {
Object taskScheduler = context.getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME);
assertEquals(ThreadPoolTaskScheduler.class, taskScheduler.getClass());
- Object errorHandler = new DirectFieldAccessor(taskScheduler).getPropertyValue("errorHandler");
+ ErrorHandler errorHandler = TestUtils.getPropertyValue(taskScheduler, "errorHandler", ErrorHandler.class);
assertEquals(MessagePublishingErrorHandler.class, errorHandler.getClass());
- Object defaultErrorChannel = new DirectFieldAccessor(errorHandler).getPropertyValue("defaultErrorChannel");
+ MessageChannel defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNull(defaultErrorChannel);
+ errorHandler.handleError(new Throwable());
+ defaultErrorChannel = TestUtils.getPropertyValue(errorHandler, "defaultErrorChannel", MessageChannel.class);
+ assertNotNull(defaultErrorChannel);
assertEquals(context.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME), defaultErrorChannel);
}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/EnableIntegrationMBeanExport.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/EnableIntegrationMBeanExport.java
new file mode 100644
index 0000000000..73562db00b
--- /dev/null
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/EnableIntegrationMBeanExport.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 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 java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+import org.springframework.jmx.support.RegistrationPolicy;
+
+/**
+ * Enables default exporting for Spring Integration components in an existing application, as
+ * well as well all {@code @ManagedResource} annotated beans.
+ *
+ *
The resulting {@link org.springframework.integration.monitor.IntegrationMBeanExporter}
+ * bean is defined under the name {@code integrationMbeanExporter}. Alternatively, consider defining a
+ * custom {@link org.springframework.integration.monitor.IntegrationMBeanExporter} bean explicitly.
+ *
+ *
This annotation is modeled after and functionally equivalent to Spring XML's
+ * {@code } element.
+ *
+ * @author Artem Bilan
+ * @since 4.0
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Import(IntegrationMBeanExportConfiguration.class)
+public @interface EnableIntegrationMBeanExport {
+
+ /**
+ * The default domain to use when generating JMX ObjectNames.
+ * Supports property placeholders (e.g. {@code ${project.domain}).
+ */
+ String defaultDomain() default "";
+
+ /**
+ * The bean name of the MBeanServer to which MBeans should be exported. Default is to
+ * use the platform's default MBeanServer.
+ * Supports property placeholders (e.g. {@code ${project.mbeanServer})
+ * and SpEL expression (e.g. {@code #{mbeanServer}).
+ */
+ String server() default "";
+
+ /**
+ * The policy to use when attempting to register an MBean under an
+ * {@link javax.management.ObjectName} that already exists. Defaults to
+ * {@link org.springframework.jmx.support.RegistrationPolicy#FAIL_ON_EXISTING}.
+ */
+ RegistrationPolicy registration() default RegistrationPolicy.FAIL_ON_EXISTING;
+
+ /**
+ * List of simple patterns for component names to register (defaults to '*').
+ * The pattern is applied to all components before they are registered, looking for a match on
+ * the 'name' property of the ObjectName. A MessageChannel and a MessageHandler (for instance)
+ * can share a name because they have a different type, so in that case they would either both
+ * be included or both excluded.
+ * Supports property placeholders (e.g. {@code ${managed.components}). Can be applied for each element.
+ */
+ String[] managedComponents() default "*";
+
+}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/IntegrationMBeanExportConfiguration.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/IntegrationMBeanExportConfiguration.java
new file mode 100644
index 0000000000..a2e70eae6b
--- /dev/null
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/IntegrationMBeanExportConfiguration.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2014 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 java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanServer;
+import javax.management.MBeanServerFactory;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportAware;
+import org.springframework.context.annotation.Role;
+import org.springframework.context.expression.StandardBeanExpressionResolver;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.integration.monitor.IntegrationMBeanExporter;
+import org.springframework.jmx.support.RegistrationPolicy;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * {@code @Configuration} class that registers a {@link IntegrationMBeanExporter} bean.
+ *
+ *
This configuration class is automatically imported when using the
+ * {@link EnableIntegrationMBeanExport} annotation. See its javadoc for complete usage details.
+ *
+ * @author Artem Bilan
+ * @since 4.0
+ */
+@Configuration
+public class IntegrationMBeanExportConfiguration implements ImportAware, EnvironmentAware, BeanFactoryAware {
+
+ private static final String MBEAN_EXPORTER_NAME = "integrationMbeanExporter";
+
+ private AnnotationAttributes attributes;
+
+ private BeanFactory beanFactory;
+
+ private BeanExpressionResolver resolver = new StandardBeanExpressionResolver();
+
+ private BeanExpressionContext expressionContext;
+
+ private Environment environment;
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ if (beanFactory instanceof ConfigurableListableBeanFactory) {
+ this.resolver = ((ConfigurableListableBeanFactory) beanFactory).getBeanExpressionResolver();
+ this.expressionContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
+ }
+ }
+
+ @Override
+ public void setEnvironment(Environment environment) {
+ this.environment = environment;
+ }
+
+ @Override
+ public void setImportMetadata(AnnotationMetadata importMetadata) {
+ Map map = importMetadata.getAnnotationAttributes(EnableIntegrationMBeanExport.class.getName());
+ this.attributes = AnnotationAttributes.fromMap(map);
+ Assert.notNull(this.attributes,
+ "@EnableIntegrationMBeanExport is not present on importing class " + importMetadata.getClassName());
+ }
+
+ @Bean(name = MBEAN_EXPORTER_NAME)
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public IntegrationMBeanExporter mbeanExporter() {
+ IntegrationMBeanExporter exporter = new IntegrationMBeanExporter();
+ exporter.setRegistrationPolicy(this.attributes.getEnum("registration"));
+ setupDomain(exporter);
+ setupServer(exporter);
+ setupComponentNamePatterns(exporter);
+ return exporter;
+ }
+
+ private void setupDomain(IntegrationMBeanExporter exporter) {
+ String defaultDomain = this.attributes.getString("defaultDomain");
+ if (defaultDomain != null && this.environment != null) {
+ defaultDomain = this.environment.resolvePlaceholders(defaultDomain);
+ }
+ if (StringUtils.hasText(defaultDomain)) {
+ exporter.setDefaultDomain(defaultDomain);
+ }
+ }
+
+ private void setupServer(IntegrationMBeanExporter exporter) {
+ String server = this.attributes.getString("server");
+ if (server != null && this.environment != null) {
+ server = this.environment.resolvePlaceholders(server);
+ }
+ if (StringUtils.hasText(server)) {
+ MBeanServer bean = null;
+ if (server.startsWith("#{") && server.endsWith("}")) {
+ bean = (MBeanServer) this.resolver.evaluate(server, this.expressionContext);
+ }
+ else {
+ bean = this.beanFactory.getBean(server, MBeanServer.class);
+ }
+ exporter.setServer(bean);
+ }
+ else {
+ exporter.setServer(MBeanServerFactory.createMBeanServer());
+ }
+ }
+
+ private void setupComponentNamePatterns(IntegrationMBeanExporter exporter) {
+ List patterns = new ArrayList();
+ String[] managedComponents = this.attributes.getStringArray("managedComponents");
+ for (String managedComponent : managedComponents) {
+ String pattern = this.environment.resolvePlaceholders(managedComponent);
+ patterns.addAll(StringUtils.commaDelimitedListToSet(pattern));
+ }
+ exporter.setComponentNamePatterns(patterns.toArray(new String[patterns.size()]));
+ }
+
+}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxIntegrationConfigurationInitializer.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxIntegrationConfigurationInitializer.java
index 78225b4594..ad62f6d659 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxIntegrationConfigurationInitializer.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/JmxIntegrationConfigurationInitializer.java
@@ -18,6 +18,8 @@ package org.springframework.integration.jmx.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.integration.config.IntegrationConfigurationInitializer;
import org.springframework.integration.monitor.IntegrationMBeanExporter;
@@ -37,11 +39,9 @@ public class JmxIntegrationConfigurationInitializer implements IntegrationConfig
}
private void registerMBeanExporterHelperIfNecessary(ConfigurableListableBeanFactory beanFactory) {
- if (!beanFactory.getBeansOfType(IntegrationMBeanExporter.class, false, false).isEmpty()) {
- MBeanExporterHelper mBeanExporterHelper = new MBeanExporterHelper();
- mBeanExporterHelper.postProcessBeanFactory(beanFactory);
- beanFactory.registerSingleton(MBEAN_EXPORTER_HELPER_BEAN_NAME, mBeanExporterHelper);
- beanFactory.initializeBean(mBeanExporterHelper, MBEAN_EXPORTER_HELPER_BEAN_NAME);
+ if (beanFactory.getBeanNamesForType(IntegrationMBeanExporter.class).length > 0) {
+ ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(MBEAN_EXPORTER_HELPER_BEAN_NAME,
+ new RootBeanDefinition(MBeanExporterHelper.class));
}
}
diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java
index f25b838558..7fb50e065b 100644
--- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java
+++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/MBeanExporterHelper.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2002-2011 the original author or authors.
- *
+ * Copyright 2002-2014 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.
@@ -20,42 +20,66 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.Ordered;
+import org.springframework.core.type.StandardMethodMetadata;
import org.springframework.integration.monitor.IntegrationMBeanExporter;
import org.springframework.jmx.export.MBeanExporter;
+import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Most likely a temporary class mainly needed to address issue described in INT-2307.
- * It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list
- * of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list
+ * It helps in eliminating conflicts when more than one MBeanExporter is present. It creates a list
+ * of bean names that will be exported by the IntegrationMBeanExporter and merges it with the list
* of 'excludedBeans' of MBeanExporter so it will not attempt to export them again.
*
* @author Oleg Zhurakousky
+ * @author Artem Bilan
* @since 2.1
*
*/
-class MBeanExporterHelper implements BeanFactoryPostProcessor,
- BeanPostProcessor, Ordered, BeanFactoryAware {
+class MBeanExporterHelper implements BeanPostProcessor, Ordered, BeanFactoryAware, InitializingBean {
private final static String EXCLUDED_BEANS_PROPERTY_NAME = "excludedBeans";
-
+
private final static String SI_ROOT_PACKAGE = "org.springframework.integration.";
private final Set siBeanNames = new HashSet();
- private volatile BeanFactory beanFactory;
+ private volatile DefaultListableBeanFactory beanFactory;
private volatile boolean capturedAutoChannelCandidates;
-
+
+ @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
- this.beanFactory = beanFactory;
+ Assert.isInstanceOf(DefaultListableBeanFactory.class, beanFactory);
+ this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (this.beanFactory != null) {
+ String[] beanNames = this.beanFactory.getBeanDefinitionNames();
+ for (String beanName : beanNames) {
+ BeanDefinition def = this.beanFactory.getBeanDefinition(beanName);
+ String className = def.getBeanClassName();
+ if (className == null && def.getSource() instanceof StandardMethodMetadata) {
+ className = ((StandardMethodMetadata) def.getSource()).getIntrospectedMethod().getReturnType().getName();
+ }
+ if (StringUtils.hasText(className)){
+ if (className.startsWith(SI_ROOT_PACKAGE) && !(className.endsWith(IntegrationMBeanExporter.class.getName()))){
+ siBeanNames.add(beanName);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!this.capturedAutoChannelCandidates && this.beanFactory != null) {
Object autoCreateChannelCandidates = beanFactory.getBean("$autoCreateChannelCandidates");
@@ -77,30 +101,18 @@ class MBeanExporterHelper implements BeanFactoryPostProcessor,
}
mbeDfa.setPropertyValue(EXCLUDED_BEANS_PROPERTY_NAME, siBeanNames);
}
+
return bean;
}
-
+ @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
-
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
- String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
- for (String beanName : beanDefinitionNames) {
- BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
-
- String className = bd.getBeanClassName();
- if (StringUtils.hasText(className)){
- if (className.startsWith(SI_ROOT_PACKAGE) && !(className.endsWith(IntegrationMBeanExporter.class.getName()))){
- siBeanNames.add(beanName);
- }
- }
- }
- }
-
+ @Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
+
}
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterHelperTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterHelperTests.java
deleted file mode 100644
index 1f8bd45152..0000000000
--- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/MBeanExporterHelperTests.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2002-2011 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.junit.Test;
-
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.beans.factory.support.RootBeanDefinition;
-
-/**
- * @author Oleg Zhurakousky
- *
- */
-public class MBeanExporterHelperTests {
-
- @Test
- public void testNoNpeWhenClassNameIsMissing(){
- DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
- RootBeanDefinition bd = new RootBeanDefinition();
- factory.registerBeanDefinition("foo", bd);
-
- MBeanExporterHelper helper = new MBeanExporterHelper();
- helper.postProcessBeanFactory(factory);
- }
-
- @Test
- public void testNoNpeWithAbstractBean(){
- DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
- RootBeanDefinition abstractBd = new RootBeanDefinition();
- abstractBd.setAbstract(true);
- abstractBd.setBeanClass(String.class);
- factory.registerBeanDefinition("abstractFoo", abstractBd);
- RootBeanDefinition concreteBd = new RootBeanDefinition(abstractBd);
-
- factory.registerBeanDefinition("concreteFoo", concreteBd);
-
- MBeanExporterHelper helper = new MBeanExporterHelper();
- helper.postProcessBeanFactory(factory);
- }
-}
diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java
new file mode 100644
index 0000000000..7c605f7cb3
--- /dev/null
+++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/configuration/EnableMBeanExportTests.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014 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.configuration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.integration.channel.QueueChannel;
+import org.springframework.integration.config.EnableIntegration;
+import org.springframework.integration.context.IntegrationContextUtils;
+import org.springframework.integration.jmx.config.EnableIntegrationMBeanExport;
+import org.springframework.integration.monitor.IntegrationMBeanExporter;
+import org.springframework.integration.test.util.TestUtils;
+import org.springframework.jmx.support.MBeanServerFactoryBean;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @author Artem Bilan
+ * @since 4.0
+ */
+@ContextConfiguration(initializers = EnableMBeanExportTests.EnvironmentApplicationContextInitializer.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+@DirtiesContext
+public class EnableMBeanExportTests {
+
+ @Autowired
+ private BeanFactory beanFactory;
+
+ @Autowired
+ private IntegrationMBeanExporter exporter;
+
+ @Autowired
+ private MBeanServer mBeanServer;
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testEnableMBeanExport() throws MalformedObjectNameException, ClassNotFoundException {
+ assertTrue(AopUtils.isAopProxy(this.beanFactory.getBean(IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME)));
+ assertTrue(AopUtils.isAopProxy(this.beanFactory.getBean(IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME)));
+
+ assertSame(this.mBeanServer, this.exporter.getServer());
+ String[] componentNamePatterns = TestUtils.getPropertyValue(this.exporter, "componentNamePatterns", String[].class);
+ for (String componentNamePattern : componentNamePatterns) {
+ assertThat(componentNamePattern, Matchers.isOneOf("input", "in*"));
+ assertThat(componentNamePattern, Matchers.not(Matchers.equalTo("*")));
+ }
+ Set names = this.mBeanServer.queryNames(ObjectName.getInstance("FOO:type=MessageChannel,*"), null);
+ // Only one registered (out of >2 available)
+ assertEquals(1, names.size());
+ assertEquals("input", names.iterator().next().getKeyProperty("name"));
+ names = this.mBeanServer.queryNames(ObjectName.getInstance("FOO:type=MessageHandler,*"), null);
+ assertEquals(0, names.size());
+
+ Class> clazz = Class.forName("org.springframework.integration.jmx.config.MBeanExporterHelper");
+ List