diff --git a/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java b/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java index 8a75ab704a..5bbbe10445 100644 --- a/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java +++ b/quickfixj-core/src/main/java/quickfix/mina/AbstractIoHandler.java @@ -22,6 +22,7 @@ import java.io.IOException; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; +import org.apache.mina.core.write.WriteToClosedSessionException; import org.apache.mina.filter.codec.ProtocolCodecException; import org.apache.mina.filter.codec.ProtocolDecoderException; import org.slf4j.Logger; @@ -81,7 +82,10 @@ public void exceptionCaught(IoSession ioSession, Throwable cause) throws Excepti } } String reason; - if (realCause instanceof IOException) { + if (realCause instanceof WriteToClosedSessionException) { + log.debug("Write to closed session ({}): {}", ioSession.getRemoteAddress(), cause.getMessage()); + return; + } else if (realCause instanceof IOException) { if (quickFixSession != null && quickFixSession.isEnabled()) { reason = "Socket exception (" + ioSession.getRemoteAddress() + "): " + cause; } else { diff --git a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java index dd12d23069..9e718e1a8b 100644 --- a/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java +++ b/quickfixj-core/src/test/java/quickfix/mina/acceptor/AcceptorIoHandlerTest.java @@ -20,6 +20,8 @@ package quickfix.mina.acceptor; import org.apache.mina.core.session.IoSession; +import org.apache.mina.core.write.DefaultWriteRequest; +import org.apache.mina.core.write.WriteToClosedSessionException; import org.junit.Test; import quickfix.FixVersions; import quickfix.Message; @@ -403,6 +405,27 @@ public void testRejectGarbledMessageWithoutMsgTypeBeforeSessionIsCreated() throw } } + // QFJ-928 + @Test + public void testWriteToClosedSessionExceptionIsHandledGracefully() throws Exception { + IoSession mockIoSession = mock(IoSession.class); + SessionSettings settings = mock(SessionSettings.class); + EventHandlingStrategy mockEventHandlingStrategy = mock(EventHandlingStrategy.class); + + when(mockIoSession.getAttribute("QF_SESSION")).thenReturn(null); + + AcceptorIoHandler handler = new AcceptorIoHandler(createSessionProvider(new HashMap<>()), + settings, new NetworkingOptions(new Properties()), mockEventHandlingStrategy); + + WriteToClosedSessionException exception = new WriteToClosedSessionException(new DefaultWriteRequest("test")); + // Should not throw and should not call setAttribute for QFJ_RESET_IO_CONNECTOR + handler.exceptionCaught(mockIoSession, exception); + + verify(mockIoSession).getAttribute("QF_SESSION"); + verify(mockIoSession).getRemoteAddress(); + verifyNoMoreInteractions(mockIoSession); + } + private class UnitTestResponder implements Responder { public String sentMessageData;