This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch camel-2.22.x in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-2.22.x by this push: new 12a749b CAMEL-12830 - Thanks to Laurent Chiarello for reporting and providing the fix (creating github PR for his sake) 12a749b is described below commit 12a749b12b422d17341f16cf40581ce9b4e78a7b Author: onders <ond...@apache.org> AuthorDate: Tue Oct 2 00:41:48 2018 +0300 CAMEL-12830 - Thanks to Laurent Chiarello for reporting and providing the fix (creating github PR for his sake) --- .../camel/component/file/remote/FtpOperations.java | 8 ++ .../component/file/remote/FtpSoTimeoutTest.java | 108 +++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java index 646c398..25cee35 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/FtpOperations.java @@ -128,6 +128,14 @@ public class FtpOperations implements RemoteFileOperations<FTPFile> { throw new GenericFileOperationFailedException(client.getReplyCode(), client.getReplyString(), "Server refused connection"); } } catch (Exception e) { + if (client.isConnected()) { + log.trace("Disconnecting due to exception during connect"); + try { + client.disconnect(); // ensures socket is closed + } catch (IOException ignore) { + log.trace("Ignore exception during disconnect: {}", ignore.getMessage()); + } + } // check if we are interrupted so we can break out if (Thread.currentThread().isInterrupted()) { throw new GenericFileOperationFailedException("Interrupted during connecting", new InterruptedException("Interrupted during connecting")); diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpSoTimeoutTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpSoTimeoutTest.java new file mode 100644 index 0000000..d6313be --- /dev/null +++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpSoTimeoutTest.java @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.remote; + +import java.net.ServerSocket; + +import org.apache.camel.CamelExecutionException; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.commons.net.ftp.FTPClient; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Test class used to demonstrate the problematic disconnect sequence of the {@link FtpOperations}. + * <p> + * Setting the logging level of {@code org.apache.camel.file.remote} to {@code TRACE} will provide useful information + * + * @author l.chiarello + * + */ +public class FtpSoTimeoutTest extends CamelTestSupport { + + private ServerSocket serverSocket; + + // --- Set up + + @Override + @Before + public void setUp() throws Exception { + // the created server socket makes it possible for the FTP client to establish the socket connection. + // However, no message will ever be sent back, thus a read timeout should occur within FTPClient#__getReply() + serverSocket = new ServerSocket(0); + super.setUp(); + } + + @Override + @After + public void tearDown() throws Exception { + super.tearDown(); + if (serverSocket != null) { + serverSocket.close(); + } + } + + @Override + protected int getShutdownTimeout() { + return 5; // speedup graceful shutdown + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:with") + .to("ftp://localhost:" + serverSocket.getLocalPort() + + "?ftpClient=#myftpclient&connectTimeout=300&soTimeout=300&reconnectDelay=100"); + + from("direct:without") + .to("ftp://localhost:" + serverSocket.getLocalPort() + + "?connectTimeout=300&soTimeout=300&reconnectDelay=100"); + } + }; + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + FTPClient ftpClient = new FTPClient(); + ftpClient.setDefaultTimeout(300); + JndiRegistry registry = super.createRegistry(); + registry.bind("myftpclient", ftpClient); + return registry; + } + + // --- Tests + + @Test(timeout = 10000, expected = CamelExecutionException.class) + public void testWithDefaultTimeout() throws Exception { + // send exchange to the route using the custom FTPClient (with a default timeout) + // the soTimeout triggers in time and test is successful + template.sendBody("direct:with", ""); + } + + @Test(timeout = 10000, expected = CamelExecutionException.class) + public void testWithoutDefaultTimeout() throws Exception { + // send exchange to the route using the default FTPClient (without a default timeout) + // the soTimeout never triggers and test fails after its own timeout + template.sendBody("direct:without", ""); + } +}