INT-3111 Fix Close Cached TCP Connection
A TCP Connection is closed when an outbound gateway times out. However, with the CachingClientConnectionFactory, the connection was returned to the pool instead of being physically closed. Override forceClose() and physically close the connection so the next time it is retrieved from the pool it is detected as stale and re-established. Refactor test case and invoke it twice; once with a regular connection factory and once with a cached factory. Remove an unused logger.
This commit is contained in:
@@ -17,8 +17,6 @@ package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.serializer.Deserializer;
|
||||
import org.springframework.core.serializer.Serializer;
|
||||
import org.springframework.integration.Message;
|
||||
@@ -34,8 +32,6 @@ import org.springframework.integration.util.SimplePool;
|
||||
*/
|
||||
public class CachingClientConnectionFactory extends AbstractClientConnectionFactory {
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final AbstractClientConnectionFactory targetConnectionFactory;
|
||||
|
||||
private final SimplePool<TcpConnectionSupport> pool;
|
||||
@@ -160,6 +156,10 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact
|
||||
return true; // true so the single-use connection doesn't close itself
|
||||
}
|
||||
|
||||
private void physicallyClose() {
|
||||
this.getTheConnection().close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////// DELEGATE METHODS ///////////////////////
|
||||
@@ -357,6 +357,16 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact
|
||||
return targetConnectionFactory.isLookupHost();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void forceClose(TcpConnection connection) {
|
||||
if (connection instanceof CachedConnection) {
|
||||
((CachedConnection) connection).physicallyClose();
|
||||
}
|
||||
// will be returned to pool but stale, so will be re-established
|
||||
super.forceClose(connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.setActive(true);
|
||||
|
||||
@@ -45,12 +45,15 @@ import javax.net.ServerSocketFactory;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
import org.springframework.core.serializer.DefaultSerializer;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageTimeoutException;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.CachingClientConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.SocketUtils;
|
||||
@@ -255,15 +258,39 @@ public class TcpOutboundGatewayTests {
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoodNetGWTimeout() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractClientConnectionFactory ccf = buildCF(port);
|
||||
ccf.start();
|
||||
testGoodNetGWTimeoutGuts(port, ccf);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoodNetGWTimeoutCached() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
AbstractClientConnectionFactory ccf = buildCF(port);
|
||||
CachingClientConnectionFactory cccf = new CachingClientConnectionFactory(ccf, 1);
|
||||
cccf.start();
|
||||
testGoodNetGWTimeoutGuts(port, cccf);
|
||||
}
|
||||
|
||||
private AbstractClientConnectionFactory buildCF(final int port) {
|
||||
AbstractClientConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSingleUse(false);
|
||||
return ccf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends 2 concurrent messages on a shared connection. The GW single threads
|
||||
* these requests. The first will timeout; the second should receive its
|
||||
* own response, not that for the first.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGoodNetGWTimeout() throws Exception {
|
||||
final int port = SocketUtils.findAvailableServerSocket();
|
||||
private void testGoodNetGWTimeoutGuts(final int port, AbstractConnectionFactory ccf) throws InterruptedException {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicBoolean done = new AtomicBoolean();
|
||||
/*
|
||||
@@ -298,23 +325,19 @@ public class TcpOutboundGatewayTests {
|
||||
serverLatch.countDown();
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.debug("error on write " + e.getClass().getSimpleName());
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (!done.get()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSingleUse(false);
|
||||
ccf.start();
|
||||
assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
|
||||
final TcpOutboundGateway gateway = new TcpOutboundGateway();
|
||||
gateway.setConnectionFactory(ccf);
|
||||
@@ -349,10 +372,12 @@ public class TcpOutboundGatewayTests {
|
||||
String reply = (String) replyChannel.receive(1000).getPayload();
|
||||
logger.debug(i + " got " + result + " " + reply);
|
||||
replies.add(reply);
|
||||
} catch (ExecutionException e) {
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
if (timeouts >= 2) {
|
||||
fail("Unexpected " + e.getMessage());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
assertNotNull(e.getCause());
|
||||
assertTrue(e.getCause() instanceof MessageTimeoutException);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user