Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

INT-2822: 'requires-reply' for outbound gateways #768

Closed
wants to merge 8 commits into from

3 participants

@artembilan
Collaborator
  • Add requires-reply attribute for all adapters outbound gateways as true by default
  • WS-outbound-gateway is still without it, because it has its own specific attribute ignore-empty-responses
  • Make requires-reply as false by default for jdbc:stored-proc-outbound-gateway inasmuch as jdbc:stored-proc-outbound-adapter doesn't have ability to configure returning-resultset
  • add parser tests for requires-reply

JIRA: https://jira.springsource.org/browse/INT-2822

@artembilan
Collaborator

Added commit about requires-reply for <ws:outbound-gateway>. See: http://forum.springsource.org/showthread.php?135953

@artembilan
Collaborator

Rabased and polished

@markfisher
Owner

Sorry but it's not immediately obvious to me.... do 'ignore-empty-responses' and 'requires-reply' potentially conflict with each other?

If so, it seems like we should deprecate 'ignore-empty-responses' (for 3.0 and remove in the next minor version upgrade) and include a note in the migration guide that people should go ahead and change to 'requires-reply' instead.

@artembilan
Collaborator

Hi, Mark!
Thanks for your attention.
In case we'll deprecate ignore-empty-responses and rely only on requires-reply we have to decide what to do with empty Strings in the Response: or we leave them as is and let to end-developer to make decision about it, or return null anyway.
IMO: empty Strings in the Response is some rare case and I don't see any problem to leave it to the conscience of the end-developer.
And one more point out of this PR: https://jira.springsource.org/browse/INT-2553

So, I'm waiting your conclusion and will go ahead.

@artembilan
Collaborator

Pushed commit about deprecation ignore-empty-responses for ws:outbound-gateway.
Added note to the What's New

@artembilan
Collaborator

Added commit about removal ignore-empty-responses tip from Reference Manual.
Special note will be added to the Migration Guide after merge this PR.

@artembilan
Collaborator

Pushed polishing after rebase

@artembilan
Collaborator

Pushed polishing commit after rebase.

...integration/ws/AbstractWebServiceOutboundGateway.java
((11 lines not shown))
public void setIgnoreEmptyResponses(boolean ignoreEmptyResponses) {
- this.ignoreEmptyResponses = ignoreEmptyResponses;
+ //No-op
}
@garyrussell Owner

This is not really a deprecation, right? We're changing the behavior (ignoring the setting and advising them to use the requires-reply).

I think I'm ok with that, but maybe we should log a WARN and refer them to the migration guide???

@artembilan Collaborator

Thank you for WARN: will be added.
Migration Guide note will be added after merge.
I leave this method here (not remove it), because I saw similar solution somewhere in SPR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@garyrussell
Owner

Otherwise LGTM

artembilan added some commits
@artembilan artembilan INT-2822: 'requires-reply' for outbound gateways
* Add `requires-reply` attribute for all adapters outbound gateways as `true` by default
* WS-outbound-gateway is still without it, because it has its own specific attribute `ignore-empty-responses`
* Make `requires-reply` as `false` by default for `jdbc:stored-proc-outbound-gateway` inasmuch as `jdbc:stored-proc-outbound-adapter`
doesn't have ability to configure `returning-resultset`
* add parser tests for `requires-reply`

JIRA: https://jira.springsource.org/browse/INT-2822
f1fba65
@artembilan artembilan INT-2822 'requires-reply' for ws:outbound-gateway 8061322
@artembilan artembilan INT-2822: Polishing after rebase b866f9c
@artembilan artembilan INT-2822: deprecate 'ignore-empty-responses'
* Add 'requires-reply' section into What's New
c4c5b69
@artembilan artembilan INT-2822: remove 'ignore-empty-responses' from RM 08c6e97
@artembilan artembilan INT-2822: Polishing after rebase 14f21cd
@artembilan artembilan INT-2822: Rebased and polished 3f11833
@artembilan artembilan INT-2822: Rebased and polished
Add WARN within deprecated `AbstractWebServiceOutboundGateway#setIgnoreEmptyResponses`
758f552
@artembilan
Collaborator

Gary, pushed commit regarding WARN.

@garyrussell garyrussell commented on the diff
...integration/ws/AbstractWebServiceOutboundGateway.java
@@ -167,15 +168,7 @@ public final Object handleRequestMessage(Message<?> requestMessage) {
throw new MessageDeliveryException(requestMessage, "Failed to determine URI for " +
"Web Service request in outbound gateway: " + this.getComponentName());
}
- Object responsePayload = this.doHandle(uri.toString(), requestMessage, this.requestCallback);
- if (responsePayload != null) {
- boolean shouldIgnore = (this.ignoreEmptyResponses
- && responsePayload instanceof String && !StringUtils.hasText((String) responsePayload));
- if (!shouldIgnore) {
- return responsePayload;
- }
- }
- return null;
+ return this.doHandle(uri.toString(), requestMessage, this.requestCallback);
@garyrussell Owner

I was just about to merge this but, after further thought, it seems to me we shouldn't remove (or perhaps even deprecate) this property.

This property really means "treat an empty string the same as null" (which would then either be rejected or accepted based on requires-reply).

Maybe instead of turning it into a no-op, we should retain the functionality with a warning that it will be removed later.

Or, maybe rename it "empty-result-is-null" ???

cc @markfisher since he raised the original question

@markfisher Owner

Sorry; I probably caused the confusion with my initial comment. Looking at it now, I think we might want to keep both 'ignore-emtpy-responses' and 'requires-reply', because there may be cases where the reply Message has an empty String (but that is non-null and therefore different) and that is to be treated as a valid reply. I believe that is why we have that boolean in the first place, based on the original request:
https://jira.springsource.org/browse/INT-630

@garyrussell Owner

I reverted the ignore-empty-responses and pushed a commit here (also with some doc polishing).

garyrussell@a937ca8

@artembilan Collaborator

Hi there!

Thanks, guys, for your review.
IMO it's OK now. However when I have removed this property I meant that the same "empty string reply" we may have and with many other outbound gateways. So, configure downstream filter is more flexible solution in any case. However now removing ignore-empty-responses should be within separate JIRA. If we decide to do it, of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@garyrussell
Owner

Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 16, 2013
  1. @artembilan

    INT-2822: 'requires-reply' for outbound gateways

    artembilan authored
    * Add `requires-reply` attribute for all adapters outbound gateways as `true` by default
    * WS-outbound-gateway is still without it, because it has its own specific attribute `ignore-empty-responses`
    * Make `requires-reply` as `false` by default for `jdbc:stored-proc-outbound-gateway` inasmuch as `jdbc:stored-proc-outbound-adapter`
    doesn't have ability to configure `returning-resultset`
    * add parser tests for `requires-reply`
    
    JIRA: https://jira.springsource.org/browse/INT-2822
  2. @artembilan
  3. @artembilan
  4. @artembilan

    INT-2822: deprecate 'ignore-empty-responses'

    artembilan authored
    * Add 'requires-reply' section into What's New
  5. @artembilan
  6. @artembilan
  7. @artembilan
  8. @artembilan

    INT-2822: Rebased and polished

    artembilan authored
    Add WARN within deprecated `AbstractWebServiceOutboundGateway#setIgnoreEmptyResponses`
This page is out of date. Refresh to see the latest.
Showing with 300 additions and 104 deletions.
  1. +3 −1 ...g-integration-amqp/src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java
  2. +9 −0 ...gration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd
  3. +1 −0  ...n-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml
  4. +4 −1 ...egration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java
  5. +3 −1 ...ntegration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java
  6. +5 −8 ...g-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd
  7. +2 −2 ...file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java
  8. +2 −1  ...g-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java
  9. +9 −0 ...gration-file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd
  10. +2 −2 ...n-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml
  11. +12 −1 ...egration-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests.java
  12. +9 −0 ...ntegration-ftp/src/main/resources/org/springframework/integration/ftp/config/spring-integration-ftp-3.0.xsd
  13. +1 −0  ...tion-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml
  14. +2 −0  ...integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java
  15. +4 −3 ...g-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java
  16. +3 −1 ...gration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java
  17. +18 −0 ...gration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd
  18. +12 −3 ...egration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java
  19. +2 −0  ...on-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java
  20. +1 −1  ...dbc/src/test/java/org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml
  21. +1 −1  ...tion-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml
  22. +3 −1 spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java
  23. +10 −1 ...ntegration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd
  24. +1 −0  ...integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java
  25. +3 −2 ...n-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml
  26. +1 −1  ...ng-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml
  27. +6 −4 ...on-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java
  28. +9 −0 ...ntegration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd
  29. +5 −4 .../src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml
  30. +19 −3 ...ion-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java
  31. +3 −1 ...tion-jpa/src/main/java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java
  32. +8 −1 ...tegration-jpa/src/main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java
  33. +9 −0 ...ration-jpa/src/main/resources/org/springframework/integration/jpa/config/xml/spring-integration-jpa-3.0.xsd
  34. +28 −9 ...gration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java
  35. +11 −3 ...egration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml
  36. +9 −0 ...ntegration-rmi/src/main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd
  37. +7 −1 ...integration-rmi/src/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java
  38. +2 −1  ...-integration-rmi/src/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml
  39. +9 −0 ...gration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd
  40. +2 −0  ...n-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml
  41. +2 −0  ...egration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java
  42. +10 −17 spring-integration-ws/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java
  43. +1 −0  ...integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java
  44. +11 −3 ...g-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd
  45. +4 −14 ...ration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java
  46. +3 −2 ...n-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml
  47. +19 −0 src/reference/docbook/whats-new.xml
  48. +0 −10 src/reference/docbook/ws.xml
View
4 .../src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -29,6 +29,7 @@
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gunnar Hillert
+ * @author Artem Bilan
*
* @since 2.1
*/
@@ -53,6 +54,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "routing-key");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "routing-key-expression");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "return-channel");
View
9 ...ain/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd
@@ -199,6 +199,15 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
1  ...va/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml
@@ -40,6 +40,7 @@
routing-key="si.test.binding"
amqp-template="amqpTemplate"
order="5"
+ requires-reply="false"
mapped-request-headers="foo*"
mapped-reply-headers="bar*"/>
View
5 ...test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java
@@ -16,6 +16,7 @@
package org.springframework.integration.amqp.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@@ -62,7 +63,7 @@ public void testGatewayConfig(){
Object edc = context.getBean("rabbitGateway");
AmqpOutboundEndpoint gateway = TestUtils.getPropertyValue(edc, "handler", AmqpOutboundEndpoint.class);
assertEquals(5, gateway.getOrder());
- assertTrue(context.containsBean("rabbitGateway"));
+ assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
assertEquals(context.getBean("fromRabbit"), TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals("amqp:outbound-gateway", gateway.getComponentType());
MessageChannel returnChannel = context.getBean("returnChannel", MessageChannel.class);
@@ -81,6 +82,8 @@ public void withHeaderMapperCustomRequestResponse() {
AmqpOutboundEndpoint endpoint = TestUtils.getPropertyValue(eventDrivernConsumer, "handler", AmqpOutboundEndpoint.class);
+ assertFalse(TestUtils.getPropertyValue(endpoint, "requiresReply", Boolean.class));
+
Field amqpTemplateField = ReflectionUtils.findField(AmqpOutboundEndpoint.class, "amqpTemplate");
amqpTemplateField.setAccessible(true);
RabbitTemplate amqpTemplate = TestUtils.getPropertyValue(endpoint, "amqpTemplate", RabbitTemplate.class);
View
4 ...c/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -26,6 +26,7 @@
* Base class for url-based outbound gateway parsers.
*
* @author Mark Fisher
+ * @author Artem Bilan
*/
public abstract class AbstractOutboundGatewayParser extends AbstractConsumerEndpointParser {
@@ -45,6 +46,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
if (StringUtils.hasText(replyChannel)) {
builder.addPropertyReference("replyChannel", replyChannel);
}
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
this.postProcessGateway(builder, element, parserContext);
return builder;
}
View
13 .../src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd
@@ -1075,7 +1075,6 @@
</xsd:complexType>
</xsd:element>
-
<xsd:complexType name="serviceActivatorType">
<xsd:complexContent>
<xsd:extension base="expressionOrInnerEndpointDefinitionAware">
@@ -1083,10 +1082,8 @@
<xsd:annotation>
<xsd:documentation>
Specify whether the service method must return a non-null value. This value will be
- FALSE by
- default, but if set to TRUE, a MessageHandlingException will be thrown when
- the underlying service method (or
- expression) returns a NULL value.
+ 'false' by default, but if set to 'true', a ReplyRequiredException will be thrown when
+ the underlying service method (or expression) returns a null value.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -3153,9 +3150,9 @@ is provided, the return value is expected to match a channel name exactly.
<xsd:attribute name="requires-reply" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation>
- Specify whether the splitter method must return a non-null value. This value will be
- FALSE by default, but if set to TRUE, a MessageHandlingException will be thrown when
- the underlying service method (or expression) returns a NULL value.
+ Specify whether the service method must return a non-null value. This value will be
+ 'false' by default, but if set to 'true', a ReplyRequiredException will be thrown when
+ the underlying service method (or expression) returns a null value.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
View
4 .../org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java
@@ -27,6 +27,7 @@
* @author Gary Russell
* @author Oleg Zhurakousky
* @author Gunnar Hillert
+ * @author Artem Bilan
*
* @since 2.1
*/
@@ -59,8 +60,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "local-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-local-directory");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "order");
- IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "rename-expression");
- return builder;
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "rename-expression"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply"); return builder;
}
protected void configureFilter(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
View
3  .../src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -44,6 +44,7 @@ protected String getInputChannelAttributeName() {
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinitionBuilder handlerBuilder = FileWritingMessageHandlerBeanDefinitionBuilder.configure(element, true, parserContext);
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "reply-timeout", "sendTimeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "requires-reply");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(handlerBuilder, element, "reply-channel", "outputChannel");
return handlerBuilder;
}
View
9 ...ain/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd
@@ -394,6 +394,15 @@ Only files matching this regular expression will be picked up by this adapter.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
4 ...va/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml
@@ -19,7 +19,7 @@
<int-file:outbound-gateway id="gatewayWithDirectoryExpression"
request-channel="someChannel" directory-expression="'build/foo'"
- auto-startup="false" order="777" filename-generator-expression="'foo.txt'">
+ auto-startup="false" order="777" filename-generator-expression="'foo.txt'" requires-reply="false">
<int-file:request-handler-advice-chain>
<beans:bean class="org.springframework.integration.file.config.FileOutboundGatewayParserTests$FooAdvice" />
</int-file:request-handler-advice-chain>
@@ -28,7 +28,7 @@
<int-file:outbound-gateway id="gatewayWithReplaceMode"
request-channel="gatewayWithReplaceModeChannel"
filename-generator-expression="'fileToAppend.txt'" mode="REPLACE"
- directory="test" />
+ directory="test" requires-reply="false"/>
<int-file:outbound-gateway id="gatewayWithAppendMode"
request-channel="gatewayWithAppendModeChannel"
View
13 ...test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -17,6 +17,7 @@
package org.springframework.integration.file.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -27,10 +28,12 @@
import org.junit.runner.RunWith;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageHandlingException;
+import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.file.DefaultFileNameGenerator;
@@ -45,6 +48,7 @@
/**
* @author Mark Fisher
* @author Gunnar Hillert
+ * @author Artem Bilan
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@@ -69,6 +73,10 @@
MessageChannel gatewayWithReplaceModeChannel;
@Autowired
+ @Qualifier("gatewayWithReplaceMode.handler")
+ MessageHandler gatewayWithReplaceModeHandler;
+
+ @Autowired
MessageChannel gatewayWithFailModeLowercaseChannel;
private volatile static int adviceCalled;
@@ -82,6 +90,7 @@ public void checkOrderedGateway() throws Exception {
assertEquals(Boolean.FALSE, gatewayAccessor.getPropertyValue("autoStartup"));
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
assertEquals(777, handlerAccessor.getPropertyValue("order"));
+ assertEquals(Boolean.TRUE, handlerAccessor.getPropertyValue("requiresReply"));
DefaultFileNameGenerator fileNameGenerator = (DefaultFileNameGenerator) handlerAccessor.getPropertyValue("fileNameGenerator");
assertNotNull(fileNameGenerator);
String expression = (String) TestUtils.getPropertyValue(fileNameGenerator, "expression");
@@ -264,6 +273,8 @@ public void gatewayWithAppendMode() throws Exception{
@Test
public void gatewayWithReplaceMode() throws Exception{
+ assertFalse(TestUtils.getPropertyValue(this.gatewayWithReplaceModeHandler, "requiresReply", Boolean.class));
+
final MessagingTemplate messagingTemplate = new MessagingTemplate(this.gatewayWithReplaceModeChannel);
String expectedFileContent = "String content:";
View
9 .../main/resources/org/springframework/integration/ftp/config/spring-integration-ftp-3.0.xsd
@@ -435,6 +435,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
1  ...java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml
@@ -41,6 +41,7 @@
command-options="-P"
expression="payload"
order="2"
+ requires-reply="false"
>
<int-ftp:request-handler-advice-chain>
<bean class="org.springframework.integration.ftp.config.FtpOutboundGatewayParserTests$FooAdvice" />
View
2  ...c/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java
@@ -84,6 +84,7 @@ public void testGateway1() {
Long sendTimeout = TestUtils.getPropertyValue(gateway, "messagingTemplate.sendTimeout", Long.class);
assertEquals(Long.valueOf(777), sendTimeout);
+ assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
}
@Test
@@ -101,6 +102,7 @@ public void testGateway2() {
Set<String> options = TestUtils.getPropertyValue(gateway, "options", Set.class);
assertTrue(options.contains(Option.PRESERVE_TIMESTAMP));
gateway.handleMessage(new GenericMessage<String>("foo"));
+ assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
assertEquals(1, adviceCalled);
}
View
7 .../src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -24,6 +24,7 @@
/**
* @author Dave Syer
* @author Gunnar Hillert
+ * @author Artem Bilan
*
* @since 2.0
*
@@ -48,8 +49,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
String updateQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update",
parserContext);
- BeanDefinitionBuilder builder = BeanDefinitionBuilder
- .genericBeanDefinition(JdbcOutboundGateway.class);
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JdbcOutboundGateway.class);
if (refToDataSourceSet) {
builder.addConstructorArgReference(dataSourceRef);
}
@@ -68,6 +68,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
String replyChannel = element.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
View
4 ...ain/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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
@@ -27,6 +27,7 @@
/**
* @author Gunnar Hillert
+ * @author Artem Bilan
* @since 2.1
*
*/
@@ -62,6 +63,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
String replyChannel = element.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
View
18 ...ain/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd
@@ -502,6 +502,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -967,6 +976,15 @@
<xsd:union memberTypes="xsd:boolean xsd:string" />
</xsd:simpleType>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'false' by default, if it set to 'true', a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:complexType>
</xsd:element>
View
15 ...test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java
@@ -14,14 +14,17 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationContext;
@@ -29,6 +32,7 @@
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
+import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.endpoint.PollingConsumer;
@@ -75,6 +79,7 @@ public void testMapPayloadMapReply() {
assertEquals("bar", payload.get("name"));
JdbcOutboundGateway gateway = context.getBean("jdbcGateway.handler", JdbcOutboundGateway.class);
assertEquals(23, TestUtils.getPropertyValue(gateway, "order"));
+ Assert.assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
Object gw = context.getBean("jdbcGateway");
assertEquals(1, adviceCalled);
}
@@ -204,11 +209,15 @@ public void testMaxMessagesPerPollIsSet() throws Exception {
@Test //INT-1029
public void testOutboundGatewayInsideChain() {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("handlingMapPayloadJdbcOutboundGatewayTest.xml", getClass());
- //INT-2755
- assertNotNull(context.getBean("org.springframework.integration.handler.MessageHandlerChain#0$child.jdbc-outbound-gateway-within-chain.handler",
- JdbcOutboundGateway.class));
+
+ JdbcOutboundGateway jdbcMessageHandler =
+ context.getBean("org.springframework.integration.handler.MessageHandlerChain#0$child.jdbc-outbound-gateway-within-chain.handler",
+ JdbcOutboundGateway.class);
MessageChannel channel = context.getBean("jdbcOutboundGatewayInsideChain", MessageChannel.class);
+
+ assertFalse(TestUtils.getPropertyValue(jdbcMessageHandler, "requiresReply", Boolean.class));
+
channel.send(MessageBuilder.withPayload(Collections.singletonMap("foo", "bar")).build());
PollableChannel outbound = context.getBean("replyChannel", PollableChannel.class);
View
2  ...ava/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java
@@ -47,6 +47,7 @@
/**
* @author Gunnar Hillert
* @author Gary Russell
+ * @author Artem Bilan
* @since 2.1
*
*/
@@ -65,6 +66,7 @@ public void testProcedureNameIsSet() throws Exception {
DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway);
Object source = accessor.getPropertyValue("handler");
accessor = new DirectFieldAccessor(source);
+ assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
source = accessor.getPropertyValue("executor");
accessor = new DirectFieldAccessor(source);
Expression storedProcedureName = (Expression) accessor.getPropertyValue("storedProcedureNameExpression");
View
2  ...org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml
@@ -26,7 +26,7 @@
<si:chain input-channel="jdbcOutboundGatewayInsideChain" output-channel="replyChannel">
<outbound-gateway id="jdbc-outbound-gateway-within-chain" query="select * from foos where id=:headers[id]"
update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
- data-source="dataSource"/>
+ data-source="dataSource" requires-reply="false"/>
</si:chain>
View
2  .../java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml
@@ -18,7 +18,7 @@
data-source="datasource" auto-startup="true" id="storedProcedureOutboundGateway"
ignore-column-meta-data="false" is-function="false"
skip-undeclared-results="false" order="2" reply-channel="replyChannel"
- reply-timeout="555" return-value-required="true">
+ reply-timeout="555" return-value-required="true" requires-reply="true">
<int-jdbc:sql-parameter-definition name="username" direction="IN" type="VARCHAR" />
<int-jdbc:sql-parameter-definition name="password" direction="OUT" />
View
4 ...ms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java
@@ -33,6 +33,7 @@
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
+ * @author Artem Bilan
*/
public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
@@ -65,6 +66,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "time-to-live");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "priority");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "explicit-qos-enabled");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
String deliveryPersistent = element.getAttribute("delivery-persistent");
if (StringUtils.hasText(deliveryPersistent)) {
@@ -119,7 +121,7 @@ private void parseReplyContainer(BeanDefinitionBuilder gatewayBuilder, ParserCon
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsOutboundGateway.ReplyContainerProperties.class);
Integer acknowledgeMode = JmsAdapterParserUtils.parseAcknowledgeMode(element, parserContext);
if (acknowledgeMode != null) {
- if (acknowledgeMode.intValue() == JmsAdapterParserUtils.SESSION_TRANSACTED) {
+ if (JmsAdapterParserUtils.SESSION_TRANSACTED == acknowledgeMode) {
builder.addPropertyValue("sessionTransacted", Boolean.TRUE);
}
else {
View
11 .../main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd
@@ -1065,6 +1065,15 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:complexType>
</xsd:element>
@@ -1469,4 +1478,4 @@
</xsd:attributeGroup>
-</xsd:schema>
+</xsd:schema>
View
1  ...c/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java
@@ -128,6 +128,7 @@ public void gatewayWithOrder() {
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
Object order = accessor.getPropertyValue("order");
assertEquals(99, order);
+ assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
}
@Test
View
5 ...a/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml
@@ -14,7 +14,7 @@
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<si:channel id="requestChannel"/>
-
+
<jms:outbound-gateway id="jmsGateway"
request-destination-name="requestQueue"
request-channel="requestChannel"
@@ -47,7 +47,8 @@
request-destination-name="requestQueue"
request-channel="requestChannel"
delivery-persistent="true"
- auto-startup="false">
+ auto-startup="false"
+ requires-reply="false">
<jms:request-handler-advice-chain>
<bean class="org.springframework.integration.jms.config.JmsOutboundGatewayParserTests$FooAdvice" />
</jms:request-handler-advice-chain>
View
2  .../src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml
@@ -15,7 +15,7 @@
<jms:outbound-gateway id="jmsGateway"
request-destination="requestQueue"
request-channel="requestChannel"
- order="99"/>
+ order="99" requires-reply="true"/>
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
<constructor-arg>
View
10 ...va/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2013 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,6 +18,7 @@
import org.w3c.dom.Element;
+import org.springframework.integration.jmx.OperationInvokingMessageHandler;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
@@ -25,10 +26,11 @@
/**
* @author Oleg Zhurakousky
+ * @author Artem Bilan
* @since 2.0
*/
public class OperationInvokingOutboundGatewayParser extends AbstractConsumerEndpointParser {
-
+
@Override
protected String getInputChannelAttributeName() {
return "request-channel";
@@ -36,12 +38,12 @@ protected String getInputChannelAttributeName() {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(
- "org.springframework.integration.jmx.OperationInvokingMessageHandler");
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(OperationInvokingMessageHandler.class);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "server");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "object-name");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "operation-name");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
return builder;
}
View
9 .../main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd
@@ -47,6 +47,15 @@
</xsd:all>
<xsd:attribute name="request-channel" type="xsd:string" />
<xsd:attribute name="reply-channel" type="xsd:string" use="optional" />
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
9 .../springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml
@@ -29,18 +29,19 @@
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
operation-name="testWithReturn">
<jmx:request-handler-advice-chain>
- <bean class="org.springframework.integration.jmx.config.OperationInvokingOutboundGatewayTests$FooADvice" />
+ <bean class="org.springframework.integration.jmx.config.OperationInvokingOutboundGatewayTests.FooAdvice" />
</jmx:request-handler-advice-chain>
</jmx:operation-invoking-outbound-gateway>
- <si:chain input-channel="jmxOutboundGatewayInsideChain" output-channel="withReplyChannelOutput">
- <jmx:operation-invoking-outbound-gateway operation-name="testWithReturn"
+ <si:chain id="operationInvokingWithinChain" input-channel="jmxOutboundGatewayInsideChain" output-channel="withReplyChannelOutput">
+ <jmx:operation-invoking-outbound-gateway operation-name="testWithReturn" requires-reply="true"
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"/>
</si:chain>
<jmx:operation-invoking-outbound-gateway request-channel="withNoReplyChannel"
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
- operation-name="test"/>
+ operation-name="test"
+ requires-reply="false"/>
<bean id="testBeanGateway" class="org.springframework.integration.jmx.config.TestBean"/>
</beans>
View
22 ...ava/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -17,6 +17,7 @@
package org.springframework.integration.jmx.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import java.util.List;
@@ -27,10 +28,13 @@
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
+import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
+import org.springframework.integration.jmx.OperationInvokingMessageHandler;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
+import org.springframework.integration.test.util.TestUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -61,6 +65,12 @@
@Autowired
private TestBean testBean;
+ @Autowired
+ @Qualifier("operationInvokingWithinChain.handler")
+ private MessageHandler operationInvokingWithinChain;
+
+
+
private static volatile int adviceCalled;
@After
@@ -89,8 +99,14 @@ public void gatewayWithNoReplyChannel() throws Exception {
assertEquals(3, testBean.messages.size());
}
- @Test //INT-1029
+ @Test //INT-1029, INT-2822
public void testOutboundGatewayInsideChain() throws Exception {
+ List handlers = TestUtils.getPropertyValue(this.operationInvokingWithinChain, "handlers", List.class);
+ assertEquals(1, handlers.size());
+ Object handler = handlers.get(0);
+ assertTrue(handler instanceof OperationInvokingMessageHandler);
+ assertTrue(TestUtils.getPropertyValue(handler, "requiresReply", Boolean.class));
+
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("1").build());
assertEquals(1, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("2").build());
@@ -99,7 +115,7 @@ public void testOutboundGatewayInsideChain() throws Exception {
assertEquals(3, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
}
- public static class FooADvice extends AbstractRequestHandlerAdvice {
+ public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
View
4 ...java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -30,6 +30,7 @@
* The Abstract Parser for the JPA Outbound Gateways.
*
* @author Gunnar Hillert
+ * @author Artem Bilan
*
* @since 2.2
*
@@ -46,6 +47,7 @@ protected BeanDefinitionBuilder parseHandler(Element gatewayElement, ParserConte
.genericBeanDefinition(JpaOutboundGatewayFactoryBean.class);
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaOutboundGatewayBuilder, gatewayElement, "reply-timeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaOutboundGatewayBuilder, gatewayElement, "requires-reply");
final String replyChannel = gatewayElement.getAttribute("reply-channel");
View
9 ...main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java
@@ -70,6 +70,8 @@
private long replyTimeout;
+ private volatile boolean requiresReply = false;
+
private volatile String componentName;
/**
@@ -118,6 +120,10 @@ public void setReplyTimeout(long replyTimeout) {
this.replyTimeout = replyTimeout;
}
+ public void setRequiresReply(boolean requiresReply) {
+ this.requiresReply = requiresReply;
+ }
+
/**
* Sets the name of the handler component.
*
@@ -140,7 +146,8 @@ protected MessageHandler createInstance() {
jpaOutboundGateway.setProducesReply(this.producesReply);
jpaOutboundGateway.setOutputChannel(this.outputChannel);
jpaOutboundGateway.setOrder(this.order);
- jpaOutboundGateway.setSendTimeout(replyTimeout);
+ jpaOutboundGateway.setSendTimeout(this.replyTimeout);
+ jpaOutboundGateway.setRequiresReply(this.requiresReply);
jpaOutboundGateway.setComponentName(this.componentName);
if (this.adviceChain != null) {
jpaOutboundGateway.setAdviceChain(this.adviceChain);
View
9 ...n/resources/org/springframework/integration/jpa/config/xml/spring-integration-jpa-3.0.xsd
@@ -363,6 +363,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:attributeGroup>
<xsd:attributeGroup name="commonUpdatingJpaAttributes">
View
37 ...st/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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,18 +13,24 @@
package org.springframework.integration.jpa.config.xml;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.aopalliance.intercept.MethodInvocation;
import org.junit.After;
import org.junit.Test;
+import org.mockito.Mockito;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
+import org.springframework.integration.MessagingException;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
+import org.springframework.integration.handler.ReplyRequiredException;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.jpa.core.JpaExecutor;
import org.springframework.integration.jpa.core.JpaOperations;
@@ -42,14 +48,12 @@
* @since 2.2
*
*/
-public class JpaOutboundGatewayParserTests {
+public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice {
private ConfigurableApplicationContext context;
private EventDrivenConsumer consumer;
- private static volatile int adviceCalled;
-
@Test
public void testRetrievingJpaOutboundGatewayParser() throws Exception {
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGateway");
@@ -69,6 +73,7 @@ public void testRetrievingJpaOutboundGatewayParser() throws Exception {
assertEquals(100, sendTimeout);
+ assertFalse(TestUtils.getPropertyValue(jpaOutboundGateway, "requiresReply", Boolean.class));
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
@@ -87,7 +92,6 @@ public void testRetrievingJpaOutboundGatewayParser() throws Exception {
final Integer maxNumberOfResults = TestUtils.getPropertyValue(jpaExecutor, "maxNumberOfResults", Integer.class);
assertEquals(Integer.valueOf(55), maxNumberOfResults);
-
}
@Test
@@ -109,6 +113,8 @@ public void testUpdatingJpaOutboundGatewayParser() throws Exception {
assertEquals(100, sendTimeout);
+ assertFalse(TestUtils.getPropertyValue(jpaOutboundGateway, "requiresReply", Boolean.class));
+
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
assertNotNull(jpaExecutor);
@@ -136,14 +142,22 @@ public void testUpdatingJpaOutboundGatewayParser() throws Exception {
}
@Test
- public void advised() throws Exception {
+ public void advised() throws Throwable {
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "advised");
MessageHandler jpaOutboundGateway = context.getBean("advised.handler", MessageHandler.class);
+ FooAdvice advice = context.getBean("jpaFooAdvice", FooAdvice.class);
assertTrue(AopUtils.isAopProxy(jpaOutboundGateway));
- jpaOutboundGateway.handleMessage(new GenericMessage<String>("foo"));
- assertEquals(1, adviceCalled);
+ try {
+ jpaOutboundGateway.handleMessage(new GenericMessage<String>("foo"));
+ fail("expected ReplyRequiredException");
+ }
+ catch (MessagingException e) {
+ assertTrue(e instanceof ReplyRequiredException);
+ }
+
+ Mockito.verify(advice).doInvoke(Mockito.any(ExecutionCallback.class), Mockito.any(Object.class), Mockito.any(Message.class));
}
@Test
@@ -168,11 +182,16 @@ public void setUp(String name, Class<?> cls, String gatewayId) {
consumer = this.context.getBean(gatewayId, EventDrivenConsumer.class);
}
+ @Override
+ protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
+ // Workaround for access to protected AbstractRequestHandlerAdvice.ExecutionCallback
+ return null;
+ }
+
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
- adviceCalled++;
return null;
}
View
14 ...est/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml
@@ -23,7 +23,8 @@
max-number-of-results="55"
request-channel="in"
reply-channel="out"
- reply-timeout="100"/>
+ reply-timeout="100"
+ requires-reply="false"/>
<int-jpa:updating-outbound-gateway id="updatingJpaOutboundGateway"
entity-manager-factory="entityManagerFactory"
@@ -34,7 +35,8 @@
order="2"
request-channel="in"
reply-channel="out"
- reply-timeout="100"/>
+ reply-timeout="100"
+ requires-reply="false"/>
<int-jpa:updating-outbound-gateway id="advised"
entity-manager-factory="entityManagerFactory"
@@ -48,8 +50,14 @@
reply-timeout="100">
<int-jpa:transactional/>
<int-jpa:request-handler-advice-chain>
- <bean class="org.springframework.integration.jpa.config.xml.JpaOutboundGatewayParserTests$FooAdvice"/>
+ <ref bean="jpaFooAdvice"/>
</int-jpa:request-handler-advice-chain>
</int-jpa:updating-outbound-gateway>
+ <bean id="jpaFooAdvice" class="org.mockito.Mockito" factory-method="spy">
+ <constructor-arg>
+ <bean class="org.springframework.integration.jpa.config.xml.JpaOutboundGatewayParserTests$FooAdvice"/>
+ </constructor-arg>
+ </bean>
+
</beans>
View
9 .../main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd
@@ -101,6 +101,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
8 ...c/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -17,7 +17,9 @@
package org.springframework.integration.rmi.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
@@ -60,6 +62,7 @@ public void testOrder() {
"rmiOutboundGatewayParserTests.xml", this.getClass());
RmiOutboundGateway gateway = context.getBean("gateway.handler", RmiOutboundGateway.class);
assertEquals(23, TestUtils.getPropertyValue(gateway, "order"));
+ assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
}
@Test
@@ -67,6 +70,9 @@ public void directInvocation() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"rmiOutboundGatewayParserTests.xml", this.getClass());
MessageChannel localChannel = (MessageChannel) context.getBean("advisedChannel");
+ RmiOutboundGateway gateway = context.getBean("advised.handler", RmiOutboundGateway.class);
+ assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
+
localChannel.send(new GenericMessage<String>("test"));
Message<?> result = testChannel.receive(1000);
assertNotNull(result);
View
3  ...rc/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml
@@ -23,6 +23,7 @@
<rmi:outbound-gateway id="advised"
request-channel="advisedChannel"
remote-channel="testChannel"
+ requires-reply="false"
host="localhost">
<rmi:request-handler-advice-chain>
<beans:bean class="org.springframework.integration.rmi.config.RmiOutboundGatewayParserTests$FooAdvice" />
@@ -30,7 +31,7 @@
</rmi:outbound-gateway>
<chain input-channel="rmiOutboundGatewayInsideChain">
- <rmi:outbound-gateway remote-channel="testChannel" host="localhost"/>
+ <rmi:outbound-gateway remote-channel="testChannel" host="localhost" requires-reply="false"/>
</chain>
View
9 ...ain/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd
@@ -432,6 +432,15 @@
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'true' by default, and a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
View
2  ...va/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml
@@ -41,6 +41,7 @@
command-options="-P"
expression="payload"
order="2"
+ requires-reply="false"
/>
<int-sftp:outbound-gateway id="gateway3"
@@ -65,6 +66,7 @@
command="get"
command-options="-P"
expression="payload"
+ requires-reply="false"
order="2">
<int-sftp:request-handler-advice-chain>
<bean class="org.springframework.integration.sftp.config.SftpOutboundGatewayParserTests$FooAdvice" />
View
2  ...test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java
@@ -73,6 +73,7 @@ public void testGateway1() {
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
+ assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
assertEquals(Command.LS, TestUtils.getPropertyValue(gateway, "command"));
@SuppressWarnings("unchecked")
@@ -95,6 +96,7 @@ public void testGateway2() {
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
assertEquals(Command.GET, TestUtils.getPropertyValue(gateway, "command"));
+ assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
@SuppressWarnings("unchecked")
Set<String> options = TestUtils.getPropertyValue(gateway, "options", Set.class);
assertTrue(options.contains(Option.PRESERVE_TIMESTAMP));
View
27 ...s/src/main/java/org/springframework/integration/ws/AbstractWebServiceOutboundGateway.java
@@ -20,7 +20,6 @@
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
-
import javax.xml.transform.TransformerException;
import org.springframework.expression.Expression;
@@ -33,7 +32,6 @@
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
import org.springframework.web.util.UriTemplate;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
@@ -70,8 +68,6 @@
private volatile WebServiceMessageCallback requestCallback;
- private volatile boolean ignoreEmptyResponses = true;
-
protected volatile SoapHeaderMapper headerMapper = new DefaultSoapHeaderMapper();
public AbstractWebServiceOutboundGateway(final String uri, WebServiceMessageFactory messageFactory) {
@@ -111,12 +107,17 @@ public void setReplyChannel(MessageChannel replyChannel) {
}
/**
- * Specify whether empty String response payloads should be ignored.
- * The default is <code>true</code>. Set this to <code>false</code> if
- * you want to send empty String responses in reply Messages.
+ * Backward compatibility - with no op.
+ * @deprecated in favor of {@link #setRequiresReply(boolean)}
*/
+ @Deprecated
public void setIgnoreEmptyResponses(boolean ignoreEmptyResponses) {
- this.ignoreEmptyResponses = ignoreEmptyResponses;
+ //No-op
+ if (logger.isWarnEnabled()) {
+ logger.warn("'ignoreEmptyResponses' is no longer supported. " +
+ "Use 'requiresReply = true' instead. " +
+ "If it is necessary, configure some downstream Filter to skip empty string payloads.");
+ }
}
public void setMessageFactory(WebServiceMessageFactory messageFactory) {
@@ -167,15 +168,7 @@ public final Object handleRequestMessage(Message<?> requestMessage) {
throw new MessageDeliveryException(requestMessage, "Failed to determine URI for " +
"Web Service request in outbound gateway: " + this.getComponentName());
}
- Object responsePayload = this.doHandle(uri.toString(), requestMessage, this.requestCallback);
- if (responsePayload != null) {
- boolean shouldIgnore = (this.ignoreEmptyResponses
- && responsePayload instanceof String && !StringUtils.hasText((String) responsePayload));
- if (!shouldIgnore) {
- return responsePayload;
- }
- }
- return null;
+ return this.doHandle(uri.toString(), requestMessage, this.requestCallback);
@garyrussell Owner

I was just about to merge this but, after further thought, it seems to me we shouldn't remove (or perhaps even deprecate) this property.

This property really means "treat an empty string the same as null" (which would then either be rejected or accepted based on requires-reply).

Maybe instead of turning it into a no-op, we should retain the functionality with a warning that it will be removed later.

Or, maybe rename it "empty-result-is-null" ???

cc @markfisher since he raised the original question

@markfisher Owner

Sorry; I probably caused the confusion with my initial comment. Looking at it now, I think we might want to keep both 'ignore-emtpy-responses' and 'requires-reply', because there may be cases where the reply Message has an empty String (but that is non-null and therefore different) and that is to be treated as a valid reply. I believe that is why we have that boolean in the first place, based on the original request:
https://jira.springsource.org/browse/INT-630

@garyrussell Owner

I reverted the ignore-empty-responses and pushed a commit here (also with some doc polishing).

garyrussell@a937ca8

@artembilan Collaborator

Hi there!

Thanks, guys, for your review.
IMO it's OK now. However when I have removed this property I meant that the same "empty string reply" we may have and with many other outbound gateways. So, configure downstream filter is more flexible solution in any case. However now removing ignore-empty-responses should be within separate JIRA. If we decide to do it, of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
protected abstract Object doHandle(String uri, Message<?> requestMessage, WebServiceMessageCallback requestCallback);
View
1  .../main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java
@@ -83,6 +83,7 @@ protected BeanDefinitionBuilder parseHandler(Element element, ParserContext pars
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-empty-responses");
this.postProcessGateway(builder, element, parserContext);
View
14 ...rc/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd
@@ -87,6 +87,15 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
+ <xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="false">
+ <xsd:annotation>
+ <xsd:documentation>
+ Specify whether this outbound gateway must return a non-null value. This value is
+ 'false' by default, otherwise a ReplyRequiredException will be thrown when
+ the underlying service returns a null value.
+ </xsd:documentation>
+ </xsd:annotation>
+ </xsd:attribute>
<xsd:attribute name="uri" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -139,8 +148,7 @@
<xsd:attribute name="ignore-empty-responses" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
- Indicates whether empty String response payloads should be ignored. The default is TRUE.
- Set this to FALSE if you want to send empty String responses in reply Messages.
+ [DEPRECATED] with 'no-op' in favor of 'requires-reply' attribute.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -456,4 +464,4 @@ this list can also be simple patterns to be matched against the header names (e.
</xsd:attribute>
</xsd:complexType>
-</xsd:schema>
+</xsd:schema>
View
18 .../java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java
@@ -23,6 +23,7 @@
import java.net.URI;
import java.util.List;
+import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
@@ -72,6 +73,7 @@ public void simpleGatewayWithReplyChannel() {
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
Object expected = context.getBean("outputChannel");
assertEquals(expected, accessor.getPropertyValue("outputChannel"));
+ Assert.assertEquals(Boolean.FALSE, accessor.getPropertyValue("requiresReply"));
@SuppressWarnings("unchecked")
List<String> requestHeaders = TestUtils.getPropertyValue(endpoint, "handler.headerMapper.requestHeaderNames", List.class);
@@ -87,27 +89,15 @@ public void simpleGatewayWithReplyChannel() {
}
@Test
- public void simpleGatewayWithIgnoreEmptyResponseTrueByDefault() {
- ApplicationContext context = new ClassPathXmlApplicationContext(
- "simpleWebServiceOutboundGatewayParserTests.xml", this.getClass());
- AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithReplyChannel");
- assertEquals(EventDrivenConsumer.class, endpoint.getClass());
- Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
- assertEquals(SimpleWebServiceOutboundGateway.class, gateway.getClass());
- DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
- assertEquals(Boolean.TRUE, accessor.getPropertyValue("ignoreEmptyResponses"));
- }
-
- @Test
public void simpleGatewayWithIgnoreEmptyResponses() {
ApplicationContext context = new ClassPathXmlApplicationContext(
"simpleWebServiceOutboundGatewayParserTests.xml", this.getClass());
- AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithIgnoreEmptyResponsesFalse");
+ AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithRequiresReplyTrue");
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertEquals(SimpleWebServiceOutboundGateway.class, gateway.getClass());
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
- assertEquals(Boolean.FALSE, accessor.getPropertyValue("ignoreEmptyResponses"));
+ Assert.assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
}
@Test
View
5 .../org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml
@@ -31,10 +31,11 @@
mapped-request-headers="testRequest"
mapped-reply-headers="testReply"/>
- <ws:outbound-gateway id="gatewayWithIgnoreEmptyResponsesFalse"
+ <ws:outbound-gateway id="gatewayWithRequiresReplyTrue"
request-channel="inputChannel"
uri="http://example.org"
- ignore-empty-responses="false"/>
+ ignore-empty-responses="false"
+ requires-reply="true"/>
<ws:outbound-gateway id="gatewayWithDefaultSourceExtractor"
request-channel="inputChannel"
View
19 src/reference/docbook/whats-new.xml
@@ -244,5 +244,24 @@
For more information see <xref linkend="message-id-generation"/>.
</para>
</section>
+ <section id="3.0-outbound-gateway-requires-reply">
+ <title>'requires-reply' attribute for Outbound Gateways</title>
+ <para>
+ All Outbound Gateways (e.g. <code>&lt;ftp:outbound-gateway/&gt;</code> or <code>&lt;jms:outbound-gateway/&gt;</code>)
+ are designed for 'request-reply' scenario. In this case we are expecting that response from external service
+ will be published to the <code>reply-channel</code>. But there are many cases where external system doesn't
+ return result, e.g. <code>&lt;jdbc:outbound-gateway/&gt;</code>, when SELECT ends with empty <interfacename>ResultSet</interfacename>
+ or the underlying Web Service is One-Way. So, we need an option when we can decide do not expect <emphasis>reply</emphasis>.
+ For this purpose <emphasis>requires-reply</emphasis> attribute was introduced for all Outbound Gateway components.
+ In most cases default value for <emphasis>requires-reply</emphasis> is <code>true</code> and if there is no any result
+ <classname>ReplyRequiredException</classname> will be thrown. Change it to <code>false</code>
+ means that, if an external service doesn't return anything, the message-flow will end on current Outbound Gateway,
+ similar to Outbound Channel Adapter.
+ </para>
+ <para>
+ Note, the <code>requiresReply</code> property is presented in the <classname>AbstractReplyProducingMessageHandler</classname>
+ but with value <code>false</code> and there wasn't any configuration ability on Outbound Gateways to change it before this release.
+ </para>
+ </section>
</section>
</chapter>
View
10 src/reference/docbook/ws.xml
@@ -79,16 +79,6 @@ as per standard Spring Web Services configuration.
reply to another channel instead, then provide a 'reply-channel' attribute on the
'outbound-gateway' element.
</note>
- <tip>
- When invoking a Web Service that returns an empty response after using a String payload
- for the request Message, <emphasis>no reply Message will be sent by default</emphasis>.
- Therefore you don't need to set a 'reply-channel' or have a REPLY_CHANNEL header in the
- request Message. If for any reason you actually <emphasis>do</emphasis> want to receive
- the empty response as a Message, then provide the 'ignore-empty-responses' attribute with
- a value of <emphasis>false</emphasis> (this only applies for Strings, because using a
- Source or Document object simply leads to a NULL response and will therefore
- <emphasis>never</emphasis> generate a reply Message).
- </tip>
To set up an inbound Web Service Gateway, use the "inbound-gateway":
<programlisting language="xml"><![CDATA[<int-ws:inbound-gateway id="simpleGateway"
Something went wrong with that request. Please try again.