diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 24865a5..a86292f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -33,9 +33,15 @@ jobs:
- name: Install and start SFTP
run: |
sudo apt install openssh-server
+ sudo sh -c 'echo "ChallengeResponseAuthentication no" >> /etc/ssh/sshd_config'
+ sudo sh -c 'echo "PasswordAuthentication no" >> /etc/ssh/sshd_config'
+ sudo sh -c 'echo "\nMatch User usr" >> /etc/ssh/sshd_config'
+ sudo sh -c 'echo "\tPasswordAuthentication yes" >> /etc/ssh/sshd_config'
+ sudo sh -c 'echo "\nMatch User All" >> /etc/ssh/sshd_config'
+ sudo sh -c 'echo "\tPasswordAuthentication no" >> /etc/ssh/sshd_config'
sudo systemctl enable ssh
sudo systemctl start ssh
-
+
- name: Create a test user account
run: |
sshGroupRaw=$(getent group | grep ssh)
@@ -43,6 +49,21 @@ jobs:
echo "adding user to group ${sshGroup}"
sudo useradd -s /bin/bash -d /home/usr -m -g ${sshGroup} -p $(echo pwd | openssl passwd -1 -stdin) usr
+ echo "adding user2ssh to group ${sshGroup}"
+ sudo useradd -s /bin/bash -d /home/usr2ssh -m -g ${sshGroup} -p $(echo pwd | openssl passwd -1 -stdin) usr2ssh
+
+ ssh-keygen -t rsa -b 4096 -N "123456" -f ~/.ssh/sftptest
+ chmod -R 700 ~/.ssh/sftptest
+ chmod 600 ~/.ssh/sftptest.pub
+
+ sudo -u usr2ssh mkdir /home/usr2ssh/.ssh/
+ sudo cat ~/.ssh/sftptest.pub >> /home/usr2ssh/.ssh/authorized_keys
+ sudo chown -R usr2ssh:${sshGroup} /home/usr2ssh/.ssh
+ sudo chmod go-w /home/usr2ssh
+ sudo chmod -R 700 /home/usr2ssh/.ssh
+ sudo chmod 600 /home/usr2ssh/.ssh/authorized_keys
+ cp ~/.ssh/sftptest ${GITHUB_WORKSPACE}/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/sftptest
+
- name: Setup Maven
uses: stCarolas/setup-maven@v5
with:
@@ -50,7 +71,7 @@ jobs:
- name: Build with Maven
run: mvn clean verify --batch-mode --fail-at-end ${{ inputs.mvnArgs }}
-
+
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
@@ -58,7 +79,7 @@ jobs:
junit_files: |
*/target/*-reports/*.xml
!*/target/*-reports/failsafe-summary.xml
-
+
- name: Archive build artifact
uses: actions/upload-artifact@v4
with:
diff --git a/sftp-connector-demo/config/variables.yaml b/sftp-connector-demo/config/variables.yaml
index 6ff84af..ea1d9c0 100644
--- a/sftp-connector-demo/config/variables.yaml
+++ b/sftp-connector-demo/config/variables.yaml
@@ -5,4 +5,27 @@
# please add a 'variables.yaml' in the sub directory '_'.
#
Variables:
- #myVariable: value
\ No newline at end of file
+ com.axonivy.connector.sftp.server:
+ dummy:
+ # The host name to the SFTP server
+ host: 'localhost'
+
+ # The port number to the SFTP server
+ port: 22
+
+ # The username to the SFTP server
+ username: 'usr'
+
+ # Auth type to the SFPT server
+ # [enum: password, ssh]
+ auth: 'ssh'
+
+ # The password to the SFTP server
+ # [password]
+ password: ''
+
+ # The path of ssh key file to SFTP server
+ sshkeyFilePath: 'C:\NonInstall\RebexTinySftpServer-Binaries-Latest\sshkeyBK\rsa4096new'
+
+ # The ssh key passphrase
+ sshPassphraseSecret: '123456'
\ No newline at end of file
diff --git a/sftp-connector-demo/src/com/axonivy/connector/sftp/demo/Constants.java b/sftp-connector-demo/src/com/axonivy/connector/sftp/demo/Constants.java
new file mode 100644
index 0000000..96ea47a
--- /dev/null
+++ b/sftp-connector-demo/src/com/axonivy/connector/sftp/demo/Constants.java
@@ -0,0 +1,6 @@
+package com.axonivy.connector.sftp.demo;
+
+public class Constants {
+ public static final String TEST_SFTP_SERVER_NAME = "dummy";
+
+}
diff --git a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemo.xhtml b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemo.xhtml
index fbb94ab..95e2089 100644
--- a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemo.xhtml
+++ b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemo.xhtml
@@ -31,7 +31,7 @@
+ listener="#{logic.handleFileUpload}" />
diff --git a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoData.ivyClass b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoData.ivyClass
index 7936602..6015ef3 100644
--- a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoData.ivyClass
+++ b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoData.ivyClass
@@ -1,5 +1,7 @@
SftpClientDemoData #class
com.axonivy.connector.sftp.demo.SftpClientDemo #namespace
+sftpServerName String #field
+sftpServerName PERSISTENT #fieldModifier
clientHost String #field
clientHost PERSISTENT #fieldModifier
clientPort Number #field
diff --git a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoProcess.p.json b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoProcess.p.json
index 945e2ed..9eb1297 100644
--- a/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoProcess.p.json
+++ b/sftp-connector-demo/src_hd/com/axonivy/connector/sftp/demo/SftpClientDemo/SftpClientDemoProcess.p.json
@@ -31,10 +31,13 @@
"config" : {
"output" : {
"code" : [
- "String prefix = \"com_axonivy_connector_sftp_server_\";",
- "in.clientHost = ivy.var.variable(prefix+\"host\").value();",
- "in.clientPort = Integer.parseInt(ivy.var.variable(prefix+\"port\").value());",
- "in.clientUsername = ivy.var.variable(prefix+\"username\").value();"
+ "import com.axonivy.connector.sftp.service.SftpClientService;",
+ "import com.axonivy.connector.sftp.demo.Constants;",
+ "",
+ "in.sftpServerName = Constants.TEST_SFTP_SERVER_NAME;",
+ "in.clientHost = SftpClientService.getClientHost(in.sftpServerName);",
+ "in.clientPort = Integer.parseInt(SftpClientService.getPort(in.sftpServerName));",
+ "in.clientUsername = SftpClientService.getUsername(in.sftpServerName);"
]
}
},
@@ -77,7 +80,7 @@
"type" : "SubProcessCall",
"name" : "Sftp/SftpUploadFile",
"config" : {
- "processCall" : "Sftp/SftpUploadFile:uploadFile(java.io.InputStream,String)",
+ "processCall" : "Sftp/SftpUploadFile:uploadFile(String,java.io.InputStream,String)",
"output" : {
"map" : {
"out" : "in",
@@ -86,10 +89,12 @@
},
"call" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "fileToBeUploaded", "type" : "java.io.InputStream" },
{ "name" : "fileName", "type" : "String" }
],
"map" : {
+ "param.sftpName" : "in.sftpServerName",
"param.fileToBeUploaded" : "in.uploadedFile.getInputStream()",
"param.fileName" : "in.uploadedFile.getFileName()"
}
@@ -111,7 +116,7 @@
"type" : "SubProcessCall",
"name" : "Sftp/SftpDownloadFile",
"config" : {
- "processCall" : "Sftp/SftpDownloadFile:downloadFile(String)",
+ "processCall" : "Sftp/SftpDownloadFile:downloadFile(String,String)",
"output" : {
"map" : {
"out" : "in",
@@ -120,9 +125,11 @@
},
"call" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "remoteFileName", "type" : "String" }
],
"map" : {
+ "param.sftpName" : "in.sftpServerName",
"param.remoteFileName" : "in.fileToDownload.name"
}
}
@@ -191,7 +198,7 @@
"type" : "SubProcessCall",
"name" : "call list All Files",
"config" : {
- "processCall" : "Sftp/SftpDownloadFile:listAllFiles(String)",
+ "processCall" : "Sftp/SftpDownloadFile:listAllFiles(String,String)",
"output" : {
"map" : {
"out" : "in",
@@ -200,9 +207,11 @@
},
"call" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "remoteDirectory", "type" : "String" }
],
"map" : {
+ "param.sftpName" : "in.sftpServerName",
"param.remoteDirectory" : "\".\""
}
}
diff --git a/sftp-connector-product/README.md b/sftp-connector-product/README.md
index 4caf2be..93f1eb4 100644
--- a/sftp-connector-product/README.md
+++ b/sftp-connector-product/README.md
@@ -53,28 +53,64 @@ Before starting the demo, please make sure to have an SSH/SFTP server on your co
1. Open the following settings in “RebexTinySftpServer.exe.config” with a text editor and update the following values:
![RebexTinySftpServer.exe.config](images/RebexTinySftpServer.exe.config.png)
-2. Open the `configuration/variables.yaml` in your Designer and update the following global variables:
+ \* In order to test the connector with SSH key pair, put the public key file to folder `c:/sshkey`.
+2. Configure one or more SFTP connectors in global variables. A SFTP connector is identified by a name and a global variable section containing access information. The following example shows connection information for a SFTP connector that should be accessible under the name local-rebex.
+Put this variable block into your project. At least `host`, `auth`, `username` and `password` must be defined.
```
Variables:
com.axonivy.connector.sftp.server:
- # The host name to the SFTP server
- host: 'localhost'
+ local-rebex:
+ # The host name to the SFTP server
+ host: 'localhost'
+
+ # Auth type to the SFPT server: password OR ssh
+ auth: 'password'
+
+ # The password to the SFTP server
+ password: pwd
+
+ # The port number to the SFTP server
+ port: 22
+
+ # The username to the SFTP server
+ username: 'usr'
- # The password to the SFTP server
- password: pwd
-
- # The port number to the SFTP server
- port: 22
+ ```
- # The username to the SFTP server
- username: 'usr'
+ Or in order to enable the connector with SSH keypair, `secret.sshkey` and `secret.sshpassphrase` must be defined:
+ ```
+
+ Variables:
+ com.axonivy.connector.sftp.server:
+ local-rebex:
+ # The host name to the SFTP server
+ host: 'localhost'
+
+ # Auth type to the SFPT server: password OR ssh
+ auth: 'ssh'
+
+ # The password to the SFTP server
+ password: ''
+
+ # The port number to the SFTP server
+ port: 22
+
+ # The username to the SFTP server
+ username: 'usr'
+
+ # The path of ssh key file to SFTP server
+ sshkeyFilePath: 'path/to/file'
+
+ # The ssh key passphrase
+ sshPassphraseSecret: 'Your ssh key passphrase'
```
+ \* the private key is in pair of the public key put in step 1
-4. Save the changed settings.
+3. Save the changed settings.
### Prerequisites:
diff --git a/sftp-connector-product/images/RebexTinySftpServer.exe.config.png b/sftp-connector-product/images/RebexTinySftpServer.exe.config.png
index 16dddd8..f54c67e 100644
Binary files a/sftp-connector-product/images/RebexTinySftpServer.exe.config.png and b/sftp-connector-product/images/RebexTinySftpServer.exe.config.png differ
diff --git a/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/BaseTest.java b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/BaseTest.java
new file mode 100644
index 0000000..0d93917
--- /dev/null
+++ b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/BaseTest.java
@@ -0,0 +1,34 @@
+package com.axonivy.connector.sftp.test;
+
+import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess;
+import ch.ivyteam.ivy.environment.Ivy;
+import ch.ivyteam.ivy.environment.IvyTest;
+
+@IvyTest
+public class BaseTest {
+ protected static final String TEST_SFTP_SERVER_NAME = "dummy";
+ protected static final String TEST_SFTP_SSH_SERVER_NAME = "dummy_ssh";
+
+ protected static final BpmProcess TEST_HELPER_PROCESS = BpmProcess.path("Sftp/SftpHelper");
+ protected static final BpmProcess TEST_UPLOAD_FILE_PROCESS = BpmProcess.path("Sftp/SftpUploadFile");
+ protected static final BpmProcess TEST_DOWNLOAD_FILE_PROCESS = BpmProcess.path("Sftp/SftpDownloadFile");
+
+ protected static final String PREFIX = "com.axonivy.connector.sftp.server";
+ protected static final String TEST_FILE_NAME = "market_market_connector_sftp.pdf";
+ protected static final long TEST_FILE_SIZE = 207569L;
+
+ protected static void setVarForSFTPName(String sftpServerName, String username, String auth, String password, String sshKeyFilePath, String sshpassphrase) {
+ setVar(sftpServerName, "host", "localhost");
+ setVar(sftpServerName, "username", username);
+ setVar(sftpServerName, "port", "22");
+ setVar(sftpServerName, "auth", auth);
+ setVar(sftpServerName, "password", password);
+ setVar(sftpServerName, "sshkeyFilePath", sshKeyFilePath);
+ setVar(sftpServerName, "sshPassphraseSecret", sshpassphrase);
+ }
+
+ private static void setVar(String sftpServerName, String var, String value) {
+ Ivy.var().set(String.format("%s.%s.%s", PREFIX, sftpServerName, var), value);
+ }
+
+}
diff --git a/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpMultiConnectionTest.java b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpMultiConnectionTest.java
new file mode 100644
index 0000000..45cfdb0
--- /dev/null
+++ b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpMultiConnectionTest.java
@@ -0,0 +1,42 @@
+package com.axonivy.connector.sftp.test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.axonivy.connector.sftp.service.SftpClientService;
+
+import ch.ivyteam.ivy.bpm.engine.client.BpmClient;
+import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest;
+
+
+/**
+ * This SftpMultiConnectionTest creates 2 sFTP connections
+ */
+@IvyProcessTest(enableWebServer = true)
+public class SftpMultiConnectionTest extends BaseTest {
+
+ private static final String SFTP_NAME = "dummy";
+ private static final String SFTP_SSH_NAME = "dummy_ssh";
+
+ @BeforeEach
+ public void preInit() throws Exception {
+ setVarForSFTPName(TEST_SFTP_SERVER_NAME, "usr", "password", "pwd", "", "");
+ String keyPath = SftpProcessSSHTest.class.getResource("sftptest").getPath();
+ setVarForSFTPName(TEST_SFTP_SSH_SERVER_NAME, "usr2ssh", "ssh", "", keyPath, "123456");
+ }
+
+ @Test
+ public void callOpenConnection(BpmClient bpmClient) throws IOException {
+ SftpClientService sftpClient = new SftpClientService(SFTP_NAME);
+ SftpClientService sftpSSHClient = new SftpClientService(SFTP_SSH_NAME);
+
+ assertThat(sftpClient).isNotNull();
+ assertThat(sftpSSHClient).isNotNull();
+ sftpClient.close();
+ sftpSSHClient.close();
+ }
+}
diff --git a/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessSSHTest.java b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessSSHTest.java
new file mode 100644
index 0000000..eb8a4b8
--- /dev/null
+++ b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessSSHTest.java
@@ -0,0 +1,130 @@
+package com.axonivy.connector.sftp.test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+
+import com.axonivy.connector.sftp.service.SftpClientService;
+import com.axonivy.connector.sftp.service.SftpClientService.FileData;
+
+import ch.ivyteam.ivy.bpm.engine.client.BpmClient;
+import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement;
+import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess;
+import ch.ivyteam.ivy.bpm.engine.client.sub.SubProcessCallResult;
+import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest;
+import ch.ivyteam.ivy.scripting.objects.File;
+
+
+/**
+ * This SftpProcessTest simulates SFTP operations by calling the sub processes:
+ * SftpUploadFile and SftpDownloadFile.
+ *
+ * The test can either be run
+ * - in the Designer IDE (
right click > run as > JUnit Test
)
+ * - or in a Maven continuous integration build pipeline (
mvn clean verify
)
+ *
+ *
+ * Detailed guidance on writing these kind of tests can be found in our
+ * Process Testing docs
+ *
+ */
+@IvyProcessTest(enableWebServer = true)
+public class SftpProcessSSHTest extends BaseTest {
+
+ @BeforeAll
+ public static void init() throws Exception {
+ String keyPath = SftpProcessSSHTest.class.getResource("sftptest").getPath();
+ setVarForSFTPName(TEST_SFTP_SSH_SERVER_NAME, "usr2ssh", "ssh", "", keyPath, "123456");
+ }
+
+ @Test
+ @Order(1)
+ public void callOpenConnection(BpmClient bpmClient) throws Exception {
+ BpmElement startable = TEST_HELPER_PROCESS.elementName("openConnection(String)");
+
+ SubProcessCallResult result = bpmClient.start()
+ .subProcess(startable)
+ .execute(TEST_SFTP_SSH_SERVER_NAME) // Callable sub process input arguments
+ .subResult();
+
+ SftpClientService sftpClient = result.param("sftpClient", SftpClientService.class);
+ assertThat(sftpClient).isNotNull();
+ if (sftpClient != null) {
+ sftpClient.close();
+ }
+ }
+
+ @Test
+ @Order(2)
+ public void callUploadFile(BpmClient bpmClient) {
+ InputStream fileToBeUploaded = getClass().getResourceAsStream(TEST_FILE_NAME);
+
+ BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(String,InputStream,String)");
+
+ SubProcessCallResult result = bpmClient.start()
+ .subProcess(startable)
+ .execute(TEST_SFTP_SSH_SERVER_NAME,fileToBeUploaded, TEST_FILE_NAME) // Callable sub process input arguments
+ .subResult();
+
+ Boolean isSuccess = result.param("isSuccess", Boolean.class);
+ assertThat(isSuccess).isTrue();
+ }
+
+ @Test
+ @Order(3)
+ public void callUploadIvyFile(BpmClient bpmClient) throws IOException {
+ InputStream fileToBeUploaded = getClass().getResourceAsStream(TEST_FILE_NAME);
+ java.io.File javaFile = new java.io.File(TEST_FILE_NAME);
+ FileUtils.copyInputStreamToFile(fileToBeUploaded, javaFile);
+
+ File ivyFile = new File(TEST_FILE_NAME, true);
+ FileUtils.moveFile(javaFile, ivyFile.getJavaFile());
+
+ BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(String,File)");
+
+ SubProcessCallResult result = bpmClient.start()
+ .subProcess(startable)
+ .execute(TEST_SFTP_SSH_SERVER_NAME, ivyFile) // Callable sub process input arguments
+ .subResult();
+
+ Boolean isSuccess = result.param("isSuccess", Boolean.class);
+ assertThat(isSuccess).isTrue();
+ }
+
+ @Test
+ @Order(4)
+ public void callListAllFiles(BpmClient bpmClient) {
+ BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("listAllFiles(String,String)");
+
+ SubProcessCallResult result = bpmClient.start()
+ .subProcess(startable)
+ .execute(TEST_SFTP_SSH_SERVER_NAME, ".") // Callable sub process input arguments
+ .subResult();
+ List listFiles = result.param("listFiles", List.class);
+ assertThat(listFiles.size()).isGreaterThanOrEqualTo(1);
+ assertThat(listFiles).anyMatch(f -> f.getName().equals(TEST_FILE_NAME));
+ }
+
+ @Test
+ @Order(5)
+ public void callDownloadFile(BpmClient bpmClient) {
+ BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("downloadFile(String,String)");
+
+ SubProcessCallResult result = bpmClient.start()
+ .subProcess(startable)
+ .execute(TEST_SFTP_SSH_SERVER_NAME, TEST_FILE_NAME) // Callable sub process input arguments
+ .subResult();
+ java.io.File downloadedFile = result.param("toFile", java.io.File.class);
+ assertThat(downloadedFile.length()).isEqualTo(TEST_FILE_SIZE);
+ assertThat(downloadedFile.getName()).isEqualTo(TEST_FILE_NAME);
+ }
+}
diff --git a/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessTest.java b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessTest.java
index e486466..c707cab 100644
--- a/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessTest.java
+++ b/sftp-connector-test/src_test/com/axonivy/connector/sftp/test/SftpProcessTest.java
@@ -7,6 +7,7 @@
import java.util.List;
import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
@@ -15,7 +16,6 @@
import ch.ivyteam.ivy.bpm.engine.client.BpmClient;
import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement;
-import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess;
import ch.ivyteam.ivy.bpm.engine.client.sub.SubProcessCallResult;
import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest;
import ch.ivyteam.ivy.scripting.objects.File;
@@ -35,24 +35,21 @@
*
*/
@IvyProcessTest(enableWebServer = true)
-public class SftpProcessTest {
-
- private static final BpmProcess TEST_HELPER_PROCESS = BpmProcess.path("Sftp/SftpHelper");
- private static final BpmProcess TEST_UPLOAD_FILE_PROCESS = BpmProcess.path("Sftp/SftpUploadFile");
- private static final BpmProcess TEST_DOWNLOAD_FILE_PROCESS = BpmProcess.path("Sftp/SftpDownloadFile");
-
- private static final String TEST_FILE_NAME = "market_market_connector_sftp.pdf";
- private static final long TEST_FILE_SIZE = 207569L;
+public class SftpProcessTest extends BaseTest {
+
+ @BeforeEach
+ public void preInit() throws Exception {
+ setVarForSFTPName(TEST_SFTP_SERVER_NAME, "usr", "password", "pwd", "", "");
+ }
-
@Test
@Order(1)
public void callOpenConnection(BpmClient bpmClient) {
- BpmElement startable = TEST_HELPER_PROCESS.elementName("openConnection()");
+ BpmElement startable = TEST_HELPER_PROCESS.elementName("openConnection(String)");
SubProcessCallResult result = bpmClient.start()
.subProcess(startable)
- .execute() // Callable sub process input arguments
+ .execute(TEST_SFTP_SERVER_NAME) // Callable sub process input arguments
.subResult();
SftpClientService sftpClient = result.param("sftpClient", SftpClientService.class);
@@ -65,11 +62,11 @@ public void callOpenConnection(BpmClient bpmClient) {
public void callUploadFile(BpmClient bpmClient) {
InputStream fileToBeUploaded = getClass().getResourceAsStream(TEST_FILE_NAME);
- BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(InputStream,String)");
+ BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(String,InputStream,String)");
SubProcessCallResult result = bpmClient.start()
.subProcess(startable)
- .execute(fileToBeUploaded, TEST_FILE_NAME) // Callable sub process input arguments
+ .execute(TEST_SFTP_SERVER_NAME, fileToBeUploaded, TEST_FILE_NAME) // Callable sub process input arguments
.subResult();
Boolean isSuccess = result.param("isSuccess", Boolean.class);
@@ -86,11 +83,11 @@ public void callUploadIvyFile(BpmClient bpmClient) throws IOException {
File ivyFile = new File(TEST_FILE_NAME, true);
FileUtils.moveFile(javaFile, ivyFile.getJavaFile());
- BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(File)");
+ BpmElement startable = TEST_UPLOAD_FILE_PROCESS.elementName("uploadFile(String,File)");
SubProcessCallResult result = bpmClient.start()
.subProcess(startable)
- .execute(ivyFile) // Callable sub process input arguments
+ .execute(TEST_SFTP_SERVER_NAME, ivyFile) // Callable sub process input arguments
.subResult();
Boolean isSuccess = result.param("isSuccess", Boolean.class);
@@ -100,11 +97,11 @@ public void callUploadIvyFile(BpmClient bpmClient) throws IOException {
@Test
@Order(4)
public void callListAllFiles(BpmClient bpmClient) {
- BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("listAllFiles(String)");
+ BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("listAllFiles(String,String)");
SubProcessCallResult result = bpmClient.start()
.subProcess(startable)
- .execute(".") // Callable sub process input arguments
+ .execute(TEST_SFTP_SERVER_NAME, ".") // Callable sub process input arguments
.subResult();
List listFiles = result.param("listFiles", List.class);
assertThat(listFiles.size()).isGreaterThanOrEqualTo(1);
@@ -114,15 +111,14 @@ public void callListAllFiles(BpmClient bpmClient) {
@Test
@Order(5)
public void callDownloadFile(BpmClient bpmClient) {
- BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("downloadFile(String)");
+ BpmElement startable = TEST_DOWNLOAD_FILE_PROCESS.elementName("downloadFile(String,String)");
SubProcessCallResult result = bpmClient.start()
.subProcess(startable)
- .execute(TEST_FILE_NAME) // Callable sub process input arguments
+ .execute(TEST_SFTP_SERVER_NAME, TEST_FILE_NAME) // Callable sub process input arguments
.subResult();
java.io.File downloadedFile = result.param("toFile", java.io.File.class);
assertThat(downloadedFile.length()).isEqualTo(TEST_FILE_SIZE);
assertThat(downloadedFile.getName()).isEqualTo(TEST_FILE_NAME);
}
-
}
diff --git a/sftp-connector/config/variables.yaml b/sftp-connector/config/variables.yaml
index 5a9221e..9d11829 100644
--- a/sftp-connector/config/variables.yaml
+++ b/sftp-connector/config/variables.yaml
@@ -1,15 +1,26 @@
Variables:
com.axonivy.connector.sftp.server:
- # The host name to the SFTP server
- host: 'localhost'
-
- # The password to the SFTP server
- # [password]
- password: pwd
-
- # The port number to the SFTP server
- port: 22
-
- # The username to the SFTP server
- username: 'usr'
+ dummy:
+ # The host name to the SFTP server
+ host: ''
+
+ # The port number to the SFTP server
+ port: 22
+
+ # The username to the SFTP server
+ username: ''
+
+ # Auth type to the SFPT server
+ # [enum: password, ssh]
+ auth: 'password'
+
+ # The password to the SFTP server
+ # [password]
+ password: ''
+
+ # The path of ssh key file to SFTP server
+ sshkeyFilePath: ''
+
+ # The ssh key passphrase
+ sshPassphraseSecret: ''
diff --git a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpDownloadFileData.ivyClass b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpDownloadFileData.ivyClass
index 21e7bfc..1dc25d7 100644
--- a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpDownloadFileData.ivyClass
+++ b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpDownloadFileData.ivyClass
@@ -5,3 +5,4 @@ toFile File #field
remoteDirectory String #field
listFiles java.util.List #field
sftpClient com.axonivy.connector.sftp.service.SftpClientService #field
+sftpName String #field
diff --git a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpHelperData.ivyClass b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpHelperData.ivyClass
index 8454560..c05f242 100644
--- a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpHelperData.ivyClass
+++ b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpHelperData.ivyClass
@@ -1,3 +1,4 @@
SftpHelperData #class
com.axonivy.connector.sftp #namespace
+sftpName String #field
sftpClient com.axonivy.connector.sftp.service.SftpClientService #field
diff --git a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpUploadFileData.ivyClass b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpUploadFileData.ivyClass
index 30d6f6c..c8db165 100644
--- a/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpUploadFileData.ivyClass
+++ b/sftp-connector/dataclasses/com/axonivy/connector/sftp/SftpUploadFileData.ivyClass
@@ -5,3 +5,4 @@ fileName String #field
sftpClient com.axonivy.connector.sftp.service.SftpClientService #field
isSuccess Boolean #field
ivyFile File #field
+sftpName String #field
diff --git a/sftp-connector/pom.xml b/sftp-connector/pom.xml
index 119c50d..6d43de1 100644
--- a/sftp-connector/pom.xml
+++ b/sftp-connector/pom.xml
@@ -11,9 +11,9 @@
- com.jcraft
+ com.github.mwiede
jsch
- 0.1.55
+ 0.2.19
diff --git a/sftp-connector/processes/Sftp/SftpDownloadFile.p.json b/sftp-connector/processes/Sftp/SftpDownloadFile.p.json
index 148fc98..6de6090 100644
--- a/sftp-connector/processes/Sftp/SftpDownloadFile.p.json
+++ b/sftp-connector/processes/Sftp/SftpDownloadFile.p.json
@@ -8,15 +8,17 @@
"elements" : [ {
"id" : "f0",
"type" : "CallSubStart",
- "name" : "downloadFile(String)",
+ "name" : "downloadFile(String,String)",
"config" : {
"callSignature" : "downloadFile",
"input" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "remoteFileName", "type" : "String" }
],
"map" : {
- "out.remoteFileName" : "param.remoteFileName"
+ "out.remoteFileName" : "param.remoteFileName",
+ "out.sftpName" : "param.sftpName"
}
},
"result" : {
@@ -99,14 +101,16 @@
}, {
"id" : "f7",
"type" : "CallSubStart",
- "name" : "listAllFiles(String)",
+ "name" : "listAllFiles(String,String)",
"config" : {
"callSignature" : "listAllFiles",
"input" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "remoteDirectory", "type" : "String" }
],
"map" : {
+ "out.sftpName" : "param.sftpName",
"out.remoteDirectory" : "param.remoteDirectory"
}
},
@@ -172,12 +176,20 @@
"type" : "SubProcessCall",
"name" : "Connect",
"config" : {
- "processCall" : "Sftp/SftpHelper:openConnection()",
+ "processCall" : "Sftp/SftpHelper:openConnection(String)",
"output" : {
"map" : {
"out" : "in",
"out.sftpClient" : "result.#sftpClient"
}
+ },
+ "call" : {
+ "params" : [
+ { "name" : "sftpName", "type" : "String" }
+ ],
+ "map" : {
+ "param.sftpName" : "in.sftpName"
+ }
}
},
"visual" : {
@@ -200,12 +212,20 @@
"type" : "SubProcessCall",
"name" : "Connect",
"config" : {
- "processCall" : "Sftp/SftpHelper:openConnection()",
+ "processCall" : "Sftp/SftpHelper:openConnection(String)",
"output" : {
"map" : {
"out" : "in",
"out.sftpClient" : "result.#sftpClient"
}
+ },
+ "call" : {
+ "params" : [
+ { "name" : "sftpName", "type" : "String" }
+ ],
+ "map" : {
+ "param.sftpName" : "in.sftpName"
+ }
}
},
"visual" : {
diff --git a/sftp-connector/processes/Sftp/SftpHelper.p.json b/sftp-connector/processes/Sftp/SftpHelper.p.json
index 20840f8..994043a 100644
--- a/sftp-connector/processes/Sftp/SftpHelper.p.json
+++ b/sftp-connector/processes/Sftp/SftpHelper.p.json
@@ -8,9 +8,17 @@
"elements" : [ {
"id" : "f0",
"type" : "CallSubStart",
- "name" : "openConnection()",
+ "name" : "openConnection(String)",
"config" : {
"callSignature" : "openConnection",
+ "input" : {
+ "params" : [
+ { "name" : "sftpName", "type" : "String", "desc" : "Name of SFtp as configured in global variables" }
+ ],
+ "map" : {
+ "out.sftpName" : "param.sftpName"
+ }
+ },
"result" : {
"params" : [
{ "name" : "sftpClient", "type" : "com.axonivy.connector.sftp.service.SftpClientService" }
@@ -41,30 +49,8 @@
"output" : {
"code" : [
"import com.axonivy.connector.sftp.service.SftpClientService;",
- "import java.lang.NumberFormatException;",
- "",
- "",
- "String prefix = \"com_axonivy_connector_sftp_server_\";",
- "",
- "String host = ivy.var.variable(prefix+\"host\").value();",
- "Integer port = 22;",
- "String portRaw = ivy.var.variable(prefix+\"port\").value();",
- "try {",
- " port = Integer.parseInt(portRaw);",
- "}",
- "catch(NumberFormatException nfe) {",
- " ivy.log.error(\"The Global Variable: com.axonivy.connector.sftp.server.port = {0} does not contain a number. The default port number: {1} will be used instead.\", ",
- " nfe, portRaw);",
- "}",
- "String username = ivy.var.variable(prefix+\"username\").value();",
- "String password = ivy.var.variable(prefix+\"password\").value();",
- "",
- "ivy.log.debug(\"The following settings will be used to connect to the SFTP server: hostname: {0}, port: {1}, username: {2}. Connection in progress...\", ",
- " host, port, username);",
- "",
- "in.sftpClient = new SftpClientService(host, port, username, password);",
"",
- "ivy.log.debug(\"Connection established.\");"
+ "in.sftpClient = new SftpClientService(in.sftpName);"
]
}
},
diff --git a/sftp-connector/processes/Sftp/SftpUploadFile.p.json b/sftp-connector/processes/Sftp/SftpUploadFile.p.json
index 5f8b618..1c63546 100644
--- a/sftp-connector/processes/Sftp/SftpUploadFile.p.json
+++ b/sftp-connector/processes/Sftp/SftpUploadFile.p.json
@@ -8,15 +8,17 @@
"elements" : [ {
"id" : "f0",
"type" : "CallSubStart",
- "name" : "uploadFile(InputStream,String)",
+ "name" : "uploadFile(String,InputStream,String)",
"config" : {
"callSignature" : "uploadFile",
"input" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "fileToBeUploaded", "type" : "java.io.InputStream" },
{ "name" : "fileName", "type" : "String" }
],
"map" : {
+ "out.sftpName" : "param.sftpName",
"out.fileName" : "param.fileName",
"out.fileToBeUploaded" : "param.fileToBeUploaded"
}
@@ -85,12 +87,20 @@
"type" : "SubProcessCall",
"name" : "Connect",
"config" : {
- "processCall" : "Sftp/SftpHelper:openConnection()",
+ "processCall" : "Sftp/SftpHelper:openConnection(String)",
"output" : {
"map" : {
"out" : "in",
"out.sftpClient" : "result.#sftpClient"
}
+ },
+ "call" : {
+ "params" : [
+ { "name" : "sftpName", "type" : "String" }
+ ],
+ "map" : {
+ "param.sftpName" : "in.sftpName"
+ }
}
},
"visual" : {
@@ -111,14 +121,16 @@
}, {
"id" : "f12",
"type" : "CallSubStart",
- "name" : "uploadFile(File)",
+ "name" : "uploadFile(String,File)",
"config" : {
"callSignature" : "uploadFile",
"input" : {
"params" : [
+ { "name" : "sftpName", "type" : "String" },
{ "name" : "file", "type" : "File" }
],
"map" : {
+ "out.sftpName" : "param.sftpName",
"out.ivyFile" : "param.file"
}
},
@@ -149,12 +161,20 @@
"type" : "SubProcessCall",
"name" : "Connect",
"config" : {
- "processCall" : "Sftp/SftpHelper:openConnection()",
+ "processCall" : "Sftp/SftpHelper:openConnection(String)",
"output" : {
"map" : {
"out" : "in",
"out.sftpClient" : "result.#sftpClient"
}
+ },
+ "call" : {
+ "params" : [
+ { "name" : "sftpName", "type" : "String" }
+ ],
+ "map" : {
+ "param.sftpName" : "in.sftpName"
+ }
}
},
"visual" : {
diff --git a/sftp-connector/src/com/axonivy/connector/sftp/enums/AuthMethod.java b/sftp-connector/src/com/axonivy/connector/sftp/enums/AuthMethod.java
new file mode 100644
index 0000000..2dde9c9
--- /dev/null
+++ b/sftp-connector/src/com/axonivy/connector/sftp/enums/AuthMethod.java
@@ -0,0 +1,10 @@
+package com.axonivy.connector.sftp.enums;
+
+/**
+ * Enumeration types of authentication method used in SFTP client
+ */
+public enum AuthMethod {
+ PASSWORD,
+ SSH,
+
+}
diff --git a/sftp-connector/src/com/axonivy/connector/sftp/service/SftpClientService.java b/sftp-connector/src/com/axonivy/connector/sftp/service/SftpClientService.java
index 775b4b0..b926ee7 100644
--- a/sftp-connector/src/com/axonivy/connector/sftp/service/SftpClientService.java
+++ b/sftp-connector/src/com/axonivy/connector/sftp/service/SftpClientService.java
@@ -5,11 +5,14 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
-import org.apache.log4j.Logger;
+import org.apache.commons.lang3.StringUtils;
+import ch.ivyteam.log.Logger;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
@@ -17,19 +20,29 @@
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
+import ch.ivyteam.ivy.environment.Ivy;
-
+import static com.axonivy.connector.sftp.enums.AuthMethod.PASSWORD;
/**
- * Service class for file transfer to/from the SFTP server.
- * The service class is used to decouple the SFTP implementation.
+ * Service class for file transfer to/from the SFTP server. The service class is
+ * used to decouple the SFTP implementation.
*/
public class SftpClientService implements AutoCloseable {
- private static final Logger LOG = Logger.getLogger(SftpClientService.class);
+ private static final Logger LOG = Ivy.log();
+
private static final String PATHSEPARATOR = "/";
private static final int SESSION_TIMEOUT = 10000;
private static final int CHANNEL_TIMEOUT = 5000;
-
-
+
+ private static final String SFTP_VAR = "com.axonivy.connector.sftp.server";
+ private static final String HOST_VAR = "host";
+ private static final String PORT_VAR = "port";
+ private static final String SECRET_SSHPASSPHRASE_VAR = "sshPassphraseSecret";
+ private static final String SSHKEY_FILEPATH_VAR = "sshkeyFilePath";
+ private static final String AUTH_VAR = "auth";
+ private static final String PASSWORD_VAR = "password";
+ private static final String USERNAME_VAR = "username";
+
/**
* A Session represents a connection to an SSH server.
*/
@@ -38,43 +51,61 @@ public class SftpClientService implements AutoCloseable {
* A Channel connected to an SFTP server (as a subsystem of the ssh server).
*/
private ChannelSftp channel;
-
-
- /**
- * Instantiates the SftpClientService object with given the host, port, username and password.
+
+ /***
*
- * @param host the host name
- * @param port the port number
- * @param username the user name
- * @param password the password
- * @throws IOException
+ * @param sftpName
+ * @throws IOException
*/
- public SftpClientService(String host, int port, String username, String password) throws IOException {
+ public SftpClientService(String sftpName) throws IOException {
+ String host = getClientHost(sftpName);
+ String portRaw = getPort(sftpName);
+ String username = getUsername(sftpName);
+ String password = getVar(sftpName, PASSWORD_VAR);
+ String auth = getVar(sftpName, AUTH_VAR);
+ String sshKeyFilePath = getVar(sftpName, SSHKEY_FILEPATH_VAR);
+ String secretSSHpassphrase = getVar(sftpName, SECRET_SSHPASSPHRASE_VAR);
+
+ int port = 22;
+ try {
+ port = Integer.parseInt(portRaw);
+ } catch (NumberFormatException nfe) {
+ LOG.error("The Global Variable: com.axonivy.connector.sftp.server.port = {0} does not contain a number. The default port number: {1} will be used instead.",
+ portRaw, port, nfe);
+ }
+ LOG.debug("The following settings will be used to connect to the SFTP server: hostname: {0}, port: {1}, username: {2}. Connection in progress...",
+ host, port, username);
try {
JSch jsch = new JSch();
-
+
session = jsch.getSession(username, host, port);
- session.setPassword(password);
-
+ if (StringUtils.isEmpty(auth) || PASSWORD.name().equalsIgnoreCase(auth)) {
+ session.setPassword(password);
+ } else {
+ byte[] sshKeyBytes = Files.readAllBytes(Paths.get(sshKeyFilePath));
+ session.setConfig("PreferredAuthentications", "publickey");
+ jsch.addIdentity(null, sshKeyBytes, null, secretSSHpassphrase.getBytes());
+ }
session.setConfig("StrictHostKeyChecking", "no");
// 10 seconds session timeout
session.connect(SESSION_TIMEOUT);
channel = (ChannelSftp) session.openChannel("sftp");
-
if (channel == null) {
close();
- throw new IOException("Error while opening the channel to SFTP session '" + host +
- "' with username '" + username + "'!");
+ throw new IOException("Error while opening the channel to SFTP session '" + host + "' with username '"
+ + username + "'!");
}
// 5 seconds timeout
channel.connect(CHANNEL_TIMEOUT);
} catch (JSchException ex) {
- throw new IOException("Error while trying to connect to SFTP server '" + host +
- "' with username '" + username + "': ", ex);
+ throw new IOException(
+ "Error while trying to connect to SFTP server '" + host + "' with username '" + username + "': ",
+ ex);
}
+ LOG.debug("Connection established.");
}
-
+
/**
* Closes the current channel and the connection to the server.
*/
@@ -85,15 +116,14 @@ public void close() {
channel.disconnect();
channel = null;
}
- }
- finally {
+ } finally {
if (session != null) {
session.disconnect();
session = null;
}
}
}
-
+
/**
* Returns the current local directory in absolute form.
*
@@ -102,7 +132,7 @@ public void close() {
public String getLocalCurrentDir() {
return channel.lpwd();
}
-
+
/**
* Creates a new remote directory.
*
@@ -112,12 +142,11 @@ public String getLocalCurrentDir() {
public void makeRemoteDir(String name) throws IOException {
try {
channel.mkdir(name);
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
* Returns the current remote directory in absolute form.
*
@@ -127,12 +156,11 @@ public void makeRemoteDir(String name) throws IOException {
public String getRemoteCurrentDir() throws IOException {
try {
return channel.pwd();
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
* Returns the File information of a single file.
*
@@ -146,7 +174,7 @@ public FileData getFileData(String remoteFilePath) {
List lsEntryList = channel.ls(remoteFilePath);
if (lsEntryList != null && !lsEntryList.isEmpty()) {
LsEntry lsEntry = lsEntryList.get(0);
-
+
fd = new FileData();
int i = remoteFilePath.lastIndexOf('/');
fd.parentPath = (i < 0) ? "" : remoteFilePath.substring(0, i);
@@ -156,14 +184,13 @@ public FileData getFileData(String remoteFilePath) {
fd.size = lsEntry.getAttrs().getSize();
fd.modificationDate = new Date(1000L * lsEntry.getAttrs().getMTime());
}
- }
- catch (SftpException ex) { // If an error occurs, null will be returned
+ } catch (SftpException ex) { // If an error occurs, null will be returned
LOG.warn("If an error occurs, null will be returned", ex);
}
-
+
return fd;
}
-
+
/**
* Returns the list of all File information of all the files in a directory.
*
@@ -185,80 +212,82 @@ public List getFileDataList(String remoteDir) {
fd.modificationDate = new Date(1000L * lsEntry.getAttrs().getMTime());
fileDataList.add(fd);
}
- }
- catch (SftpException ex) { // If an error occurs, empty list will be returned
+ } catch (SftpException ex) { // If an error occurs, empty list will be returned
LOG.warn("If an error occurs, empty list will be returned", ex);
}
return fileDataList;
}
-
+
/**
- * Uploads a file from an input stream.
- * If the file is already existing in the remote directory, it will be overwritten.
+ * Uploads a file from an input stream. If the file is already existing in the
+ * remote directory, it will be overwritten.
*
- * @param is the source file, in form of an input stream.
- * @param remoteDstFilePath the remote destination file name, relative to the current remote directory.
+ * @param is the source file, in form of an input stream.
+ * @param remoteDstFilePath the remote destination file name, relative to the
+ * current remote directory.
* @throws IOException
*/
public void uploadFile(InputStream is, String remoteDstFilePath) throws IOException {
try {
channel.put(is, remoteDstFilePath);
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
- * Uploads a file.
- * If the file is already existing in the remote directory, it will be overwritten.
+ * Uploads a file. If the file is already existing in the remote directory, it
+ * will be overwritten.
*
- * @param localSrcFilePath the local source file name, absolute or relative to the current local directory.
- * @param remoteDstFilePath the remote destination file name, absolute or relative to the current remote directory.
+ * @param localSrcFilePath the local source file name, absolute or relative to
+ * the current local directory.
+ * @param remoteDstFilePath the remote destination file name, absolute or
+ * relative to the current remote directory.
* @throws IOException
*/
public void uploadFile(String localSrcFilePath, String remoteDstFilePath) throws IOException {
try {
channel.put(localSrcFilePath, remoteDstFilePath);
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
- * Downloads a file to an OutputStream. This uses OVERWRITE mode and no progress monitor.
+ * Downloads a file to an OutputStream. This uses OVERWRITE mode and no progress
+ * monitor.
*
- * @param remoteSrcFilePath the source file name, relative to the current remote directory
- * @param oStream the Output Stream
+ * @param remoteSrcFilePath the source file name, relative to the current remote
+ * directory
+ * @param oStream the Output Stream
* @throws IOException
*/
public void downloadFile(String remoteSrcFilePath, OutputStream oStream) throws IOException {
try {
channel.get(remoteSrcFilePath, oStream);
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
- * Downloads a file.
- * If the file is already existing in the local directory, it will be overwritten.
+ * Downloads a file. If the file is already existing in the local directory, it
+ * will be overwritten.
*
- * @param remoteSrcFilePath the source file name, relative to the current remote directory.
- * @param localDstFilePath the destination file name, relative to the current local directory.
+ * @param remoteSrcFilePath the source file name, relative to the current remote
+ * directory.
+ * @param localDstFilePath the destination file name, relative to the current
+ * local directory.
* @throws IOException
*/
public void downloadFile(String remoteSrcFilePath, String localDstFilePath) throws IOException {
try {
channel.get(remoteSrcFilePath, localDstFilePath);
- }
- catch (SftpException ex) {
+ } catch (SftpException ex) {
throw new IOException(ex);
}
}
-
+
/**
* Removes one remote file or one remote directory and its content.
*
@@ -267,17 +296,16 @@ public void downloadFile(String remoteSrcFilePath, String localDstFilePath) thro
*/
public void deleteRemoteFileOrDir(String path) throws IOException {
FileData fd = getFileData(path);
- if(fd != null) {
- if(fd.isFile) {
+ if (fd != null) {
+ if (fd.isFile) {
try {
channel.rm(path); // Remove file
} catch (SftpException ex) {
throw new IOException(ex);
}
- }
- else if(fd.isDirectory) {
+ } else if (fd.isDirectory) {
List fileAndFolderList = getFileDataList(path); // List source directory structure
-
+
for (FileData item : fileAndFolderList) { // Iterate objects in the list to get file/folder names
if (item.isFile) { // If it is a file (not a directory)
try {
@@ -285,15 +313,16 @@ else if(fd.isDirectory) {
} catch (SftpException ex) {
throw new IOException(ex);
}
- }
- else if (!(".".equals(item.name) || "..".equals(item.name))) { // If it is a subdir
+ } else if (!(".".equals(item.name) || "..".equals(item.name))) { // If it is a subdir
try {
// removing sub directory.
channel.rmdir(path + "/" + item.name);
- } catch (Exception ex) { // If subdir is not empty and error occurs,
+ } catch (Exception ex) { // If subdir is not empty and error occurs,
// Do deleteRemoteFileOrDir on this subdir to enter it and clear its contents
deleteRemoteFileOrDir(path + "/" + item.name);
- LOG.warn("If subdir is not empty and error occurs, Do deleteRemoteFileOrDir on this subdir to enter it and clear its contents", ex);
+ LOG.warn(
+ "If subdir is not empty and error occurs, Do deleteRemoteFileOrDir on this subdir to enter it and clear its contents",
+ ex);
}
}
}
@@ -305,12 +334,14 @@ else if (!(".".equals(item.name) || "..".equals(item.name))) { // If it is a sub
}
}
}
-
+
/**
- * Changes the current remote directory.
- * This checks the existence and accessibility of the indicated directory, and changes the current remote directory setting.
+ * Changes the current remote directory. This checks the existence and
+ * accessibility of the indicated directory, and changes the current remote
+ * directory setting.
*
- * @param path a directory path, absolute or relative to the current remote path.
+ * @param path a directory path, absolute or relative to the current remote
+ * path.
* @throws IOException
*/
public void changeDir(String path) throws IOException {
@@ -320,31 +351,29 @@ public void changeDir(String path) throws IOException {
throw new IOException(ex);
}
}
-
+
/**
- * This method is called recursively to Upload the local folder content
- * to the SFTP server remote directory.
+ * This method is called recursively to Upload the local folder content to the
+ * SFTP server remote directory.
*
* @param sourcePath
*/
public void uploadAllFiles(String sourcePath) {
File sourceFile = new File(sourcePath);
File[] files = sourceFile.listFiles();
- for(File f : files) {
- if(f.isFile() && !f.getName().startsWith(".")) { // Copy if it is a file
+ for (File f : files) {
+ if (f.isFile() && !f.getName().startsWith(".")) { // Copy if it is a file
try {
uploadFile(new FileInputStream(f), f.getName());
} catch (IOException e) {
LOG.error("Error occured while uploading", e);
}
- }
- else {
+ } else {
// Check if the directory is already existing
FileData fileData = getFileData(f.getName());
if (fileData != null) {
LOG.debug("Directory exists IsDir=" + fileData.isDirectory);
- }
- else { // else create a directory
+ } else { // else create a directory
LOG.debug("Creating dir " + f.getName());
try {
makeRemoteDir(f.getName());
@@ -357,9 +386,9 @@ public void uploadAllFiles(String sourcePath) {
} catch (IOException e1) {
LOG.error("Error occured", e1);
}
-
+
uploadAllFiles(f.getAbsolutePath());
-
+
try {
changeDir("..");
} catch (IOException e1) {
@@ -370,8 +399,8 @@ public void uploadAllFiles(String sourcePath) {
}
/**
- * This method is called recursively to download the remote folder content
- * of the SFTP server.
+ * This method is called recursively to download the remote folder content of
+ * the SFTP server.
*
* @param sourcePath
* @param destinationPath
@@ -394,12 +423,14 @@ public void downloadAllFiles(String sourcePath, String destinationPath) {
}
}
}
-
+
/**
* Renames a file or directory.
*
- * @param oldpath the old name of the file, relative to the current remote directory.
- * @param newpath the new name of the file, relative to the current remote directory.
+ * @param oldpath the old name of the file, relative to the current remote
+ * directory.
+ * @param newpath the new name of the file, relative to the current remote
+ * directory.
* @throws IOException
*/
public void rename(String oldpath, String newpath) throws IOException {
@@ -409,8 +440,23 @@ public void rename(String oldpath, String newpath) throws IOException {
throw new IOException(ex);
}
}
+
+ private static String getVar(String store, String var) {
+ return Ivy.var().get(String.format("%s.%s.%s", SFTP_VAR, store, var));
+ }
+ public static String getClientHost(String store) {
+ return getVar(store, HOST_VAR);
+ }
+ public static String getPort(String store) {
+ return getVar(store, PORT_VAR);
+ }
+
+ public static String getUsername(String store) {
+ return getVar(store, USERNAME_VAR);
+ }
+
/**
* File information class
*
@@ -425,73 +471,84 @@ public static class FileData {
* The last modification date.
*/
Date modificationDate;
-
+
/**
* @return the isFile
*/
public boolean isFile() {
return isFile;
}
+
/**
* @param isFile the isFile to set
*/
public void setFile(boolean isFile) {
this.isFile = isFile;
}
+
/**
* @return the isDirectory
*/
public boolean isDirectory() {
return isDirectory;
}
+
/**
* @param isDirectory the isDirectory to set
*/
public void setDirectory(boolean isDirectory) {
this.isDirectory = isDirectory;
}
+
/**
* @return the parentPath
*/
public String getParentPath() {
return parentPath;
}
+
/**
* @param parentPath the parentPath to set
*/
public void setParentPath(String parentPath) {
this.parentPath = parentPath;
}
+
/**
* @return the name
*/
public String getName() {
return name;
}
+
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
+
/**
* @return the size
*/
public long getSize() {
return size;
}
+
/**
* @param size the size to set
*/
public void setSize(long size) {
this.size = size;
}
+
/**
* @return the modificationDate
*/
public Date getModificationDate() {
return modificationDate;
}
+
/**
* @param modificationDate the modificationDate to set
*/
@@ -500,4 +557,3 @@ public void setModificationDate(Date modificationDate) {
}
}
}
-