INT-3330 EnableIntegrationMBeanExport Annotation

JIRA: https://jira.spring.io/browse/INT-3330

INT-3330: Enable SpEL evaluation

INT-3330: Polishing for `MBeanExporterHelper`

INT-3330: Fix `errorChannel` early access

INT-3330: Polishing according PR comments

Polishing - copyrights, author, docs
This commit is contained in:
Artem Bilan
2014-03-18 20:57:36 +02:00
committed by Gary Russell
parent 1d6e80ecd0
commit 97c270c0e2
23 changed files with 643 additions and 196 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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.
*
* <p>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.
*
* <p>This annotation is modeled after and functionally equivalent to Spring XML's
* {@code <int-jmx:mbean-export/>} 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 "*";
}

View File

@@ -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.
* <p/>
* <p>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<String, Object> 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.<RegistrationPolicy>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<String> patterns = new ArrayList<String>();
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()]));
}
}

View File

@@ -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));
}
}

View File

@@ -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<String> siBeanNames = new HashSet<String>();
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;
}
}

View File

@@ -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);
}
}

View File

@@ -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<ObjectName> 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<Object> beanPostProcessors = TestUtils.getPropertyValue(beanFactory, "beanPostProcessors", List.class);
Object mBeanExporterHelper = null;
for (Object beanPostProcessor : beanPostProcessors) {
if (clazz.isAssignableFrom(beanPostProcessor.getClass())) {
mBeanExporterHelper = beanPostProcessor;
break;
}
}
assertNotNull(mBeanExporterHelper);
assertTrue(TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames", Set.class).contains("input"));
assertTrue(TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames", Set.class).contains("output"));
}
@Configuration
@EnableIntegration
@EnableIntegrationMBeanExport(server = "#{mbeanServer}", defaultDomain = "${managed.domain}", managedComponents = {"input", "${managed.component}"})
public static class ContextConfiguration {
@Bean
public MBeanServerFactoryBean mbeanServer() {
return new MBeanServerFactoryBean();
}
@Bean
public QueueChannel input() {
return new QueueChannel();
}
@Bean
public QueueChannel output() {
return new QueueChannel();
}
}
public static class EnvironmentApplicationContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
@Override
public void initialize(GenericApplicationContext applicationContext) {
applicationContext.setEnvironment(new MockEnvironment()
.withProperty("managed.component", "input,in*")
.withProperty("managed.domain", "FOO"));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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
@@ -13,6 +13,7 @@
package org.springframework.integration_.mbeanexporterhelper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
@@ -33,6 +34,7 @@ import org.springframework.jmx.export.MBeanExporter;
/**
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*
*/
public class Int2307Tests {
@@ -70,9 +72,17 @@ public class Int2307Tests {
assertEquals(4, count);
Class<?> clazz = Class.forName("org.springframework.integration.jmx.config.MBeanExporterHelper");
Object mBeanExporterHelper = context.getBean(clazz);
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("z"));
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("zz"));
List<Object> beanPostProcessors = TestUtils.getPropertyValue(context, "beanFactory.beanPostProcessors", List.class);
Object mBeanExporterHelper = null;
for (Object beanPostProcessor : beanPostProcessors) {
if (clazz.isAssignableFrom(beanPostProcessor.getClass())) {
mBeanExporterHelper = beanPostProcessor;
break;
}
}
assertNotNull(mBeanExporterHelper);
assertTrue(TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames", Set.class).contains("z"));
assertTrue(TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames", Set.class).contains("zz"));
// make sure there are no duplicate MBean ObjectNames if 2 contexts loaded from same config
new ClassPathXmlApplicationContext("single-config.xml", this.getClass());
@@ -90,8 +100,16 @@ public class Int2307Tests {
assertTrue(excludedBeanNames.contains("y"));
assertTrue(excludedBeanNames.contains("foo")); // non SI bean
Class<?> clazz = Class.forName("org.springframework.integration.jmx.config.MBeanExporterHelper");
Object mBeanExporterHelper = context.getBean(clazz);
assertTrue(((Set<String>)TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames")).contains("z"));
List<Object> beanPostProcessors = TestUtils.getPropertyValue(context, "beanFactory.beanPostProcessors", List.class);
Object mBeanExporterHelper = null;
for (Object beanPostProcessor : beanPostProcessors) {
if (clazz.isAssignableFrom(beanPostProcessor.getClass())) {
mBeanExporterHelper = beanPostProcessor;
break;
}
}
assertNotNull(mBeanExporterHelper);
assertTrue(TestUtils.getPropertyValue(mBeanExporterHelper, "siBeanNames", Set.class).contains("z"));
}
public static class Foo{}

View File

@@ -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.mail.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);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 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.rmi.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);
}

View File

@@ -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.security.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);
}

View File

@@ -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.stream.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);
}

View File

@@ -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.ws.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);
}

View File

@@ -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.xml.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);
}

View File

@@ -140,12 +140,12 @@
<section id="tree-polling-channel-adapter">
<title>Tree Polling Channel Adapter</title>
<para>
The <emphasis>Tree Polling Channel Adapter</emphasis> queries the JMX MBean tree and
sends a message with a payload that is the graph of objects that matches the query. By
default the MBeans are mapped to primitives and simple Objects like Map, List and arrays -
permitting simple transformation, for example, to JSON. An MBeanServer reference is also
required, but it will automatically check for a bean named <emphasis>mbeanServer</emphasis>
by default, just like the <emphasis>Notification-listening Channel Adapter</emphasis>
The <emphasis>Tree Polling Channel Adapter</emphasis> queries the JMX MBean tree and
sends a message with a payload that is the graph of objects that matches the query. By
default the MBeans are mapped to primitives and simple Objects like Map, List and arrays -
permitting simple transformation, for example, to JSON. An MBeanServer reference is also
required, but it will automatically check for a bean named <emphasis>mbeanServer</emphasis>
by default, just like the <emphasis>Notification-listening Channel Adapter</emphasis>
described above. A basic configuration would be:
</para>
<programlisting language="xml"><![CDATA[<int-jmx:tree-polling-channel-adapter id="adapter"
@@ -277,7 +277,27 @@
It also has a useful operation, as discussed in <xref linkend="jmx-mbean-shutdown"/>.
</para>
</important>
<para>
Starting with <emphasis>Spring Integration 4.0</emphasis> the <code>@EnableIntegrationMBeanExport</code>
annotation has been introduced for convenient configuration of a default
(<code>integrationMbeanExporter</code>) bean of type
<classname>IntegrationMBeanExporter</classname> with several useful options
at the <code>@Configuration</code> class level. For example:
<programlisting language="java"><![CDATA[@Configuration
@EnableIntegration
@EnableIntegrationMBeanExport(server = "mbeanServer", managedComponents = "input")
public class ContextConfiguration {
@Bean
public MBeanServerFactoryBean mbeanServer() {
return new MBeanServerFactoryBean();
}
}]]></programlisting>
If there is a need to provide more options, or have several <classname>IntegrationMBeanExporter</classname> beans
e.g. for different MBean Servers, or to avoid conflicts with the standard Spring <classname>MBeanExporter</classname>
(e.g. via <code>@EnableMBeanExport</code>), you can simply configure an <classname>IntegrationMBeanExporter</classname>
as a generic bean.
</para>
<section id="jmx-mbean-features">
<title>MBean ObjectNames</title>

View File

@@ -94,6 +94,13 @@
For more information, see <xref linkend="redis-cms"/>.
</para>
</section>
<section id="4.0-MBeanExport-annotation">
<title>@EnableIntegrationMBeanExport</title>
<para>
The <classname>IntegrationMBeanExporter</classname> can now be enabled with the <code>@EnableIntegrationMBeanExport</code>
annotation in a <code>@Configuration</code> class. For more information, see <xref linkend="jmx-mbean-exporter"/>.
</para>
</section>
</section>
<section id="4.0-general">