diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java
index c45569c0da..53474cbfdb 100644
--- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java
+++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java
@@ -15,6 +15,7 @@
*/
package org.springframework.integration.jdbc;
+import java.util.Collections;
import java.util.List;
import javax.sql.DataSource;
@@ -28,6 +29,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
/**
* @author Dave Syer
@@ -60,14 +62,28 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
}
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery, String selectQuery) {
- if (selectQuery != null) {
+
+ Assert.notNull(jdbcOperations, "'jdbcOperations' must not be null.");
+
+ if (!StringUtils.hasText(updateQuery) && !StringUtils.hasText(selectQuery)) {
+ throw new IllegalArgumentException("The 'updateQuery' and the 'selectQuery' must not both be null or empty.");
+ }
+
+ if (StringUtils.hasText(selectQuery)) {
poller = new JdbcPollingChannelAdapter(jdbcOperations, selectQuery);
poller.setMaxRowsPerPoll(1);
}
else {
poller = null;
}
- handler = new JdbcMessageHandler(jdbcOperations, updateQuery);
+
+ if (StringUtils.hasText(updateQuery)) {
+ handler = new JdbcMessageHandler(jdbcOperations, updateQuery);
+ }
+ else {
+ handler = null;
+ }
+
}
/**
@@ -96,13 +112,24 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
poller.setMaxRowsPerPoll(this.maxRowsPerPoll);
}
- handler.afterPropertiesSet();
+ if (this.handler!= null) {
+ handler.afterPropertiesSet();
+ }
}
@Override
protected Object handleRequestMessage(Message> requestMessage) {
- List> list = handler.executeUpdateQuery(requestMessage, keysGenerated);
+
+ List> list;
+
+ if (this.handler != null) {
+ list = handler.executeUpdateQuery(requestMessage, keysGenerated);
+ }
+ else {
+ list = Collections.emptyList();
+ }
+
if (poller != null) {
SqlParameterSource sqlQueryParameterSource = sqlParameterSourceFactory
.createParameterSource(requestMessage);
diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java
index 1c7249ad20..864b264959 100644
--- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java
+++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java
@@ -36,22 +36,18 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
String jdbcOperationsRef = element.getAttribute("jdbc-operations");
boolean refToDataSourceSet = StringUtils.hasText(dataSourceRef);
boolean refToJdbcOperationsSet = StringUtils.hasText(jdbcOperationsRef);
+
if ((refToDataSourceSet && refToJdbcOperationsSet) || (!refToDataSourceSet && !refToJdbcOperationsSet)) {
parserContext.getReaderContext().error(
"Exactly one of the attributes data-source or "
+ "simple-jdbc-operations should be set for the JDBC outbound-gateway", element);
}
+
String selectQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query",
parserContext);
- if (!StringUtils.hasText(selectQuery)) {
- selectQuery = null;
- }
String updateQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update",
parserContext);
- if (!StringUtils.hasText(updateQuery)) {
- parserContext.getReaderContext().error("The update attribute is required", element);
- return null;
- }
+
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(JdbcOutboundGateway.class);
if (refToDataSourceSet) {
@@ -61,8 +57,8 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
builder.addConstructorArgReference(jdbcOperationsRef);
}
- builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(1, updateQuery);
- builder.getRawBeanDefinition().getConstructorArgumentValues().addIndexedArgumentValue(2, selectQuery);
+ builder.addConstructorArgValue(updateQuery);
+ builder.addConstructorArgValue(selectQuery);
IntegrationNamespaceUtils
.setReferenceIfAttributeDefined(builder, element, "reply-sql-parameter-source-factory");
diff --git a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
index 1217053ebb..ae8c3bed9a 100644
--- a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
+++ b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-2.2.xsd
@@ -315,9 +315,14 @@
Defines an outbound Channel Gateway for updating a
- database in response to a message on the request
- channel and getting a response
- on the reply channel. The response can be created from a query
+ database in response to a message on the request channel, and/or
+ for retrieving data from the database using the input message as
+ a source of parameters for the specified SQL select query.
+
+ The database response will be used to create the response Message
+ on the reply channel.
+
+ The response can be created from a query
supplied here, or (if keys-generated="true") can be the
primary keys generated from an auto-increment, or else just a
count of the number of rows affected by the update. The response
@@ -334,9 +339,19 @@
- An update query to execute when a message is
+ An update query to be executed when a message is
received. If this is in a transaction then the
update will roll back when the transaction does.
+
+ The update can also be specified using the
+ "update" attribute.
+
+ Since Spring Integration 2.2 specifying an
+ update query is optional, if at least the
+ select query is specified.
+
+ If you specify both, update- and select
+ query, then the update is executed first.
@@ -353,6 +368,13 @@
update will roll back when the transaction does.
The update can also be specified as a nested element.
+
+ Since Spring Integration 2.2 specifying an
+ update query is optional, if at least the
+ select query is specified.
+
+ If you specify both, update- and select
+ query, then the update is executed first.
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java
index 1bfe6658cf..e066192c6c 100644
--- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java
@@ -16,9 +16,12 @@ import static org.junit.Assert.fail;
import javax.sql.DataSource;
+import junit.framework.Assert;
+
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
+import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
/**
@@ -35,12 +38,12 @@ public class JdbcOutboundGatewayTests {
DataSource dataSource = new EmbeddedDatabaseBuilder().build();
- JdbcOutboundGateway jdbcOutboundGateway = new JdbcOutboundGateway(dataSource, "select * from DOES_NOT_EXIST");
+ JdbcOutboundGateway jdbcOutboundGateway = new JdbcOutboundGateway(dataSource, "update something");
try {
jdbcOutboundGateway.setMaxRowsPerPoll(10);
jdbcOutboundGateway.onInit();
-
+
} catch (IllegalArgumentException e) {
assertEquals("If you want to set 'maxRowsPerPoll', then you must provide a 'selectQuery'.", e.getMessage());
return;
@@ -50,6 +53,41 @@ public class JdbcOutboundGatewayTests {
}
+ @Test
+ public void testConstructorWithNulljdbcOperations() {
+
+ JdbcOperations jdbcOperations = null;
+
+ try {
+ new JdbcOutboundGateway(jdbcOperations, "select * from DOES_NOT_EXIST");
+ }
+ catch (IllegalArgumentException e) {
+ Assert.assertEquals("'jdbcOperations' must not be null.", e.getMessage());
+ return;
+ }
+
+ fail("Expected an IllegalArgumentException to be thrown.");
+ }
+
+ @Test
+ public void testConstructorWithEmptyAndNullQueries() {
+
+ final DataSource dataSource = new EmbeddedDatabaseBuilder().build();
+
+ final String selectQuery = " ";
+ final String updateQuery = null;
+
+ try {
+ new JdbcOutboundGateway(dataSource, updateQuery, selectQuery);
+ }
+ catch (IllegalArgumentException e) {
+ Assert.assertEquals("The 'updateQuery' and the 'selectQuery' must not both be null or empty.", e.getMessage());
+ return;
+ }
+
+ fail("Expected an IllegalArgumentException to be thrown.");
+ }
+
/**
* Test method for
* {@link org.springframework.integration.jdbc.JdbcOutboundGateway#setMaxRowsPerPoll(Integer)}.
diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java
index 78f632b0a4..75b4f0a40f 100644
--- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java
+++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java
@@ -119,6 +119,28 @@ public class JdbcOutboundGatewayParserTests {
assertEquals("bar", payload.get("name"));
}
+ @Test
+ public void testWithSelectQueryOnly() throws Exception{
+ ApplicationContext ac = new ClassPathXmlApplicationContext("JdbcOutboundGatewayWithSelectTest-context.xml", this.getClass());
+ Message> message = MessageBuilder.withPayload(Integer.valueOf(100)).build();
+ MessageChannel requestChannel = ac.getBean("request", MessageChannel.class);
+ PollableChannel replyChannel = ac.getBean("reply", PollableChannel.class);
+
+ requestChannel.send(message);
+ Thread.sleep(1000);
+
+ @SuppressWarnings("unchecked")
+ Message