From 5d2820dfbeae81699505cfeb3326bac7be26f0fc Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 3 Mar 2014 19:22:36 +0200 Subject: [PATCH] INT-1834: Register Beans for Annotated Handlers JIRA: https://jira.springsource.org/browse/INT-1834 The general issue has been raised about `MessageHistory` for annotated endpoints (`@ServiceActivator`, `@Transformer` etc.) * Register generated `MessageHandler`s as beans with concrete names based on component, method and annotation. * Add tests and docs In addition revert the version for JRuby to 1.7.8 as other latests versions have a NPE issue around `System.console()` Doc Polishing --- build.gradle | 2 +- .../config/IntegrationConfigUtils.java | 2 ++ ...AbstractMethodAnnotationPostProcessor.java | 25 +++++++++++++------ .../integration/config/xml/ChainParser.java | 2 +- .../config/xml/IntegrationNamespaceUtils.java | 3 +-- .../EnableIntegrationTests-context.xml | 12 +-------- .../configuration/EnableIntegrationTests.java | 3 ++- .../EnableIntegrationTests.properties | 2 +- .../SplitterIntegrationTests-context.xml | 6 ++--- .../splitter/SplitterIntegrationTests.java | 2 ++ src/reference/docbook/configuration.xml | 9 +++++++ src/reference/docbook/message-history.xml | 3 ++- src/reference/docbook/whats-new.xml | 4 ++- 13 files changed, 46 insertions(+), 29 deletions(-) diff --git a/build.gradle b/build.gradle index 8201aad3c7..4360525333 100644 --- a/build.gradle +++ b/build.gradle @@ -78,7 +78,7 @@ subprojects { subproject -> javaxMailVersion = '1.4.7' jmsSpecVersion = '1.1.1' jpa21ApiVersion = '1.0.0.Final' - jrubyVersion = '1.7.10' + jrubyVersion = '1.7.8' jschVersion = '0.1.50' jsonpathVersion = '0.9.1' junitVersion = '4.11' diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java index 47ddf89f6d..a4aebfb098 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationConfigUtils.java @@ -32,6 +32,8 @@ public final class IntegrationConfigUtils { public static final String BASE_PACKAGE = "org.springframework.integration"; + public static final String HANDLER_ALIAS_SUFFIX = ".handler"; + public static void registerSpelFunctionBean(BeanDefinitionRegistry registry, String functionId, String className, String methodSignature) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpelFunctionFactoryBean.class) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java index 0b45706140..cd559a0b05 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/annotation/AbstractMethodAnnotationPostProcessor.java @@ -25,11 +25,11 @@ import java.util.List; import org.aopalliance.aop.Advice; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.Order; +import org.springframework.integration.config.IntegrationConfigUtils; import org.springframework.integration.context.Orderable; import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.integration.endpoint.EventDrivenConsumer; @@ -40,6 +40,7 @@ import org.springframework.messaging.MessageHandler; import org.springframework.messaging.SubscribableChannel; import org.springframework.messaging.core.DestinationResolver; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -70,7 +71,7 @@ public abstract class AbstractMethodAnnotationPostProcessor annotationType) { + String baseName = originalBeanName + "." + method.getName() + "." + ClassUtils.getShortNameAsProperty(annotationType); + String name = baseName; + int count = 1; + while (this.beanFactory.containsBean(name)) { + name = baseName + "#" + (++count); + } + return name + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX; + } + /** * Subclasses must implement this method to create the MessageHandler. * diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ChainParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ChainParser.java index 18ccfbba70..900bd26d95 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ChainParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ChainParser.java @@ -140,7 +140,7 @@ public class ChainParser extends AbstractConsumerEndpointParser { return null; } else { - holder = new BeanDefinitionHolder(beanDefinition, handlerComponentName + IntegrationNamespaceUtils.HANDLER_ALIAS_SUFFIX); + holder = new BeanDefinitionHolder(beanDefinition, handlerComponentName + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java index cb1e34e1fb..39413fdc56 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java @@ -61,7 +61,6 @@ public abstract class IntegrationNamespaceUtils { public static final String METHOD_ATTRIBUTE = "method"; public static final String ORDER = "order"; public static final String EXPRESSION_ATTRIBUTE = "expression"; - public static final String HANDLER_ALIAS_SUFFIX = ".handler"; public static final String REQUEST_HANDLER_ADVICE_CHAIN = "request-handler-advice-chain"; public static final String AUTO_STARTUP = "auto-startup"; public static final String PHASE = "phase"; @@ -382,7 +381,7 @@ public abstract class IntegrationNamespaceUtils { String[] handlerAlias = null; String id = element.getAttribute(ID_ATTRIBUTE); if (StringUtils.hasText(id)) { - handlerAlias = new String[] {id + HANDLER_ALIAS_SUFFIX}; + handlerAlias = new String[] {id + IntegrationConfigUtils.HANDLER_ALIAS_SUFFIX}; } return handlerAlias; } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml index 141d30333a..38ca103759 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests-context.xml @@ -6,16 +6,6 @@ http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd"> - - - - - - input - publishedChannel - - - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java index 24e5c7ff0c..4c758df43f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.java @@ -93,6 +93,7 @@ public class EnableIntegrationTests { assertNotNull(messageHistory); String messageHistoryString = messageHistory.toString(); assertThat(messageHistoryString, Matchers.containsString("input")); + assertThat(messageHistoryString, Matchers.containsString("AnnotationTestService.handle.serviceActivator.handler")); assertThat(messageHistoryString, Matchers.not(Matchers.containsString("output"))); receive = this.publishedChannel.receive(1000); @@ -132,7 +133,7 @@ public class EnableIntegrationTests { @IntegrationComponentScan @EnableIntegration @PropertySource("classpath:org/springframework/integration/configuration/EnableIntegrationTests.properties") - @EnableMessageHistory({"input", "publishedChannel"}) + @EnableMessageHistory({"input", "publishedChannel", "*AnnotationTestService*"}) public static class ContextConfiguration { @Bean diff --git a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties index 35117148f8..a843590afd 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties +++ b/spring-integration-core/src/test/java/org/springframework/integration/configuration/EnableIntegrationTests.properties @@ -1 +1 @@ -message.history.tracked.components=input, publishedChannel +message.history.tracked.components=input, publishedChannel, *AnnotationTestService* diff --git a/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests-context.xml index 7f8fb3baf2..4bc8d5dc4e 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests-context.xml @@ -2,7 +2,7 @@ @@ -14,7 +14,7 @@ - @@ -29,4 +29,4 @@ - \ No newline at end of file + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests.java index 8d29693d7b..e2161f52ca 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/splitter/SplitterIntegrationTests.java @@ -29,6 +29,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; @@ -65,6 +66,7 @@ public class SplitterIntegrationTests { MessageChannel inDelimiters; @Autowired + @Qualifier("splitter.handler") MethodInvokingSplitter splitter; private String sentence = "The quick brown fox jumped over the lazy dog"; diff --git a/src/reference/docbook/configuration.xml b/src/reference/docbook/configuration.xml index 4a7409ef1a..9cb6db6218 100644 --- a/src/reference/docbook/configuration.xml +++ b/src/reference/docbook/configuration.xml @@ -326,6 +326,15 @@ public class FooService { still available. For more detail see . + + The processing of these annotations creates the same beans (EventDrivenConsumers and + MessageHandlers) as with similar xml components. The bean names are generated + with this pattern: + [componentName].[methodName].[annotationClassShortName] for the EventDrivenConsumer + endpoint and the same name with an additional .handler suffix for + the MessageHandler bean. The + MessageHandlers are also eligible to be tracked by . + Also see . diff --git a/src/reference/docbook/message-history.xml b/src/reference/docbook/message-history.xml index 99272d8062..170993399c 100644 --- a/src/reference/docbook/message-history.xml +++ b/src/reference/docbook/message-history.xml @@ -70,7 +70,8 @@ assertEquals("sampleChain", chainHistory.get("name"));]]> If multiple beans (declared by @EnableMessageHistory and/or <message-history/>) they - all must have identical component name patterns (when trimmed and sorted). + all must have identical component name patterns (when trimmed and sorted). Do not use a generic + <bean/> definition for the MessageHistoryConfigurer. Remember that by definition the Message History header is immutable (you can't re-write history, although some try). Therefore, when writing diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml index fd3bf9548d..688bef819a 100644 --- a/src/reference/docbook/whats-new.xml +++ b/src/reference/docbook/whats-new.xml @@ -40,7 +40,9 @@ Message history can now be enabled with the @EnableMessageHistory annotation in a @Configuration class; in addition the message history settings can be modified - by a JMX MBean. For more information, see . + by a JMX MBean. In addition auto-created MessageHandlers for + annotated endpoints (e.g. @ServiceActivator, @Splitter etc.) + now are also trackable by MessageHistory. For more information, see .