├── .gitignore ├── LICENSE ├── pom.xml └── src ├── main └── java │ └── com │ └── github │ └── sparsick │ └── ssh4j │ ├── JSchClient.java │ ├── SshClient.java │ ├── SshJClient.java │ └── VfsSftpClient.java └── test ├── java └── com │ └── github │ └── sparsick │ └── ssh4j │ ├── JSchClientIT.java │ ├── SshClientIT.java │ ├── SshJClientIT.java │ └── VfsSftpClientIT.java └── resources ├── id_rsa ├── id_rsa.pub ├── known_hosts └── test.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | /target/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Sandra Parsick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | com.github.sparsick.ssh4j 8 | comparison-ssh-java 9 | 1.0.0-SNAPSHOT 10 | 11 | SSH libraries for Java in Comparison 12 | 13 | 14 | 1.8 15 | UTF-8 16 | 17 | 18 | 19 | 20 | com.hierynomus 21 | sshj 22 | 0.12.0 23 | 24 | 25 | org.apache.commons 26 | commons-vfs2 27 | 2.0 28 | 29 | 30 | com.jcraft 31 | jsch 32 | 0.1.53 33 | 34 | 35 | junit 36 | junit 37 | 4.12 38 | test 39 | 40 | 41 | org.assertj 42 | assertj-core 43 | 3.0.0 44 | test 45 | 46 | 47 | 48 | 49 | 50 | 51 | maven-compiler-plugin 52 | 2.3.2 53 | 54 | ${java.version} 55 | ${java.version} 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/com/github/sparsick/ssh4j/JSchClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | import com.jcraft.jsch.ChannelExec; 4 | import com.jcraft.jsch.ChannelSftp; 5 | import com.jcraft.jsch.JSch; 6 | import com.jcraft.jsch.JSchException; 7 | import com.jcraft.jsch.Session; 8 | import com.jcraft.jsch.SftpException; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.io.OutputStream; 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class JSchClient implements SshClient { 18 | 19 | private String password; 20 | private String user; 21 | private Path privateKey; 22 | private Session session; 23 | private Path knownHosts; 24 | 25 | @Override 26 | public void authUserPassword(String user, String password) { 27 | this.user = user; 28 | this.password = password; 29 | } 30 | 31 | @Override 32 | public void authUserPublicKey(String user, Path privateKey) { 33 | this.user = user; 34 | this.privateKey = privateKey; 35 | } 36 | 37 | @Override 38 | public void setKnownHosts(Path knownHosts) { 39 | this.knownHosts = knownHosts; 40 | } 41 | 42 | @Override 43 | public void connect(String host) throws IOException { 44 | if (session == null) { 45 | try { 46 | JSch sshClient = new JSch(); 47 | if (privateKey != null) { 48 | sshClient.addIdentity(privateKey.toString()); 49 | } 50 | if (knownHosts != null) { 51 | sshClient.setKnownHosts(knownHosts.toString()); 52 | } else { 53 | sshClient.setKnownHosts("~/.ssh/known_hosts"); 54 | } 55 | 56 | session = sshClient.getSession(user, host); 57 | if (password != null) { 58 | session.setPassword(password); 59 | } else if (privateKey == null){ 60 | throw new IOException("Either privateKey nor password is set. Please call one of the authentication method."); 61 | } 62 | session.connect(); 63 | } catch (JSchException ex) { 64 | throw new IOException(ex); 65 | } 66 | } 67 | 68 | } 69 | 70 | @Override 71 | public void disconnect() { 72 | if (session != null) { 73 | session.disconnect(); 74 | session = null; 75 | } 76 | } 77 | 78 | @Override 79 | public void download(String remotePath, Path local) throws IOException { 80 | ChannelSftp sftpChannel = null; 81 | try { 82 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 83 | sftpChannel.connect(); 84 | InputStream inputStream = sftpChannel.get(remotePath); 85 | Files.copy(inputStream, local); 86 | } catch (SftpException | JSchException ex) { 87 | throw new IOException(ex); 88 | } finally { 89 | if (sftpChannel != null) { 90 | sftpChannel.disconnect(); 91 | 92 | } 93 | } 94 | } 95 | 96 | @Override 97 | public void upload(Path local, String remotePath) throws IOException { 98 | ChannelSftp sftpChannel = null; 99 | try { 100 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 101 | sftpChannel.connect(); 102 | OutputStream outputStream = sftpChannel.put(remotePath); 103 | Files.copy(local, outputStream); 104 | } catch (SftpException | JSchException ex) { 105 | throw new IOException(ex); 106 | } finally { 107 | if (sftpChannel != null) { 108 | sftpChannel.disconnect(); 109 | 110 | } 111 | } 112 | } 113 | 114 | @Override 115 | public void move(String oldRemotePath, String newRemotePath) throws IOException { 116 | ChannelSftp sftpChannel = null; 117 | try { 118 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 119 | sftpChannel.connect(); 120 | sftpChannel.rename(oldRemotePath, newRemotePath); 121 | } catch (SftpException | JSchException ex) { 122 | throw new IOException(ex); 123 | } finally { 124 | if (sftpChannel != null) { 125 | sftpChannel.disconnect(); 126 | 127 | } 128 | } 129 | } 130 | 131 | @Override 132 | public void copy(String oldRemotePath, String newRemotePath) throws IOException { 133 | executeCommand("cp " + oldRemotePath + " " + newRemotePath); 134 | } 135 | 136 | private void executeCommand(String command) throws IOException { 137 | ChannelExec execChannel = null; 138 | try { 139 | execChannel = (ChannelExec) session.openChannel("exec"); 140 | execChannel.connect(); 141 | execChannel.setCommand(command); 142 | execChannel.start(); 143 | } catch (JSchException ex) { 144 | throw new IOException(ex); 145 | } finally { 146 | if (execChannel != null) { 147 | execChannel.disconnect(); 148 | 149 | } 150 | } 151 | } 152 | 153 | @Override 154 | public void delete(String remotePath) throws IOException { 155 | ChannelSftp sftpChannel = null; 156 | try { 157 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 158 | sftpChannel.connect(); 159 | sftpChannel.rm(remotePath); 160 | } catch (SftpException | JSchException ex) { 161 | throw new IOException(ex); 162 | } finally { 163 | if (sftpChannel != null) { 164 | sftpChannel.disconnect(); 165 | 166 | } 167 | } 168 | } 169 | 170 | @Override 171 | public boolean fileExists(String remotePath) throws IOException { 172 | ChannelSftp sftpChannel = null; 173 | try { 174 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 175 | sftpChannel.connect(); 176 | sftpChannel.ls(remotePath); 177 | return true; 178 | } catch (JSchException ex) { 179 | throw new IOException(ex); 180 | } catch (SftpException ex) { 181 | return false; 182 | } finally { 183 | if (sftpChannel != null) { 184 | sftpChannel.disconnect(); 185 | 186 | } 187 | } 188 | } 189 | 190 | @Override 191 | public List listChildrenNames(String remotePath) throws IOException { 192 | ChannelSftp sftpChannel = null; 193 | try { 194 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 195 | sftpChannel.connect(); 196 | return sftpChannel.ls(remotePath); 197 | } catch (SftpException | JSchException ex) { 198 | throw new IOException(ex); 199 | } finally { 200 | if (sftpChannel != null) { 201 | sftpChannel.disconnect(); 202 | 203 | } 204 | } 205 | } 206 | 207 | @Override 208 | public List listChildrenFolderNames(String remotePath) throws IOException { 209 | ChannelSftp sftpChannel = null; 210 | List folderChildren = new ArrayList<>(); 211 | try { 212 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 213 | sftpChannel.connect(); 214 | sftpChannel.ls(remotePath, (ChannelSftp.LsEntry entry) -> { 215 | if (entry.getAttrs().isDir()) { 216 | folderChildren.add(entry.getFilename()); 217 | } 218 | return ChannelSftp.LsEntrySelector.CONTINUE; 219 | }); 220 | return folderChildren; 221 | } catch (SftpException | JSchException ex) { 222 | throw new IOException(ex); 223 | } finally { 224 | if (sftpChannel != null) { 225 | sftpChannel.disconnect(); 226 | 227 | } 228 | } 229 | } 230 | 231 | @Override 232 | public List listChildrenFileNames(String remotePath) throws IOException { 233 | ChannelSftp sftpChannel = null; 234 | List folderChildren = new ArrayList<>(); 235 | try { 236 | sftpChannel = (ChannelSftp) session.openChannel("sftp"); 237 | sftpChannel.connect(); 238 | sftpChannel.ls(remotePath, (ChannelSftp.LsEntry entry) -> { 239 | if (entry.getAttrs().isReg()) { 240 | folderChildren.add(entry.getFilename()); 241 | } 242 | return ChannelSftp.LsEntrySelector.CONTINUE; 243 | }); 244 | return folderChildren; 245 | } catch (SftpException | JSchException ex) { 246 | throw new IOException(ex); 247 | } finally { 248 | if (sftpChannel != null) { 249 | sftpChannel.disconnect(); 250 | 251 | } 252 | } 253 | } 254 | 255 | @Override 256 | public void execute(String command) throws IOException { 257 | executeCommand(command); 258 | } 259 | 260 | @Override 261 | public void close() throws Exception { 262 | disconnect(); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/main/java/com/github/sparsick/ssh4j/SshClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | import java.util.List; 6 | 7 | 8 | public interface SshClient extends AutoCloseable { 9 | 10 | void authUserPassword(String user, String password); 11 | 12 | void authUserPublicKey(String user, Path privateKey); 13 | 14 | void setKnownHosts(Path knownHosts); 15 | 16 | void connect(String host) throws IOException; 17 | 18 | void disconnect(); 19 | 20 | void download(String remotePath, Path local) throws IOException; 21 | 22 | void upload(Path local, String remotePath) throws IOException; 23 | 24 | void move(String oldRemotePath, String newRemotePath) throws IOException; 25 | 26 | void copy(String oldRemotePath, String newRemotePath) throws IOException; 27 | 28 | void delete(String remotePath) throws IOException; 29 | 30 | boolean fileExists(String remotePath) throws IOException ; 31 | 32 | List listChildrenNames(String remotePath) throws IOException; 33 | 34 | List listChildrenFolderNames(String remotePath) throws IOException; 35 | 36 | List listChildrenFileNames(String remotePath) throws IOException; 37 | 38 | void execute(String command) throws IOException; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/github/sparsick/ssh4j/SshJClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import net.schmizz.sshj.SSHClient; 8 | import net.schmizz.sshj.connection.channel.direct.Session; 9 | import net.schmizz.sshj.sftp.RemoteResourceFilter; 10 | import net.schmizz.sshj.sftp.RemoteResourceInfo; 11 | import net.schmizz.sshj.sftp.SFTPClient; 12 | import net.schmizz.sshj.xfer.FileSystemFile; 13 | 14 | public class SshJClient implements SshClient { 15 | 16 | private String user; 17 | private String password; 18 | private Path privateKey; 19 | private Path knownHosts; 20 | private SSHClient sshClient; 21 | 22 | @Override 23 | public void authUserPassword(String user, String password) { 24 | this.user = user; 25 | this.password = password; 26 | } 27 | 28 | @Override 29 | public void authUserPublicKey(String user, Path privateKey) { 30 | this.user = user; 31 | this.privateKey = privateKey; 32 | } 33 | 34 | @Override 35 | public void setKnownHosts(Path knownHosts) { 36 | this.knownHosts = knownHosts; 37 | } 38 | 39 | @Override 40 | public void connect(String host) throws IOException { 41 | sshClient = new SSHClient(); 42 | if (knownHosts == null) { 43 | sshClient.loadKnownHosts(); 44 | } else { 45 | sshClient.loadKnownHosts(knownHosts.toFile()); 46 | } 47 | 48 | sshClient.connect(host); 49 | 50 | if (privateKey != null) { 51 | sshClient.authPublickey(user, privateKey.toString()); 52 | } else if (password != null) { 53 | sshClient.authPassword(user, password); 54 | } else { 55 | throw new RuntimeException("Either privateKey nor password is set. Please call one of the auth method."); 56 | } 57 | } 58 | 59 | @Override 60 | public void disconnect() { 61 | try { 62 | close(); 63 | } catch (Exception ex) { 64 | // Ignore because disconnection is quietly 65 | } 66 | } 67 | 68 | @Override 69 | public void download(String remotePath, Path local) throws IOException { 70 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 71 | sftpClient.get(remotePath, new FileSystemFile(local.toFile())); 72 | } 73 | } 74 | 75 | @Override 76 | public void upload(Path local, String remotePath) throws IOException { 77 | try (SFTPClient sFTPClient = sshClient.newSFTPClient()) { 78 | sFTPClient.put(new FileSystemFile(local.toFile()), remotePath); 79 | } 80 | } 81 | 82 | @Override 83 | public void move(String oldRemotePath, String newRemotePath) throws IOException { 84 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 85 | sftpClient.rename(oldRemotePath, newRemotePath); 86 | } 87 | } 88 | 89 | @Override 90 | public void copy(String oldRemotePath, String newRemotePath) throws IOException { 91 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 92 | sftpClient.put(oldRemotePath, newRemotePath); 93 | } 94 | } 95 | 96 | @Override 97 | public void delete(String remotePath) throws IOException { 98 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 99 | sftpClient.rm(remotePath); 100 | } 101 | } 102 | 103 | @Override 104 | public boolean fileExists(String remotePath) throws IOException { 105 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 106 | return sftpClient.statExistence(remotePath) != null; 107 | } 108 | } 109 | 110 | @Override 111 | public List listChildrenNames(String remotePath) throws IOException { 112 | return listChildrenNamesByFilter(remotePath, null); 113 | } 114 | 115 | @Override 116 | public List listChildrenFolderNames(String remotePath) throws IOException { 117 | return listChildrenNamesByFilter(remotePath, RemoteResourceInfo::isDirectory); 118 | } 119 | 120 | @Override 121 | public List listChildrenFileNames(String remotePath) throws IOException { 122 | return listChildrenNamesByFilter(remotePath, RemoteResourceInfo::isRegularFile); 123 | } 124 | 125 | private List listChildrenNamesByFilter(String remotePath, RemoteResourceFilter remoteFolderResourceFilter) throws IOException { 126 | try (SFTPClient sftpClient = sshClient.newSFTPClient()) { 127 | List children = new ArrayList<>(); 128 | List childrenInfos = sftpClient.ls(remotePath, remoteFolderResourceFilter); 129 | childrenInfos.stream().forEach((childInfo) -> { 130 | children.add(childInfo.getName()); 131 | }); 132 | return children; 133 | } 134 | } 135 | 136 | @Override 137 | public void execute(String command) throws IOException { 138 | try (Session session = sshClient.startSession()) { 139 | session.exec(command); 140 | } 141 | } 142 | 143 | @Override 144 | public void close() throws Exception { 145 | sshClient.close(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/github/sparsick/ssh4j/VfsSftpClient.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.nio.file.Path; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import org.apache.commons.vfs2.AllFileSelector; 9 | import org.apache.commons.vfs2.FileObject; 10 | import org.apache.commons.vfs2.FileSystemException; 11 | import org.apache.commons.vfs2.FileSystemOptions; 12 | import org.apache.commons.vfs2.FileType; 13 | import org.apache.commons.vfs2.impl.StandardFileSystemManager; 14 | import org.apache.commons.vfs2.provider.local.LocalFile; 15 | import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; 16 | 17 | public class VfsSftpClient implements SshClient { 18 | 19 | private String password; 20 | private String user; 21 | private Path privateKey; 22 | private Path knownHosts; 23 | private StandardFileSystemManager fileSystemManager; 24 | private FileObject remoteRootDirectory; 25 | 26 | @Override 27 | public void authUserPassword(String user, String password) { 28 | this.user = user; 29 | this.password = password; 30 | } 31 | 32 | @Override 33 | public void authUserPublicKey(String user, Path privateKey) { 34 | this.user = user; 35 | this.privateKey = privateKey; 36 | } 37 | 38 | @Override 39 | public void setKnownHosts(Path knownHosts) { 40 | this.knownHosts = knownHosts; 41 | } 42 | 43 | @Override 44 | public void connect(String host) throws IOException { 45 | initFileSystemManager(); 46 | FileSystemOptions connectionOptions = buildConnectionOptions(); 47 | String connectionUrl = buildConnectionUrl(host); 48 | remoteRootDirectory = fileSystemManager.resolveFile(connectionUrl, connectionOptions); 49 | } 50 | 51 | private void initFileSystemManager() throws FileSystemException { 52 | if (fileSystemManager == null) { 53 | fileSystemManager = new StandardFileSystemManager(); 54 | fileSystemManager.init(); 55 | } 56 | } 57 | 58 | private FileSystemOptions buildConnectionOptions() throws FileSystemException { 59 | SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance(); 60 | FileSystemOptions opts = new FileSystemOptions(); 61 | sftpConfigBuilder.setUserDirIsRoot(opts, false); 62 | sftpConfigBuilder.setStrictHostKeyChecking(opts, "yes"); 63 | if (knownHosts != null) { 64 | sftpConfigBuilder.setKnownHosts(opts, knownHosts.toFile()); 65 | } else { 66 | sftpConfigBuilder.setKnownHosts(opts, new File("~/.ssh/known_hosts")); 67 | } 68 | if (privateKey != null) { 69 | sftpConfigBuilder.setIdentities(opts, new File[]{privateKey.toFile()}); 70 | } 71 | return opts; 72 | } 73 | 74 | private String buildConnectionUrl(String host) { 75 | if (privateKey != null) { 76 | return String.format("sftp://%s@%s", user, host); 77 | } else if (password != null) { 78 | return String.format("sftp://%s:%s@%s", user, password, host); 79 | } else { 80 | throw new RuntimeException("Either privateKey nor password is set. Please call one of the auth methods."); 81 | } 82 | } 83 | 84 | @Override 85 | public void disconnect() { 86 | if (fileSystemManager != null) { 87 | fileSystemManager.close(); 88 | fileSystemManager = null; 89 | } 90 | } 91 | 92 | @Override 93 | public void download(String remotePath, Path local) throws IOException { 94 | LocalFile localFileObject = (LocalFile) fileSystemManager.resolveFile(local.toUri().toString()); 95 | FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath); 96 | try { 97 | localFileObject.copyFrom(remoteFileObject, new AllFileSelector()); 98 | } finally { 99 | localFileObject.close(); 100 | remoteFileObject.close(); 101 | } 102 | 103 | } 104 | 105 | @Override 106 | public void upload(Path local, String remotePath) throws IOException { 107 | LocalFile localFileObject = (LocalFile) fileSystemManager.resolveFile(local.toUri().toString()); 108 | FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath); 109 | try { 110 | remoteFileObject.copyFrom(localFileObject, new AllFileSelector()); 111 | } finally { 112 | localFileObject.close(); 113 | remoteFileObject.close(); 114 | } 115 | } 116 | 117 | @Override 118 | public void move(String oldRemotePath, String newRemotePath) throws IOException { 119 | FileObject remoteOldFileObject = remoteRootDirectory.resolveFile(oldRemotePath); 120 | FileObject newRemoteFileObject = remoteRootDirectory.resolveFile(newRemotePath); 121 | try { 122 | remoteOldFileObject.moveTo(newRemoteFileObject); 123 | remoteOldFileObject.close(); 124 | } finally { 125 | newRemoteFileObject.close(); 126 | } 127 | } 128 | 129 | @Override 130 | public void copy(String oldRemotePath, String newRemotePath) throws IOException { 131 | FileObject newRemoteFileObject = remoteRootDirectory.resolveFile(newRemotePath); 132 | FileObject oldRemoteFileObject = remoteRootDirectory.resolveFile(oldRemotePath); 133 | try { 134 | newRemoteFileObject.copyFrom(oldRemoteFileObject, new AllFileSelector()); 135 | } finally { 136 | oldRemoteFileObject.close(); 137 | newRemoteFileObject.close(); 138 | } 139 | } 140 | 141 | @Override 142 | public void delete(String remotePath) throws IOException { 143 | FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath); 144 | try { 145 | remoteFileObject.delete(); 146 | } finally { 147 | remoteFileObject.close(); 148 | } 149 | } 150 | 151 | @Override 152 | public boolean fileExists(String remotePath) throws IOException { 153 | FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath); 154 | try { 155 | return remoteFileObject.exists(); 156 | } finally { 157 | remoteFileObject.close(); 158 | } 159 | } 160 | 161 | @Override 162 | public List listChildrenNames(String remotePath) throws IOException { 163 | return listChildrenNamesByFileType(remotePath, null); 164 | } 165 | 166 | @Override 167 | public List listChildrenFolderNames(String remotePath) throws IOException { 168 | return listChildrenNamesByFileType(remotePath, FileType.FOLDER); 169 | } 170 | 171 | @Override 172 | public List listChildrenFileNames(String remotePath) throws IOException { 173 | return listChildrenNamesByFileType(remotePath, FileType.FILE); 174 | } 175 | 176 | private List listChildrenNamesByFileType(String remotePath, FileType fileType) throws FileSystemException { 177 | FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath); 178 | try { 179 | FileObject[] fileObjectChildren = remoteFileObject.getChildren(); 180 | List childrenNames = new ArrayList<>(); 181 | for (FileObject child : fileObjectChildren) { 182 | if (fileType == null || child.getType() == fileType) { 183 | childrenNames.add(child.getName().getBaseName()); 184 | } 185 | } 186 | return childrenNames; 187 | } finally { 188 | remoteFileObject.close(); 189 | } 190 | } 191 | 192 | @Override 193 | public void execute(String command) throws IOException { 194 | throw new UnsupportedOperationException("Not supported yet."); 195 | } 196 | 197 | @Override 198 | public void close() throws Exception { 199 | disconnect(); 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /src/test/java/com/github/sparsick/ssh4j/JSchClientIT.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | 4 | public class JSchClientIT extends SshClientIT { 5 | 6 | @Override 7 | public void setUp() { 8 | clientUnderTest = new JSchClient(); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/github/sparsick/ssh4j/SshClientIT.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.FileSystems; 5 | import java.util.List; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | import java.nio.file.Path; 13 | 14 | public abstract class SshClientIT { 15 | 16 | private static final String SSH_USER = "vagrant"; 17 | private static final String SSH_HOST = "192.168.33.10"; 18 | 19 | protected SshClient clientUnderTest; 20 | 21 | @Before 22 | public abstract void setUp(); 23 | 24 | @After 25 | public void tearDown() { 26 | clientUnderTest.disconnect(); 27 | } 28 | 29 | @Test 30 | public void authUserPasswordAndConnect() throws IOException { 31 | clientUnderTest.authUserPassword(SSH_USER, "vagrant"); 32 | clientUnderTest.setKnownHosts(FileSystems.getDefault().getPath("src/test/resources/known_hosts")); 33 | clientUnderTest.connect(SSH_HOST); 34 | } 35 | 36 | @Test 37 | public void authUserPublicKeyAndConnect() throws IOException { 38 | clientUnderTest.authUserPublicKey(SSH_USER, FileSystems.getDefault().getPath("src/test/resources/id_rsa")); 39 | clientUnderTest.setKnownHosts(FileSystems.getDefault().getPath("src/test/resources/known_hosts")); 40 | clientUnderTest.connect(SSH_HOST); 41 | } 42 | 43 | @Test 44 | public void listChildrenNames() throws IOException { 45 | authUserPasswordAndConnect(); 46 | 47 | List children = clientUnderTest.listChildrenNames("/home"); 48 | assertThat(children.size()).isGreaterThan(0); 49 | } 50 | 51 | @Test 52 | public void listChildrenFolderNames() throws IOException { 53 | authUserPasswordAndConnect(); 54 | 55 | List children = clientUnderTest.listChildrenFolderNames("/home"); 56 | assertThat(children.size()).isGreaterThan(0); 57 | } 58 | 59 | @Test 60 | public void listChildrenFileNames() throws IOException { 61 | authUserPasswordAndConnect(); 62 | 63 | List children = clientUnderTest.listChildrenFileNames("/home"); 64 | assertThat(children.size()).isEqualTo(0); 65 | } 66 | 67 | @Test 68 | public void uploadAndListFile() throws IOException { 69 | authUserPasswordAndConnect(); 70 | String remoteDirPath = "/home/vagrant"; 71 | String remoteFilePath = remoteDirPath + "/test.txt"; 72 | 73 | clientUnderTest.upload(FileSystems.getDefault().getPath("src/test/resources/test.txt"), remoteFilePath); 74 | assertThat(clientUnderTest.listChildrenFileNames(remoteDirPath)).contains("test.txt"); 75 | } 76 | 77 | @Test 78 | public void uploadAndDownloadFile() throws IOException { 79 | authUserPasswordAndConnect(); 80 | String remotePath = "/home/vagrant/test1.txt"; 81 | Path localPath = FileSystems.getDefault().getPath("target/test1.txt"); 82 | 83 | clientUnderTest.upload(FileSystems.getDefault().getPath("src/test/resources/test.txt"), remotePath); 84 | clientUnderTest.download(remotePath, localPath); 85 | assertThat(localPath).exists(); 86 | } 87 | 88 | @Test 89 | public void uploadMoveAndListFile() throws IOException { 90 | authUserPasswordAndConnect(); 91 | String remotePath = "/home/vagrant/test2.txt"; 92 | String remoteMovePath = "/home/vagrant/test3.txt"; 93 | 94 | clientUnderTest.upload(FileSystems.getDefault().getPath("src/test/resources/test.txt"), remotePath); 95 | clientUnderTest.move(remotePath, remoteMovePath); 96 | List children = clientUnderTest.listChildrenFileNames("/home/vagrant"); 97 | assertThat(children).contains("test3.txt"); 98 | } 99 | 100 | @Test 101 | public void uploadAndDeleteFile() throws IOException { 102 | authUserPasswordAndConnect(); 103 | String remotePath = "/home/vagrant/test4.txt"; 104 | 105 | clientUnderTest.upload(FileSystems.getDefault().getPath("src/test/resources/test.txt"), remotePath); 106 | clientUnderTest.delete(remotePath); 107 | List children = clientUnderTest.listChildrenFileNames("/home/vagrant"); 108 | assertThat(children).doesNotContain("test4.txt"); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/github/sparsick/ssh4j/SshJClientIT.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | public class SshJClientIT extends SshClientIT { 4 | 5 | @Override 6 | public void setUp() { 7 | clientUnderTest = new SshJClient(); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/github/sparsick/ssh4j/VfsSftpClientIT.java: -------------------------------------------------------------------------------- 1 | package com.github.sparsick.ssh4j; 2 | 3 | public class VfsSftpClientIT extends SshClientIT { 4 | 5 | @Override 6 | public void setUp() { 7 | clientUnderTest = new VfsSftpClient(); 8 | } 9 | 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/resources/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEA6HPbAaDkgydBmSBhu1SfQfoDz8SbJ8EiWh8csVFTx0z4jyWu 3 | b4dKfAdS/DPOm8/tuWy5nGmX97iMaNtrkgqvUz8PfKZpQUTCyXZgguFNOI348sQV 4 | TSaVTcARYc3qnFCgE2h1PToR/Mj5zKobYvvBRRNP0xwlnVOi2WR8xBpptzLl6AkA 5 | gsEr6yMGjMND9sFHgStsUK6NMlcijJXVBSF8LLVJM/ADTAGCgj5d7oKxu7M6zCRV 6 | iM0SVNUVR0lkgw4CFYf2HGRelX/iApr9DqJ3ED7hE1fhlzpaS9eqDOY0P8GshRxi 7 | eLgPFJLZIm/yjOxNgpRONjwrvx5U5hnLtf9uGQIDAQABAoIBAQCdY8SH576RpwTd 8 | f3Vs97EVZQkrpn0/f5+Y0bQFw4EsUsuBcQwY68vdCsB/jzx3d2QIxrsuUrjYvBYl 9 | 8Vt2eNGZVftQdQSTctFIw2Q5ef9lKYvEJEwf/t3c1Q1v4ZLW4Chiu7mWCTmgpRuu 10 | HgeJD9kewiKsWESHr9d1xnpL9W5a4Us3YHkVTNIW91dX/IF87hqaEORLhIgE3Jyz 11 | Wmn8GRDXc7bpBvsl/gIzrpMK9Z64xEb5PuILhq218CTKlZ4KxWwa08ffNtW67U8F 12 | qGO4iZu5j7e0cVMpFBp9XBE+tal/fjuAqzveXEKSxn3i30di+LMdDztnr64eiDkh 13 | mYR+cBeZAoGBAPb36gX3UfB757gDzCiGJkirCv0Yj4YhIEKeIitndU1WCWevzcnb 14 | 6v9q+ozwei2lXZX7/f8JK8TDKrN/nQEwp2gVDkJgT5S9qiJSKuLI2mAqQ3KZwD5J 15 | UoZYzmuqx/HSNgAD6qA3MDUbkJbq6vtQEsj9dauHSiBa4SH+ke0pE8hjAoGBAPD0 16 | C7rsgbVfUtrJa0Qjf1dD0AWkOu4LUIzJaFANgdT/myX38bF89T7+YkX1aQwQUTzY 17 | JYjHsa4kE2NAr0HkqciyJILIlapqB9Y3yREAgnRRMAb8tR7anocVmgLXWn/rmls5 18 | SJQVA+TqozPSHTwtchCblS1bVTGyjCVQNsEvj5JTAoGBAJoXx1nfna2Z8dOb8vdZ 19 | 9Gsk5Z9TgsGiy5klR5ajX8pYI1ghlhob8H1bh2cG6ISwiDr71tgZJckIKQ2EUzcZ 20 | 32oOsS3zH9RjntL5R67muXKFDD5l9lAmuan/oRQGo+ibS3wo9Wzv4lFQmJ/Bhco2 21 | hPIJSzEyIascaRon128NUT2XAoGAYmDiITHLS8hdxeKTH0D3DyQq3QLO5L5N5w2c 22 | v4KkTdkG+ZugXP1ODKhEa5flif1njdYajRwrmZQ1LkMMy3SXNdA2RAetw+SCyp4A 23 | RCbXHLLBTzkColRUgYb6WMqgsrX5UeGzlnJ2IpMCi3fwY8+SUOGVKO2vfRkPS3TS 24 | xlGq5u0CgYBziv+nOvOAEKyqhvg/Yd1js28vdG9ZypCC6YQePLmd33tKEoqakpqI 25 | sylfKck7dnT6ChjqBbTNOpfATUC/OxjwHMLivynWaNTobz54to8pF8BU7AUA1vwL 26 | HLQzhDMCG2SXPgE06fYHCFlYMrbRDNBcXl7ubrqcT0xWtSXmsRUkqQ== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /src/test/resources/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDoc9sBoOSDJ0GZIGG7VJ9B+gPPxJsnwSJaHxyxUVPHTPiPJa5vh0p8B1L8M86bz+25bLmcaZf3uIxo22uSCq9TPw98pmlBRMLJdmCC4U04jfjyxBVNJpVNwBFhzeqcUKATaHU9OhH8yPnMqhti+8FFE0/THCWdU6LZZHzEGmm3MuXoCQCCwSvrIwaMw0P2wUeBK2xQro0yVyKMldUFIXwstUkz8ANMAYKCPl3ugrG7szrMJFWIzRJU1RVHSWSDDgIVh/YcZF6Vf+ICmv0OoncQPuETV+GXOlpL16oM5jQ/wayFHGJ4uA8Uktkib/KM7E2ClE42PCu/HlTmGcu1/24Z skosmalla@skosmalla-ThinkPad-T430s 2 | -------------------------------------------------------------------------------- /src/test/resources/known_hosts: -------------------------------------------------------------------------------- 1 | |1|kvHaX2btU1VRjil0Cwk3fKIYLIc=|uJDM6vZWkLeZSwTci3pllUmN26Q= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAye/ADYofk2N4nHSpbNjssY7E9ovuO7FiIVc1zH2M64lcjPChoD2V/GyVrtLCcw8qw/l0M1kSd9WfaAT9oCe8CsQiLqQgfqt2ApaLreKWWIg2raB+PSbm/k4K+J681HkJ04dwImr4bAQS4PecaoDFvYpPf8ApDNrXFu8LqxtHVz5hfbi8iEY6Hd4+SMB+BcGRGLM6xlN6OwlAd4G1Ystwqr5BERmk6a5upF2bhRYt7aNk3Ur58XsLKsS99fnlZhEc4okfHOyEp1wMJMV1yXd2borzH/JOwbmlqenpkpYKH96EFMELur9ymv4AouH6DrswbMIr3LuHhYjiNrvjEjI51w== 2 | -------------------------------------------------------------------------------- /src/test/resources/test.txt: -------------------------------------------------------------------------------- 1 | 99 bottles --------------------------------------------------------------------------------