INT-4202: Fix StoredProcOutboundGateway NPE
JIRA: https://jira.spring.io/browse/INT-4202 The `StoredProcOutboundGateway` uses `MessageBuilder` directly for procedure result without any conditions. If procedure result is `null`, `MessageBuilder.withPayload` throws `java.lang.IllegalArgumentException: payload must not be null`. * Since the super `AbstractReplyProducingMessageHandler` class takes care about `null` reply properly via its `requiresReply` property and really uses `MessageBuilder` for reply, just fix `StoredProcOutboundGateway` to return procedure result as is from the `handleRequestMessage()` implementation * Fix some typos and code style * Increase some JDBC tests performance changing `Thread.sleep()` solution to proper `PollableChannel.receive()` or iterations over expected result **Cherry-pick to 4.3.x** Update `@Copyright` to 2017 Make `StoredProcOutboundGateway` as `requiresReply = true` by default Revert `setRequiresReply(true)` change Specify `setRequiresReply(true)` only if `expectSingleResult == true` and `setRequiresReply()` hasn't been called explicitly Conflicts: spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcOutboundGateway.java spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreChannelIntegrationTests.java spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java Resolved.
This commit is contained in:
committed by
Gary Russell
parent
85a825cd75
commit
0c2ba3f761
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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,7 +26,11 @@ import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link AbstractReplyProducingMessageHandler} implementation for performing
|
||||
* RDBMS stored procedures which return results.
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -36,17 +40,45 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand
|
||||
|
||||
private volatile boolean expectSingleResult = false;
|
||||
|
||||
private boolean requiresReplyExplicitlySet;
|
||||
|
||||
/**
|
||||
* Constructor taking {@link StoredProcExecutor}.
|
||||
*
|
||||
* @param storedProcExecutor Must not be null.
|
||||
*
|
||||
*/
|
||||
public StoredProcOutboundGateway(StoredProcExecutor storedProcExecutor) {
|
||||
|
||||
Assert.notNull(storedProcExecutor, "storedProcExecutor must not be null.");
|
||||
this.executor = storedProcExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiresReply(boolean requiresReply) {
|
||||
super.setRequiresReply(requiresReply);
|
||||
this.requiresReplyExplicitlySet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This parameter indicates that only one result object shall be returned from
|
||||
* the Stored Procedure/Function Call. If set to {@code true}, a {@code resultMap} that contains
|
||||
* only 1 element, will have that 1 element extracted and returned as payload.
|
||||
* <p> If the {@code resultMap} contains more than 1 element and {@code expectSingleResult == true},
|
||||
* then a {@link MessagingException} is thrown.
|
||||
* <p> Otherwise the complete {@code resultMap} is returned as the {@link Message} payload.
|
||||
* <p> Important Note: Several databases such as H2 are not fully supported.
|
||||
* The H2 database, for example, does not fully support the {@link CallableStatement}
|
||||
* semantics and when executing function calls against H2, a result list is
|
||||
* returned rather than a single value.
|
||||
* <p> Therefore, even if you set {@code expectSingleResult = true}, you may end up with
|
||||
* a collection being returned.
|
||||
* <p> When set to {@code true}, a {@link #setRequiresReply(boolean)} is called
|
||||
* with {@code true} as well, indicating that exactly single result is expected
|
||||
* and {@code null} isn't appropriate value.
|
||||
* A {@link org.springframework.integration.handler.ReplyRequiredException} is thrown
|
||||
* in case of {@code null} result.
|
||||
* @param expectSingleResult true if a single result is expected.
|
||||
*/
|
||||
public void setExpectSingleResult(boolean expectSingleResult) {
|
||||
this.expectSingleResult = expectSingleResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -55,8 +87,15 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
protected void doInit() {
|
||||
super.doInit();
|
||||
if (!this.requiresReplyExplicitlySet) {
|
||||
setRequiresReply(this.expectSingleResult);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object handleRequestMessage(Message<?> requestMessage) {
|
||||
Map<String, Object> resultMap = this.executor.executeStoredProcedure(requestMessage);
|
||||
|
||||
final Object payload;
|
||||
@@ -65,7 +104,6 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
|
||||
if (this.expectSingleResult && resultMap.size() == 1) {
|
||||
payload = resultMap.values().iterator().next();
|
||||
}
|
||||
@@ -73,41 +111,16 @@ public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHand
|
||||
|
||||
throw new MessageHandlingException(requestMessage,
|
||||
"Stored Procedure/Function call returned more than "
|
||||
+ "1 result object and expectSingleResult was 'true'. ");
|
||||
|
||||
+ "1 result object and expectSingleResult was 'true'. ");
|
||||
}
|
||||
else {
|
||||
payload = resultMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this.getMessageBuilderFactory().withPayload(payload).copyHeaders(requestMessage.getHeaders()).build();
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* This parameter indicates that only one result object shall be returned from
|
||||
* the Stored Procedure/Function Call. If set to true, a resultMap that contains
|
||||
* only 1 element, will have that 1 element extracted and returned as payload.
|
||||
*
|
||||
* If the resultMap contains more than 1 element and expectSingleResult is true,
|
||||
* then a {@link MessagingException} is thrown.
|
||||
*
|
||||
* Otherwise the complete resultMap is returned as the {@link Message} payload.
|
||||
*
|
||||
* Important Note: Several databases such as H2 are not fully supported.
|
||||
* The H2 database, for example, does not fully support the {@link CallableStatement}
|
||||
* semantics and when executing function calls against H2, a result list is
|
||||
* returned rather than a single value.
|
||||
*
|
||||
* Therefore, even if you set expectSingleResult = true, you may end up with
|
||||
* a collection being returned.
|
||||
*
|
||||
* @param expectSingleResult true if a single result is expected.
|
||||
*/
|
||||
public void setExpectSingleResult(boolean expectSingleResult) {
|
||||
this.expectSingleResult = expectSingleResult;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -51,11 +51,11 @@ public class StoredProcOutboundGatewayParser extends AbstractConsumerEndpointPar
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(storedProcExecutorBuilder, element, "sql-parameter-source-factory");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(storedProcExecutorBuilder, element, "skip-undeclared-results");
|
||||
|
||||
final ManagedMap<String, BeanMetadataElement> returningResultsetMap =
|
||||
final ManagedMap<String, BeanMetadataElement> returningResultSetMap =
|
||||
StoredProcParserUtils.getReturningResultsetBeanDefinitions(element, parserContext);
|
||||
|
||||
if (!returningResultsetMap.isEmpty()) {
|
||||
storedProcExecutorBuilder.addPropertyValue("returningResultSetRowMappers", returningResultsetMap);
|
||||
if (!returningResultSetMap.isEmpty()) {
|
||||
storedProcExecutorBuilder.addPropertyValue("returningResultSetRowMappers", returningResultSetMap);
|
||||
}
|
||||
|
||||
final AbstractBeanDefinition storedProcExecutorBuilderBeanDefinition = storedProcExecutorBuilder.getBeanDefinition();
|
||||
|
||||
@@ -656,7 +656,7 @@ public class JdbcChannelMessageStore implements PriorityCapableChannelMessageSto
|
||||
*/
|
||||
public void removeFromIdCache(String messageId) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing Message Id:" + messageId);
|
||||
logger.debug("Removing Message Id: " + messageId);
|
||||
}
|
||||
this.idCacheWriteLock.lock();
|
||||
try {
|
||||
|
||||
@@ -963,7 +963,7 @@
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="false">
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
||||
@@ -2,17 +2,10 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<import resource="classpath:derby-stored-procedures-setup-context.xml"/>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.util.Collection;
|
||||
@@ -38,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.handler.ReplyRequiredException;
|
||||
import org.springframework.integration.jdbc.config.JdbcTypesEnum;
|
||||
import org.springframework.integration.jdbc.storedproc.User;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
@@ -149,6 +151,7 @@ public class StoredProcOutboundGatewayWithSpelIntegrationTests {
|
||||
@Test
|
||||
@Transactional
|
||||
public void testInt2865SqlReturnType() throws Exception {
|
||||
Mockito.reset(this.clobSqlReturnType);
|
||||
Message<String> testMessage = MessageBuilder.withPayload("TEST").setHeader("FOO", "BAR").build();
|
||||
String messageId = testMessage.getHeaders().getId().toString();
|
||||
String jsonMessage = new JsonOutboundMessageMapper().fromMessage(testMessage);
|
||||
@@ -168,6 +171,17 @@ public class StoredProcOutboundGatewayWithSpelIntegrationTests {
|
||||
Mockito.eq(2), Mockito.eq(JdbcTypesEnum.CLOB.getCode()), Mockito.eq((String) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoIllegalArgumentButRequiresReplyException() {
|
||||
try {
|
||||
this.getMessageChannel.send(new GenericMessage<String>("foo"));
|
||||
fail("ReplyRequiredException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(ReplyRequiredException.class));
|
||||
}
|
||||
}
|
||||
|
||||
static class Counter {
|
||||
|
||||
private final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvi
|
||||
import org.springframework.integration.jdbc.JdbcMessageHandler;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -117,8 +119,18 @@ public class JdbcMessageHandlerParserTests {
|
||||
MessageChannel target = context.getBean("target", MessageChannel.class);
|
||||
Message<?> message = MessageBuilder.withPayload("foo").setHeader("business.key", "FOO").build();
|
||||
target.send(message);
|
||||
Thread.sleep(2000);
|
||||
Map<String, Object> map = (context.getBean("jdbcTemplate", JdbcTemplate.class)).queryForMap("SELECT * from FOOW");
|
||||
|
||||
JdbcTemplate jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
|
||||
int n = 0;
|
||||
List<Map<String, Object>> result = jdbcTemplate.query("SELECT * from FOOW", new ColumnMapRowMapper());
|
||||
while (result.isEmpty() && n++ < 100) {
|
||||
Thread.sleep(100);
|
||||
result = jdbcTemplate.query("SELECT * from FOOW", new ColumnMapRowMapper());
|
||||
}
|
||||
assertTrue(n < 100);
|
||||
|
||||
assertEquals(1, result.size());
|
||||
Map<String, Object> map = result.get(0);
|
||||
assertEquals("Wrong id", "FOO", map.get("ID"));
|
||||
assertEquals("Wrong id", "foo", map.get("name"));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -50,6 +50,8 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||
/**
|
||||
* @author David Syer
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.0
|
||||
*
|
||||
*/
|
||||
@@ -69,6 +71,7 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
public void testNoAutoStartupInboundChannelAdapter() {
|
||||
setUp("pollingNoAutoStartupJdbcInboundChannelAdapterTest.xml", getClass());
|
||||
this.jdbcTemplate.update("insert into item values(1,'',2)");
|
||||
messagingTemplate.setReceiveTimeout(1);
|
||||
Message<?> message = messagingTemplate.receive();
|
||||
assertNull("Message found ", message);
|
||||
}
|
||||
@@ -94,8 +97,9 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
this.jdbcTemplate.update("insert into item values(1,'',2)");
|
||||
Message<?> message = messagingTemplate.receive();
|
||||
assertNotNull(message);
|
||||
messagingTemplate.setReceiveTimeout(1);
|
||||
message = messagingTemplate.receive();
|
||||
assertNull(messagingTemplate.receive());
|
||||
assertNull(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -104,8 +108,9 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
this.jdbcTemplate.update("insert into item values(1,'',2)");
|
||||
Message<?> message = messagingTemplate.receive();
|
||||
assertNotNull(message);
|
||||
messagingTemplate.setReceiveTimeout(1);
|
||||
message = messagingTemplate.receive();
|
||||
assertNull(messagingTemplate.receive());
|
||||
assertNull(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -171,7 +171,7 @@ public class StoredProcOutboundGatewayParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testProcedurepParametersAreSet() throws Exception {
|
||||
public void testProcedureParametersAreSet() throws Exception {
|
||||
setUp("storedProcOutboundGatewayParserTest.xml", getClass());
|
||||
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway);
|
||||
@@ -200,7 +200,7 @@ public class StoredProcOutboundGatewayParserTests {
|
||||
assertEquals("kenny", parameter1.getValue());
|
||||
assertEquals("Who killed Kenny?", parameter2.getValue());
|
||||
assertNull(parameter3.getValue());
|
||||
assertEquals(Integer.valueOf(30), parameter4.getValue());
|
||||
assertEquals(30, parameter4.getValue());
|
||||
|
||||
assertNull(parameter1.getExpression());
|
||||
assertNull(parameter2.getExpression());
|
||||
@@ -273,11 +273,8 @@ public class StoredProcOutboundGatewayParserTests {
|
||||
assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType());
|
||||
assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType());
|
||||
|
||||
assertTrue(parameter1 instanceof SqlParameter);
|
||||
assertTrue(parameter2 instanceof SqlOutParameter);
|
||||
assertTrue(parameter3 instanceof SqlInOutParameter);
|
||||
assertTrue(parameter4 instanceof SqlParameter);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,39 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<int:channel id="requestChannel" />
|
||||
<int:channel id="replyChannel" />
|
||||
<int:channel id="requestChannel"/>
|
||||
<int:channel id="replyChannel"/>
|
||||
|
||||
<jdbc:embedded-database id="datasource" type="HSQL" />
|
||||
<jdbc:embedded-database id="datasource" type="HSQL"/>
|
||||
|
||||
<int-jdbc:stored-proc-outbound-gateway
|
||||
request-channel="requestChannel" stored-procedure-name="GET_PRIME_NUMBERS"
|
||||
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="false">
|
||||
<int-jdbc:stored-proc-outbound-gateway
|
||||
request-channel="requestChannel" stored-procedure-name="GET_PRIME_NUMBERS"
|
||||
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="false">
|
||||
|
||||
<int-jdbc:sql-parameter-definition name="username" direction="IN" type="VARCHAR" />
|
||||
<int-jdbc:sql-parameter-definition name="password" direction="OUT" />
|
||||
<int-jdbc:sql-parameter-definition name="age" direction="INOUT" type="INTEGER" scale="5" />
|
||||
<int-jdbc:sql-parameter-definition name="description" />
|
||||
<int-jdbc:parameter name="username" value="kenny" type="java.lang.String" />
|
||||
<int-jdbc:parameter name="description" value="Who killed Kenny?" />
|
||||
<int-jdbc:parameter name="password" expression="payload.username" />
|
||||
<int-jdbc:parameter name="age" value="30" type="java.lang.Integer" />
|
||||
<int-jdbc:returning-resultset name="out" row-mapper="org.springframework.integration.jdbc.storedproc.PrimeMapper"/>
|
||||
<int-jdbc:sql-parameter-definition name="username" direction="IN" type="VARCHAR"/>
|
||||
<int-jdbc:sql-parameter-definition name="password" direction="OUT"/>
|
||||
<int-jdbc:sql-parameter-definition name="age" direction="INOUT" type="INTEGER" scale="5"/>
|
||||
<int-jdbc:sql-parameter-definition name="description"/>
|
||||
<int-jdbc:parameter name="username" value="kenny" type="java.lang.String"/>
|
||||
<int-jdbc:parameter name="description" value="Who killed Kenny?"/>
|
||||
<int-jdbc:parameter name="password" expression="payload.username"/>
|
||||
<int-jdbc:parameter name="age" value="30" type="java.lang.Integer"/>
|
||||
<int-jdbc:returning-resultset name="out"
|
||||
row-mapper="org.springframework.integration.jdbc.storedproc.PrimeMapper"/>
|
||||
|
||||
<int-jdbc:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.jdbc.config.StoredProcOutboundGatewayParserTests$FooAdvice" />
|
||||
</int-jdbc:request-handler-advice-chain>
|
||||
</int-jdbc:stored-proc-outbound-gateway>
|
||||
<int-jdbc:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.jdbc.config.StoredProcOutboundGatewayParserTests$FooAdvice"/>
|
||||
</int-jdbc:request-handler-advice-chain>
|
||||
</int-jdbc:stored-proc-outbound-gateway>
|
||||
|
||||
<int:poller default="true" fixed-rate="10000"/>
|
||||
|
||||
<int:poller default="true" fixed-rate="10000" />
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -101,6 +101,9 @@ public abstract class AbstractTxTimeoutMessageStoreTests {
|
||||
@Autowired
|
||||
protected PollableChannel priorityChannel;
|
||||
|
||||
@Autowired
|
||||
protected PollableChannel afterTxChannel;
|
||||
|
||||
@Test
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
@@ -131,7 +134,10 @@ public abstract class AbstractTxTimeoutMessageStoreTests {
|
||||
Assert.assertTrue(String.format("Countdown latch did not count down from " +
|
||||
"%s to 0 in %sms.", maxMessages, maxWaitTime), testService.await(maxWaitTime));
|
||||
|
||||
Thread.sleep(2000);
|
||||
for (int i = 0; i < maxMessages; i++) {
|
||||
Message<?> afterTxMessage = this.afterTxChannel.receive(10000);
|
||||
assertNotNull(afterTxMessage);
|
||||
}
|
||||
|
||||
Assert.assertEquals(Integer.valueOf(0), Integer.valueOf(jdbcChannelMessageStore.getSizeOfIdCache()));
|
||||
Assert.assertEquals(Integer.valueOf(maxMessages), Integer.valueOf(testService.getSeenMessages().size()));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -69,7 +69,7 @@ public class TestService {
|
||||
|
||||
if (this.threadSleep > 0) {
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
Thread.sleep(10);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
@@ -2,22 +2,20 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
|
||||
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/task/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<int:transaction-synchronization-factory id="syncFactory">
|
||||
<int:after-commit expression="@store.removeFromIdCache(headers.id.toString())" />
|
||||
<int:after-rollback expression="@store.removeFromIdCache(headers.id.toString())"/>
|
||||
<int:before-commit expression="@store.removeFromIdCache(headers.id.toString())"/>
|
||||
<int:after-commit channel="afterTxChannel"/>
|
||||
</int:transaction-synchronization-factory>
|
||||
|
||||
<int:channel id="afterTxChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<task:executor id="pool" pool-size="10" queue-capacity="10" rejection-policy="CALLER_RUNS" />
|
||||
|
||||
<bean id="store" class="org.springframework.integration.jdbc.store.JdbcChannelMessageStore">
|
||||
|
||||
Reference in New Issue
Block a user