diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java
index ab9a91b8db..01d2ed28b0 100644
--- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java
+++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java
@@ -143,7 +143,7 @@ public abstract class TcpConnectionSupport implements TcpConnection {
if (logger.isDebugEnabled()) {
logger.debug("Closing single-use connection" + this.getConnectionId());
}
- this.closeConnection();
+ this.closeConnection(false);
}
}
}
@@ -165,7 +165,7 @@ public abstract class TcpConnectionSupport implements TcpConnection {
* If we have been intercepted, propagate the close from the outermost interceptor;
* otherwise, just call close().
*/
- protected void closeConnection() {
+ protected void closeConnection(boolean isException) {
if (!(this.listener instanceof TcpConnectionInterceptor)) {
close();
return;
@@ -175,6 +175,10 @@ public abstract class TcpConnectionSupport implements TcpConnection {
outerInterceptor = (TcpConnectionInterceptor) outerInterceptor.getListener();
}
outerInterceptor.close();
+ if (isException) {
+ // ensure physical close in case the interceptor did not close
+ this.close();
+ }
}
/**
diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java
index 204494b300..bbd71c52a0 100644
--- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java
+++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java
@@ -170,7 +170,7 @@ public class TcpNetConnection extends TcpConnectionSupport {
catch (NoListenerException nle) {
if (singleUse) {
logger.debug("Closing single use socket after inbound message " + this.getConnectionId());
- this.closeConnection();
+ this.closeConnection(true);
okToRun = false;
} else {
logger.warn("Unexpected message - no inbound adapter registered with connection " + message);
@@ -186,7 +186,7 @@ public class TcpNetConnection extends TcpConnectionSupport {
*/
if (singleUse && ((!this.isServer() && !intercepted) || (this.isServer() && this.getSender() == null))) {
logger.debug("Closing single use socket after inbound message " + this.getConnectionId());
- this.closeConnection();
+ this.closeConnection(false);
okToRun = false;
}
}
@@ -212,12 +212,11 @@ public class TcpNetConnection extends TcpConnectionSupport {
}
catch (SocketException e1) {
logger.error("Error accessing soTimeout", e1);
- doClose = true;
}
}
if (doClose) {
boolean noReadErrorOnClose = this.isNoReadErrorOnClose();
- this.closeConnection();
+ this.closeConnection(true);
if (!(e instanceof SoftEndOfStreamException)) {
if (e instanceof SocketTimeoutException && this.isSingleUse()) {
if (logger.isDebugEnabled()) {
diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java
index 139f6ba061..25c0ff1e34 100644
--- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java
+++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java
@@ -228,7 +228,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
":" + e.getCause() + ":" + e.getMessage());
}
}
- this.closeConnection();
+ this.closeConnection(true);
this.sendExceptionToListener(e);
return;
}
@@ -268,8 +268,9 @@ public class TcpNioConnection extends TcpConnectionSupport {
Message> message = null;
try {
message = this.getMapper().toMessage(this);
- } catch (Exception e) {
- this.closeConnection();
+ }
+ catch (Exception e) {
+ this.closeConnection(true);
if (e instanceof SocketTimeoutException && this.isSingleUse()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing single use socket after timeout " + this.getConnectionId());
@@ -290,13 +291,14 @@ public class TcpNioConnection extends TcpConnectionSupport {
if (message != null) {
intercepted = getListener().onMessage(message);
}
- } catch (Exception e) {
+ }
+ catch (Exception e) {
if (e instanceof NoListenerException) {
if (this.isSingleUse()) {
if (logger.isDebugEnabled()) {
logger.debug("Closing single use channel after inbound message " + this.getConnectionId());
}
- this.closeConnection();
+ this.closeConnection(true);
}
}
else {
@@ -312,7 +314,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
if (logger.isDebugEnabled()) {
logger.debug("Closing single use channel after inbound message " + this.getConnectionId());
}
- this.closeConnection();
+ this.closeConnection(false);
}
}
@@ -334,7 +336,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
int len = this.socketChannel.read(this.rawBuffer);
if (len < 0) {
this.writingToPipe = false;
- this.closeConnection();
+ this.closeConnection(true);
}
if (logger.isTraceEnabled()) {
logger.trace("After read:" + this.rawBuffer.position() + "/" + this.rawBuffer.limit());
@@ -412,16 +414,18 @@ public class TcpNioConnection extends TcpConnectionSupport {
}
try {
doRead();
- } catch (ClosedChannelException cce) {
+ }
+ catch (ClosedChannelException cce) {
if (logger.isDebugEnabled()) {
logger.debug(this.getConnectionId() + " Channel is closed");
}
- this.closeConnection();
- } catch (Exception e) {
+ this.closeConnection(true);
+ }
+ catch (Exception e) {
logger.error("Exception on Read " +
this.getConnectionId() + " " +
e.getMessage(), e);
- this.closeConnection();
+ this.closeConnection(true);
}
}
@@ -429,7 +433,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
* Close the socket due to timeout.
*/
void timeout() {
- this.closeConnection();
+ this.closeConnection(true);
}
/**
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests-context.xml
index ce3986f640..522674071d 100644
--- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests-context.xml
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests-context.xml
@@ -7,12 +7,13 @@
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ port="#{tcpIpUtils.findAvailableServerSocket()}"/>
@@ -53,7 +54,7 @@
id="gateway.ccf"
type="client"
host="localhost"
- port="9876"
+ port="#{scf.port}"
so-timeout="60000"
/>
diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java
index 01673f9b04..ef2ad7e7ea 100644
--- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java
+++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java
@@ -16,6 +16,7 @@
package org.springframework.integration.ip.tcp.connection;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
@@ -353,6 +354,28 @@ public class CachingClientConnectionFactoryTests {
okToRun.set(false);
}
+ @Test
+ public void testCloseOnTimeoutNet() throws Exception {
+ TcpNetClientConnectionFactory cf = new TcpNetClientConnectionFactory("localhost", serverCf.getPort());
+ testCloseOnTimeoutGuts(cf);
+ }
+
+ @Test
+ public void testCloseOnTimeoutNio() throws Exception {
+ TcpNioClientConnectionFactory cf = new TcpNioClientConnectionFactory("localhost", serverCf.getPort());
+ testCloseOnTimeoutGuts(cf);
+ }
+
+ private void testCloseOnTimeoutGuts(AbstractClientConnectionFactory cf) throws Exception, InterruptedException {
+ cf.setSoTimeout(100);
+ CachingClientConnectionFactory cccf = new CachingClientConnectionFactory(cf, 1);
+ cccf.start();
+ TcpConnection connection = cccf.getConnection();
+ Thread.sleep(200);
+ assertFalse(connection.isOpen());
+ cccf.stop();
+ }
+
@Test
public void testCachedFailover() throws Exception {
// Failover