diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java index dd39596c25..52e68113a3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessagingGatewayRegistrar.java @@ -142,13 +142,13 @@ public class MessagingGatewayRegistrar implements ImportBeanDefinitionRegistrar, if (StringUtils.hasText(defaultRequestChannel)) { - gatewayProxyBuilder.addPropertyReference("defaultRequestChannel", defaultRequestChannel); + gatewayProxyBuilder.addPropertyValue("defaultRequestChannelName", defaultRequestChannel); } if (StringUtils.hasText(defaultReplyChannel)) { - gatewayProxyBuilder.addPropertyReference("defaultReplyChannel", defaultReplyChannel); + gatewayProxyBuilder.addPropertyValue("defaultReplyChannelName", defaultReplyChannel); } if (StringUtils.hasText(errorChannel)) { - gatewayProxyBuilder.addPropertyReference("errorChannel", errorChannel); + gatewayProxyBuilder.addPropertyValue("errorChannelName", errorChannel); } if (asyncExecutor == null || AnnotationConstants.NULL.equals(asyncExecutor)) { gatewayProxyBuilder.addPropertyValue("asyncExecutor", null); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java index f16278ba26..f37a286b7b 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayProxyFactoryBean.java @@ -93,10 +93,16 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint private volatile MessageChannel defaultRequestChannel; + private volatile String defaultRequestChannelName; + private volatile MessageChannel defaultReplyChannel; + private volatile String defaultReplyChannelName; + private volatile MessageChannel errorChannel; + private volatile String errorChannelName; + private volatile Long defaultRequestTimeout; private volatile Long defaultReplyTimeout; @@ -159,7 +165,6 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint /** * Set the default request channel. - * * @param defaultRequestChannel the channel to which request messages will * be sent if no request channel has been configured with an annotation. */ @@ -167,11 +172,20 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint this.defaultRequestChannel = defaultRequestChannel; } + /** + * Set the default request channel bean name. + * @param defaultRequestChannelName the channel name to which request messages will + * be sent if no request channel has been configured with an annotation. + * @since 4.2.9 + */ + public void setDefaultRequestChannelName(String defaultRequestChannelName) { + this.defaultRequestChannelName = defaultRequestChannelName; + } + /** * Set the default reply channel. If no default reply channel is provided, * and no reply channel is configured with annotations, an anonymous, * temporary channel will be used for handling replies. - * * @param defaultReplyChannel the channel from which reply messages will be * received if no reply channel has been configured with an annotation */ @@ -179,17 +193,39 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint this.defaultReplyChannel = defaultReplyChannel; } + /** + * Set the default reply channel bean name. If no default reply channel is provided, + * and no reply channel is configured with annotations, an anonymous, + * temporary channel will be used for handling replies. + * @param defaultReplyChannelName the channel name from which reply messages will be + * received if no reply channel has been configured with an annotation + * @since 4.2.9 + */ + public void setDefaultReplyChannelName(String defaultReplyChannelName) { + this.defaultReplyChannelName = defaultReplyChannelName; + } + /** * Set the error channel. If no error channel is provided, this gateway will * propagate Exceptions to the caller. To completely suppress Exceptions, provide * a reference to the "nullChannel" here. - * * @param errorChannel The error channel. */ public void setErrorChannel(MessageChannel errorChannel) { this.errorChannel = errorChannel; } + /** + * Set the error channel name. If no error channel is provided, this gateway will + * propagate Exceptions to the caller. To completely suppress Exceptions, provide + * a reference to the "nullChannel" here. + * @param errorChannelName The error channel bean name. + * @since 4.2.9 + */ + public void setErrorChannelName(String errorChannelName) { + this.errorChannelName = errorChannelName; + } + /** * Set the default timeout value for sending request messages. If not * explicitly configured with an annotation, this value will be used. @@ -456,13 +492,12 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint private MethodInvocationGateway createGatewayForMethod(Method method) { Gateway gatewayAnnotation = method.getAnnotation(Gateway.class); - MessageChannel requestChannel = this.defaultRequestChannel; String requestChannelName = null; - MessageChannel replyChannel = this.defaultReplyChannel; String replyChannelName = null; Long requestTimeout = this.defaultRequestTimeout; Long replyTimeout = this.defaultReplyTimeout; - String payloadExpression = this.globalMethodMetadata != null ? this.globalMethodMetadata.getPayloadExpression() + String payloadExpression = this.globalMethodMetadata != null + ? this.globalMethodMetadata.getPayloadExpression() : null; Map headerExpressions = new HashMap(); if (gatewayAnnotation != null) { @@ -492,7 +527,7 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint String name = gatewayHeader.name(); boolean hasValue = StringUtils.hasText(value); - if (!(hasValue ^ StringUtils.hasText(expression))) { + if (hasValue == StringUtils.hasText(expression)) { throw new BeanDefinitionStoreException("exactly one of 'value' or 'expression' " + "is required on a gateway's header."); } @@ -533,23 +568,39 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint } messageMapper.setBeanFactory(this.getBeanFactory()); MethodInvocationGateway gateway = new MethodInvocationGateway(messageMapper); - gateway.setErrorChannel(this.errorChannel); + + if (this.errorChannel != null) { + gateway.setErrorChannel(this.errorChannel); + } + else if (StringUtils.hasText(this.errorChannelName)) { + gateway.setErrorChannelName(this.errorChannelName); + } + if (this.getTaskScheduler() != null) { gateway.setTaskScheduler(this.getTaskScheduler()); } gateway.setBeanName(this.getComponentName()); + if (StringUtils.hasText(requestChannelName)) { gateway.setRequestChannelName(requestChannelName); } - else { - gateway.setRequestChannel(requestChannel); + else if (StringUtils.hasText(this.defaultRequestChannelName)) { + gateway.setRequestChannelName(this.defaultRequestChannelName); } + else { + gateway.setRequestChannel(this.defaultRequestChannel); + } + if (StringUtils.hasText(replyChannelName)) { gateway.setReplyChannelName(replyChannelName); } - else { - gateway.setReplyChannel(replyChannel); + else if (StringUtils.hasText(this.defaultReplyChannelName)) { + gateway.setReplyChannelName(this.defaultReplyChannelName); } + else { + gateway.setReplyChannel(this.defaultReplyChannel); + } + if (requestTimeout == null) { gateway.setRequestTimeout(-1); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java index fbc10f24fe..89f8d0facf 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/ChainParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -394,8 +394,8 @@ public class ChainParserTests { //INT-3117 GatewayProxyFactoryBean gatewayProxyFactoryBean = this.beanFactory.getBean("&subComponentsIdSupport1$child.gatewayWithinChain.handler", GatewayProxyFactoryBean.class); - assertSame(this.strings, TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestChannel", MessageChannel.class)); - assertSame(this.numbers, TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultReplyChannel", MessageChannel.class)); + assertEquals("strings", TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestChannelName")); + assertEquals("numbers", TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultReplyChannelName")); assertEquals(new Long(1000), TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultRequestTimeout", Long.class)); assertEquals(new Long(100), TestUtils.getPropertyValue(gatewayProxyFactoryBean, "defaultReplyTimeout", Long.class)); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java index 0608879798..94a825fcb8 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/gateway/GatewayInterfaceTests.java @@ -49,7 +49,9 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor; @@ -58,8 +60,10 @@ import org.springframework.integration.annotation.BridgeTo; import org.springframework.integration.annotation.Gateway; import org.springframework.integration.annotation.IntegrationComponentScan; import org.springframework.integration.annotation.MessagingGateway; +import org.springframework.integration.annotation.ServiceActivator; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.handler.BridgeHandler; import org.springframework.integration.support.MessageBuilder; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; @@ -71,6 +75,7 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Payload; import org.springframework.messaging.support.ChannelInterceptorAdapter; import org.springframework.scheduling.annotation.AsyncResult; +import org.springframework.stereotype.Component; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -81,6 +86,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback; * @author Oleg Zhurakousky * @author Gunnar Hillert * @author Gary Russell + * @author Artem Bilan */ @ContextConfiguration(classes = GatewayInterfaceTests.TestConfig.class) @RunWith(SpringJUnit4ClassRunner.class) @@ -107,6 +113,9 @@ public class GatewayInterfaceTests { @Autowired private SimpleAsyncTaskExecutor exec; + @Autowired + private AutoCreateChannelService autoCreateChannelService; + @Test public void testWithServiceSuperclassAnnotatedMethod() throws Exception { @@ -394,6 +403,10 @@ public class GatewayInterfaceTests { assertThat(result2.get().getName(), startsWith("exec-")); } + @Test + public void testAutoCreateChannelGateway() { + assertEquals("foo", this.autoCreateChannelService.service("foo")); + } public interface Foo { @@ -431,9 +444,23 @@ public class GatewayInterfaceTests { } + @Component + public static class AutoCreateChannelService { + + @Autowired + private AutoCreateChannelGateway gateway; + + public String service(String request) { + return this.gateway.foo(request); + } + + } + @Configuration - @EnableIntegration + @ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, + classes = AutoCreateChannelService.class)) @IntegrationComponentScan + @EnableIntegration public static class TestConfig { @Bean @@ -474,6 +501,12 @@ public class GatewayInterfaceTests { return simpleAsyncTaskExecutor; } + @Bean + @ServiceActivator(inputChannel = "autoCreateChannel") + public MessageHandler autoCreateServiceActivator() { + return new BridgeHandler(); + } + } @MessagingGateway @@ -509,4 +542,12 @@ public class GatewayInterfaceTests { } + + @MessagingGateway(defaultRequestChannel = "autoCreateChannel") + public interface AutoCreateChannelGateway { + + String foo(String payload); + + } + }