diff --git a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
index bd0a24888fc94..47b87133d01ad 100644
--- a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
+++ b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
@@ -111,93 +111,95 @@ protected void processExchange(Exchange exchange, String target) throws Exceptio
log.trace("Processing file: {} for exchange: {}", target, exchange);
try {
- preWriteCheck();
-
- // should we write to a temporary name and then afterwards rename to real target
- boolean writeAsTempAndRename = ObjectHelper.isNotEmpty(endpoint.getTempFileName());
- String tempTarget = null;
- // remember if target exists to avoid checking twice
- Boolean targetExists = null;
- if (writeAsTempAndRename) {
- // compute temporary name with the temp prefix
- tempTarget = createTempFileName(exchange, target);
-
- log.trace("Writing using tempNameFile: {}", tempTarget);
-
- // cater for file exists option on the real target as
- // the file operations code will work on the temp file
-
- // if an existing file already exists what should we do?
- targetExists = operations.existsFile(target);
- if (targetExists) {
- if (endpoint.getFileExist() == GenericFileExist.Ignore) {
- // ignore but indicate that the file was written
- log.trace("An existing file already exists: {}. Ignore and do not override it.", target);
- return;
- } else if (endpoint.getFileExist() == GenericFileExist.Fail) {
- throw new GenericFileOperationFailedException("File already exist: " + target + ". Cannot write new file.");
- } else if (endpoint.isEagerDeleteTargetFile() && endpoint.getFileExist() == GenericFileExist.Override) {
- // we override the target so we do this by deleting it so the temp file can be renamed later
- // with success as the existing target file have been deleted
- log.trace("Eagerly deleting existing file: {}", target);
- if (!operations.deleteFile(target)) {
- throw new GenericFileOperationFailedException("Cannot delete file: " + target);
+ preWriteCheck(exchange);
+
+ if (isUploadFile()) {
+ // should we write to a temporary name and then afterwards rename to real target
+ boolean writeAsTempAndRename = ObjectHelper.isNotEmpty(endpoint.getTempFileName());
+ String tempTarget = null;
+ // remember if target exists to avoid checking twice
+ Boolean targetExists = null;
+ if (writeAsTempAndRename) {
+ // compute temporary name with the temp prefix
+ tempTarget = createTempFileName(exchange, target);
+
+ log.trace("Writing using tempNameFile: {}", tempTarget);
+
+ // cater for file exists option on the real target as
+ // the file operations code will work on the temp file
+
+ // if an existing file already exists what should we do?
+ targetExists = operations.existsFile(target);
+ if (targetExists) {
+ if (endpoint.getFileExist() == GenericFileExist.Ignore) {
+ // ignore but indicate that the file was written
+ log.trace("An existing file already exists: {}. Ignore and do not override it.", target);
+ return;
+ } else if (endpoint.getFileExist() == GenericFileExist.Fail) {
+ throw new GenericFileOperationFailedException("File already exist: " + target + ". Cannot write new file.");
+ } else if (endpoint.isEagerDeleteTargetFile() && endpoint.getFileExist() == GenericFileExist.Override) {
+ // we override the target so we do this by deleting it so the temp file can be renamed later
+ // with success as the existing target file have been deleted
+ log.trace("Eagerly deleting existing file: {}", target);
+ if (!operations.deleteFile(target)) {
+ throw new GenericFileOperationFailedException("Cannot delete file: " + target);
+ }
}
}
- }
- // delete any pre existing temp file
- if (operations.existsFile(tempTarget)) {
- log.trace("Deleting existing temp file: {}", tempTarget);
- if (!operations.deleteFile(tempTarget)) {
- throw new GenericFileOperationFailedException("Cannot delete file: " + tempTarget);
+ // delete any pre existing temp file
+ if (operations.existsFile(tempTarget)) {
+ log.trace("Deleting existing temp file: {}", tempTarget);
+ if (!operations.deleteFile(tempTarget)) {
+ throw new GenericFileOperationFailedException("Cannot delete file: " + tempTarget);
+ }
}
}
- }
- // write/upload the file
- writeFile(exchange, tempTarget != null ? tempTarget : target);
-
- // if we did write to a temporary name then rename it to the real
- // name after we have written the file
- if (tempTarget != null) {
-
- // if we should not eager delete the target file then do it now just before renaming
- if (!endpoint.isEagerDeleteTargetFile() && targetExists
- && endpoint.getFileExist() == GenericFileExist.Override) {
- // we override the target so we do this by deleting it so the temp file can be renamed later
- // with success as the existing target file have been deleted
- log.trace("Deleting existing file: {}", target);
- if (!operations.deleteFile(target)) {
- throw new GenericFileOperationFailedException("Cannot delete file: " + target);
+ // write/upload the file
+ writeFile(exchange, tempTarget != null ? tempTarget : target);
+
+ // if we did write to a temporary name then rename it to the real
+ // name after we have written the file
+ if (tempTarget != null) {
+
+ // if we should not eager delete the target file then do it now just before renaming
+ if (!endpoint.isEagerDeleteTargetFile() && targetExists
+ && endpoint.getFileExist() == GenericFileExist.Override) {
+ // we override the target so we do this by deleting it so the temp file can be renamed later
+ // with success as the existing target file have been deleted
+ log.trace("Deleting existing file: {}", target);
+ if (!operations.deleteFile(target)) {
+ throw new GenericFileOperationFailedException("Cannot delete file: " + target);
+ }
}
- }
- // now we are ready to rename the temp file to the target file
- log.trace("Renaming file: [{}] to: [{}]", tempTarget, target);
- boolean renamed = operations.renameFile(tempTarget, target);
- if (!renamed) {
- throw new GenericFileOperationFailedException("Cannot rename file from: " + tempTarget + " to: " + target);
+ // now we are ready to rename the temp file to the target file
+ log.trace("Renaming file: [{}] to: [{}]", tempTarget, target);
+ boolean renamed = operations.renameFile(tempTarget, target);
+ if (!renamed) {
+ throw new GenericFileOperationFailedException("Cannot rename file from: " + tempTarget + " to: " + target);
+ }
}
- }
- // any done file to write?
- if (endpoint.getDoneFileName() != null) {
- String doneFileName = endpoint.createDoneFileName(target);
- ObjectHelper.notEmpty(doneFileName, "doneFileName", endpoint);
+ // any done file to write?
+ if (endpoint.getDoneFileName() != null) {
+ String doneFileName = endpoint.createDoneFileName(target);
+ ObjectHelper.notEmpty(doneFileName, "doneFileName", endpoint);
- // create empty exchange with empty body to write as the done file
- Exchange empty = new DefaultExchange(exchange);
- empty.getIn().setBody("");
+ // create empty exchange with empty body to write as the done file
+ Exchange empty = new DefaultExchange(exchange);
+ empty.getIn().setBody("");
- log.trace("Writing done file: [{}]", doneFileName);
- // delete any existing done file
- if (operations.existsFile(doneFileName)) {
- if (!operations.deleteFile(doneFileName)) {
- throw new GenericFileOperationFailedException("Cannot delete existing done file: " + doneFileName);
+ log.trace("Writing done file: [{}]", doneFileName);
+ // delete any existing done file
+ if (operations.existsFile(doneFileName)) {
+ if (!operations.deleteFile(doneFileName)) {
+ throw new GenericFileOperationFailedException("Cannot delete existing done file: " + doneFileName);
+ }
}
+ writeFile(empty, doneFileName);
}
- writeFile(empty, doneFileName);
}
// let's store the name we really used in the header, so end-users
@@ -210,6 +212,15 @@ protected void processExchange(Exchange exchange, String target) throws Exceptio
postWriteCheck();
}
+ /**
+ * Override if required. Files are actually sent / returns true by default
+ *
+ * @return true to send files, false to skip sending files.
+ */
+ protected boolean isUploadFile() {
+ return true;
+ }
+
/**
* If we fail writing out a file, we will call this method. This hook is
* provided to disconnect from servers or clean up files we created (if needed).
@@ -221,7 +232,7 @@ public void handleFailedWrite(Exchange exchange, Exception exception) throws Exc
/**
* Perform any actions that need to occur before we write such as connecting to an FTP server etc.
*/
- public void preWriteCheck() throws Exception {
+ public void preWriteCheck(Exchange exchange) throws Exception {
// nothing needed to check
}
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 4cbc4ddb32390..0522aad803e36 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
@@ -167,8 +167,13 @@ public boolean connect(RemoteFileConfiguration configuration) throws GenericFile
throw new GenericFileOperationFailedException(client.getReplyCode(), client.getReplyString(), e.getMessage(), e);
}
- // site commands
- if (endpoint.getConfiguration().getSiteCommand() != null) {
+ return true;
+ }
+
+ public void sendSiteCommands(RemoteFileConfiguration configuration, Exchange exchange) throws GenericFileOperationFailedException {
+ if (configuration.getSiteCommand() != null) {
+ final boolean captureOutput = exchange != null && configuration.isSiteCommandCapture();
+ final List siteOutput = new ArrayList();
// commands can be separated using new line
Iterator> it = ObjectHelper.createIterator(endpoint.getConfiguration().getSiteCommand(), "\n");
while (it.hasNext()) {
@@ -177,14 +182,21 @@ public boolean connect(RemoteFileConfiguration configuration) throws GenericFile
log.trace("Site command to send: {}", command);
if (command != null) {
boolean result = sendSiteCommand(command);
+
+ if (captureOutput) {
+ String reply = getFtpClient().getReplyString();
+ siteOutput.add( reply );
+ }
+
if (!result) {
throw new GenericFileOperationFailedException("Site command: " + command + " returned false");
}
}
}
+ if ( captureOutput ) {
+ exchange.getIn().setBody(siteOutput);
+ }
}
-
- return true;
}
public boolean isConnected() throws GenericFileOperationFailedException {
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java
index e5325bacfa677..89f3e3c75c3b6 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConfiguration.java
@@ -47,6 +47,7 @@ public enum PathSeparator { UNIX, Windows, Auto };
private int soTimeout;
private boolean throwExceptionOnConnectFailed;
private String siteCommand;
+ private boolean siteCommandCapture = false;
private boolean stepwise = true;
private PathSeparator separator = PathSeparator.Auto;
private boolean streamDownload;
@@ -57,7 +58,7 @@ public RemoteFileConfiguration() {
public RemoteFileConfiguration(URI uri) {
configure(uri);
}
-
+
@Override
public boolean needToNormalize() {
return false;
@@ -230,6 +231,25 @@ public void setSiteCommand(String siteCommand) {
this.siteCommand = siteCommand;
}
+ public boolean isSiteCommandCapture() {
+ return siteCommandCapture;
+ }
+
+ /**
+ * Capture the output of the site commands. The output of the site commands will be returned
+ * in the exchange's body as a List with the output of each executed site command
+ * as a list element in order of execution. The order of execution is defined by the order
+ * of the site commands in the siteCommand option (each separated by a newline character).
+ * If false, the body remains untouched.
+ *
+ * The default is false.
+ *
+ * @param siteCommandCapture if true, capture site command output.
+ */
+ public void setSiteCommandCapture(boolean siteCommandCapture) {
+ this.siteCommandCapture = siteCommandCapture;
+ }
+
public boolean isStepwise() {
return stepwise;
}
@@ -261,7 +281,7 @@ public PathSeparator getSeparator() {
public void setSeparator(PathSeparator separator) {
this.separator = separator;
}
-
+
public boolean isStreamDownload() {
return streamDownload;
}
@@ -271,7 +291,7 @@ public boolean isStreamDownload() {
* the remote files are streamed to the route as they are read. When set to false, the remote files
* are loaded into memory before being sent into the route.
*
- * @param streamDownload
+ * @param streamDownload
*/
public void setStreamDownload(boolean streamDownload) {
this.streamDownload = streamDownload;
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
index e347c7dcc1f68..0669ccccd2053 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
@@ -55,6 +55,7 @@ protected boolean prePollCheck() throws Exception {
} else {
connectIfNecessary();
}
+ getOperations().sendSiteCommands( getEndpoint().getConfiguration(), null );
} catch (Exception e) {
loggedIn = false;
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java
index 1951143ad36bf..895573ef55238 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileEndpoint.java
@@ -38,6 +38,7 @@ public abstract class RemoteFileEndpoint extends GenericFileEndpoint {
private boolean disconnect;
private boolean fastExistsCheck;
private boolean download = true;
+ private boolean upload = true;
public RemoteFileEndpoint() {
// no args constructor for spring bean endpoint configuration
@@ -208,4 +209,12 @@ public boolean isDownload() {
public void setDownload(boolean download) {
this.download = download;
}
+
+ public boolean isUpload() {
+ return this.upload;
+ }
+
+ public void setUpload(boolean upload) {
+ this.upload = upload;
+ }
}
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileOperations.java
index 55573cbe48232..116a402348a25 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileOperations.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileOperations.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.component.file.remote;
+import org.apache.camel.Exchange;
import org.apache.camel.component.file.GenericFileOperationFailedException;
import org.apache.camel.component.file.GenericFileOperations;
@@ -65,4 +66,17 @@ public interface RemoteFileOperations extends GenericFileOperations {
*/
boolean sendSiteCommand(String command) throws GenericFileOperationFailedException;
+ /**
+ * Sends the site commands to the remote server which are specified in the
+ * configuration option siteCommand. If option siteCommandCapture is true,
+ * the output of each site command will be captured and returned as a List
+ * in the body.
+ *
+ * Works with the producer only.
+ *
+ * @param configuration the configuration
+ * @param exchange the exchange; if null, output will not be captured
+ * @throws GenericFileOperationFailedException can be thrown
+ */
+ void sendSiteCommands(RemoteFileConfiguration configuration, Exchange exchange) throws GenericFileOperationFailedException;
}
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileProducer.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileProducer.java
index 87882aad16949..00bca04b28837 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileProducer.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileProducer.java
@@ -89,7 +89,7 @@ public void disconnect() throws GenericFileOperationFailedException {
}
@Override
- public void preWriteCheck() throws Exception {
+ public void preWriteCheck(Exchange exchange) throws Exception {
// before writing send a noop to see if the connection is alive and works
boolean noop = false;
if (loggedIn) {
@@ -114,6 +114,7 @@ public void preWriteCheck() throws Exception {
} else {
connectIfNecessary();
}
+ getOperations().sendSiteCommands(getEndpoint().getConfiguration(), exchange);
} catch (Exception e) {
loggedIn = false;
@@ -136,6 +137,11 @@ public void postWriteCheck() {
}
}
+ @Override
+ protected boolean isUploadFile() {
+ return getEndpoint().isUpload();
+ }
+
@Override
protected void doStart() throws Exception {
log.debug("Starting");
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
index 68da99e7a8da1..60460356404a4 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java
@@ -867,4 +867,9 @@ public boolean sendSiteCommand(String command) throws GenericFileOperationFailed
// is not implemented
return true;
}
+
+ @Override
+ public void sendSiteCommands(RemoteFileConfiguration configuration, Exchange exchange) throws GenericFileOperationFailedException {
+ // is not implemented
+ }
}
diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerSiteCommandTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerSiteCommandTest.java
index 064e2c2e8b793..be100881f1745 100644
--- a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerSiteCommandTest.java
+++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerSiteCommandTest.java
@@ -17,19 +17,61 @@
package org.apache.camel.component.file.remote;
import java.io.File;
+import java.util.List;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.converter.IOConverter;
import org.junit.Test;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.startsWith;
+
public class FtpProducerSiteCommandTest extends FtpServerTestSupport {
+ private String getFtpUrl() {
+ return "ftp://admin@localhost:" + getPort() + "/site?password=admin&siteCommand=help site";
+ }
+
@Override
- public boolean isUseRouteBuilder() {
- return false;
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:callSiteCommandWithoutUpload")
+ .to("ftp://admin@localhost:" + getPort() + "/site?password=admin&siteCommand=STAT&upload=false");
+
+ from("direct:callSiteCommandAndCaptureOutput")
+ .inOut("ftp://admin@localhost:" + getPort() + "/site?password=admin&siteCommand=STAT&upload=false&siteCommandCapture=true");
+
+ from("direct:callTwoSiteCommands")
+ .inOut("ftp://admin@localhost:" + getPort() + "/site?password=admin&siteCommand=STAT%0AZONE&upload=false&siteCommandCapture=true");
+ }
+ };
}
- private String getFtpUrl() {
- return "ftp://admin@localhost:" + getPort() + "/site?password=admin&siteCommand=help site";
+ @Test
+ public void testSiteCommandWithoutUploadingFile() throws Exception {
+ template.sendBodyAndHeader("direct:callSiteCommandWithoutUpload", "Hello world", Exchange.FILE_NAME, "hello.txt");
+
+ File file = new File(FTP_ROOT_DIR + "/site/hello.txt");
+ assertFalse("No file should be uploaded", file.exists());
+ }
+
+ @Test
+ public void testCaptureSiteCommandOutput() throws Exception {
+ List output = template.requestBody("direct:callSiteCommandAndCaptureOutput", null, List.class);
+
+ assertThat("Body should contain one line of site command output", output.size(), is(1));
+ assertThat("Site command output should start with response code 200", output.get(0), startsWith("200"));
+ }
+
+ @Test
+ public void testCallsTwoSiteCommands() throws Exception {
+ List output = template.requestBody("direct:callTwoSiteCommands", null, List.class);
+ System.out.println(output.get(0));
+ System.out.println(output.get(1));
+ assertThat("Body should contain one line of site command output", output.size(), is(2));
}
@Test
@@ -37,8 +79,7 @@ public void testSiteCommand() throws Exception {
sendFile(getFtpUrl(), "Hello World", "hello.txt");
File file = new File(FTP_ROOT_DIR + "/site/hello.txt");
- assertTrue("The uploaded file should exists", file.exists());
+ assertTrue("The uploaded file should exist", file.exists());
assertEquals("Hello World", IOConverter.toString(file, null));
}
-
}
\ No newline at end of file
diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpServerTestSupport.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpServerTestSupport.java
index 7df7a9296b1e1..7c695507f91df 100644
--- a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpServerTestSupport.java
+++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpServerTestSupport.java
@@ -38,7 +38,7 @@
public abstract class FtpServerTestSupport extends BaseServerTestSupport {
protected static final String FTP_ROOT_DIR = "./target/res/home";
- protected static final File USERS_FILE = new File("./src/test/resources/users.properties");
+ protected static final File USERS_FILE = new File(FtpServerTestSupport.class.getResource( "/users.properties" ).getFile());
protected static final String DEFAULT_LISTENER = "default";
protected FtpServer ftpServer;
diff --git a/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java b/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
index 4bea7fb2988c2..32ae1fcd686b5 100644
--- a/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
+++ b/components/camel-jsch/src/main/java/org/apache/camel/component/jsch/ScpOperations.java
@@ -212,7 +212,12 @@ public boolean sendSiteCommand(String command) throws GenericFileOperationFailed
// TODO: not really used, maybe implement at a later time
return true;
}
-
+
+ @Override
+ public void sendSiteCommands(RemoteFileConfiguration configuration, Exchange exchange) throws GenericFileOperationFailedException {
+ // TODO: not really used, maybe implement at a later time
+ }
+
private Session createSession(ScpConfiguration config) {
ObjectHelper.notNull(config, "ScpConfiguration");
try {