You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2018/04/25 05:01:29 UTC

[8/8] mina-sshd git commit: [SSHD-818] Split SCP code (client + server) to its own module

[SSHD-818] Split SCP code (client + server) to its own module


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/af415e5f
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/af415e5f
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/af415e5f

Branch: refs/heads/master
Commit: af415e5fec5fadf1c397371313cec20d3b4428f4
Parents: cb8982a
Author: Goldstein Lyor <ly...@c-b4.com>
Authored: Mon Apr 23 16:32:34 2018 +0300
Committer: Goldstein Lyor <ly...@c-b4.com>
Committed: Wed Apr 25 08:01:09 2018 +0300

----------------------------------------------------------------------
 README.md                                       |  146 ++-
 assembly/pom.xml                                |    5 +
 pom.xml                                         |    1 +
 sshd-cli/pom.xml                                |    5 +
 .../apache/sshd/cli/client/ScpCommandMain.java  |   57 +-
 .../apache/sshd/cli/server/SshServerMain.java   |    1 -
 sshd-contrib/pom.xml                            |    5 +
 ...SimpleAccessControlScpEventListenerTest.java |    4 +-
 .../sshd/client/ClientFactoryManager.java       |    2 -
 .../java/org/apache/sshd/client/SshClient.java  |   12 -
 .../sshd/client/scp/AbstractScpClient.java      |  278 ----
 .../sshd/client/scp/CloseableScpClient.java     |   32 -
 .../sshd/client/scp/DefaultScpClient.java       |  159 ---
 .../client/scp/DefaultScpStreamResolver.java    |   88 --
 .../org/apache/sshd/client/scp/ScpClient.java   |  174 ---
 .../sshd/client/scp/ScpClientCreator.java       |   97 --
 .../client/session/AbstractClientSession.java   |   31 -
 .../sshd/client/session/ClientSession.java      |    6 +-
 .../client/simple/AbstractSimpleClient.java     |  106 --
 .../apache/sshd/client/simple/SimpleClient.java |    1 -
 .../sshd/client/simple/SimpleScpClient.java     |  159 ---
 ...AbstractScpTransferEventListenerAdapter.java |   74 --
 .../apache/sshd/common/scp/ScpException.java    |   56 -
 .../apache/sshd/common/scp/ScpFileOpener.java   |  284 -----
 .../sshd/common/scp/ScpFileOpenerHolder.java    |   37 -
 .../org/apache/sshd/common/scp/ScpHelper.java   |  837 ------------
 .../org/apache/sshd/common/scp/ScpLocation.java |  227 ----
 .../sshd/common/scp/ScpReceiveLineHandler.java  |   36 -
 .../common/scp/ScpSourceStreamResolver.java     |   73 --
 .../common/scp/ScpTargetStreamResolver.java     |   67 -
 .../apache/sshd/common/scp/ScpTimestamp.java    |   69 -
 .../common/scp/ScpTransferEventListener.java    |  105 --
 .../scp/helpers/DefaultScpFileOpener.java       |   75 --
 .../LocalFileScpSourceStreamResolver.java       |   97 --
 .../LocalFileScpTargetStreamResolver.java       |  159 ---
 .../common/util/io/functors/IOFunction.java     |   86 ++
 .../org/apache/sshd/server/scp/ScpCommand.java  |  350 -----
 .../sshd/server/scp/ScpCommandFactory.java      |  272 ----
 .../apache/sshd/server/scp/UnknownCommand.java  |  138 --
 .../sshd/server/shell/UnknownCommand.java       |  138 ++
 .../server/shell/UnknownCommandFactory.java     |   39 +
 .../org/apache/sshd/client/scp/ScpTest.java     | 1197 -----------------
 .../simple/BaseSimpleClientTestSupport.java     |   70 -
 .../sshd/client/simple/SimpleScpClientTest.java |  119 --
 .../client/simple/SimpleSessionClientTest.java  |    1 +
 .../server/command/ScpCommandFactoryTest.java   |  114 --
 .../sshd/util/test/UnknownCommandFactory.java   |   40 -
 .../java/org/apache/sshd/util/test/Utils.java   |    1 +
 .../simple/BaseSimpleClientTestSupport.java     |   71 ++
 .../sshd/git/AbstractGitCommandFactory.java     |    2 +-
 sshd-scp/pom.xml                                |  201 +++
 .../sshd/client/scp/AbstractScpClient.java      |  278 ++++
 .../client/scp/AbstractScpClientCreator.java    |   63 +
 .../sshd/client/scp/CloseableScpClient.java     |   32 +
 .../sshd/client/scp/DefaultScpClient.java       |  159 +++
 .../client/scp/DefaultScpClientCreator.java     |   42 +
 .../client/scp/DefaultScpStreamResolver.java    |   88 ++
 .../org/apache/sshd/client/scp/ScpClient.java   |  174 +++
 .../sshd/client/scp/ScpClientCreator.java       |  106 ++
 .../apache/sshd/client/scp/SimpleScpClient.java |  178 +++
 .../sshd/client/scp/SimpleScpClientImpl.java    |  153 +++
 ...AbstractScpTransferEventListenerAdapter.java |   74 ++
 .../apache/sshd/common/scp/ScpException.java    |   56 +
 .../apache/sshd/common/scp/ScpFileOpener.java   |  284 +++++
 .../sshd/common/scp/ScpFileOpenerHolder.java    |   37 +
 .../org/apache/sshd/common/scp/ScpHelper.java   |  837 ++++++++++++
 .../org/apache/sshd/common/scp/ScpLocation.java |  227 ++++
 .../sshd/common/scp/ScpReceiveLineHandler.java  |   36 +
 .../common/scp/ScpSourceStreamResolver.java     |   73 ++
 .../common/scp/ScpTargetStreamResolver.java     |   67 +
 .../apache/sshd/common/scp/ScpTimestamp.java    |   69 +
 .../common/scp/ScpTransferEventListener.java    |  105 ++
 .../scp/helpers/DefaultScpFileOpener.java       |   75 ++
 .../LocalFileScpSourceStreamResolver.java       |   97 ++
 .../LocalFileScpTargetStreamResolver.java       |  159 +++
 .../org/apache/sshd/server/scp/ScpCommand.java  |  350 +++++
 .../sshd/server/scp/ScpCommandFactory.java      |  272 ++++
 .../org/apache/sshd/client/scp/ScpTest.java     | 1203 ++++++++++++++++++
 .../sshd/client/scp/SimpleScpClientTest.java    |  121 ++
 .../sshd/server/scp/ScpCommandFactoryTest.java  |  113 ++
 .../sshd/client/simple/SimpleSftpClient.java    |  179 ---
 .../client/simple/SimpleSftpClientImpl.java     |  171 ---
 .../client/subsystem/sftp/SimpleSftpClient.java |  179 +++
 .../sftp/impl/SimpleSftpClientImpl.java         |  192 +++
 .../java/org/apache/sshd/client/ClientTest.java |  426 -------
 .../simple/BaseSimpleClientTestSupport.java     |   70 -
 .../client/simple/SimpleSftpClientTest.java     |  129 --
 .../sftp/AbstractSftpClientTestSupport.java     |    2 -
 .../sshd/client/subsystem/sftp/ClientTest.java  |  424 ++++++
 .../subsystem/sftp/SftpFileSystemTest.java      |    2 -
 .../subsystem/sftp/SimpleSftpClientTest.java    |  128 ++
 .../sftp/ApacheSshdSftpSessionFactoryTest.java  |    2 -
 92 files changed, 7168 insertions(+), 6668 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index f512a3f..5a1e249 100644
--- a/README.md
+++ b/README.md
@@ -533,17 +533,80 @@ it will be **closed** automatically when the stream using it is closed.
 
 ## SCP
 
-Besides the `ScpTransferEventListener`, the SCP module also uses a `ScpFileOpener` instance in order to access
-the local files - client or server-side. The default implementation simply opens an [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html)
+Both client-side and server-side SCP are supported. Starting from version 2.0, the SCP related code is located in the `sshd-scp` module, so you need
+to add this additional dependency to your maven project:
+
+```xml
+
+    <dependency>
+        <groupId>org.apache.sshd</groupId>
+        <artifactId>sshd-sscp</artifactId>
+        <version>...same as sshd-core...</version>
+    </dependency>
+
+```
+
+### Client-side SCP
+
+In order to obtain an `ScpClient` one needs to use an `ScpClientCreator`:
+
+```java
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+ScpClient client = creator.createScpClient(session);
+
+```
+
+A default `ScpClientCreator` instance is provided as part of the module - see `ScpClientCreator.instance()`
+
+#### ScpFileOpener(s)
+
+As part of the `ScpClientCreator`, the SCP module also uses a `ScpFileOpener` instance in order to access
+the local files. The default implementation simply opens an [InputStream](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html)
 or [OutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html) on the requested local path. However,
-the user may replace it and intercept the calls - e.g., for logging, for wrapping/filtering the streams, etc... **Note:**
-due to SCP protocol limitations one cannot change the **size** of the input/output since it is passed as part of the command
+the user may replace it and intercept the calls - e.g., for logging, for wrapping/filtering the streams, etc... The user may
+attach a default opener that will be automatically attached to **all** clients created unless specifically overridden:
+
+```java
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+creator.setScpFileOpener(new MySuperDuperOpener());
+
+ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses MySuperDuperOpener
+ScpClient client2 = creator.createScpClient(session, new SomeOtherOpener());   // <<== uses SomeOtherOpener instead of MySuperDuperOpener
+
+```
+
+**Note:** due to SCP protocol limitations one cannot change the **size** of the input/output since it is passed as part of the command
 **before** the file opener is invoked - so there are a few limitations on what one can do within this interface implementation.
 
+#### ScpTransferEventListener(s)
+
+The `ScpClientCreator` can also be used to attach a default `ScpTransferEventListener` that will be attached to
+**all** created SCP client instances through that creator - unless specifically overridden:
+
+```java
+
+ClientSession session = ... obtain an instance ...
+ScpClientCreator creator = ... obtain an instance ...
+creator.setScpTransferEventListener(new MySuperDuperListener());
+
+ScpClient client1 = creator.createScpClient(session);   // <<== automatically uses MySuperDuperListener
+ScpClient client2 = creator.createScpClient(session, new SomeOtherListener());   // <<== uses SomeOtherListener instead of MySuperDuperListener
+
+```
+
+### Server-side SCP
+
+The `ScpCommandFactory` allows users to attach an `ScpFileOpener` and/or `ScpTransferEventListener` having the same behavior as the client - i.e.,
+monitoring and intervention on the accessed local files.
 
 ## SFTP
 
-Both client-side and server-side SFTP are supported.  Starting from SSHD 1.8.0, the SFTP related code is located in the `sshd-sftp`, so you need to add this additional dependency to your maven project:
+Both client-side and server-side SFTP are supported. Starting from version 2.0, the SFTP related code is located in the `sshd-sftp`, so you need to add
+this additional dependency to your maven project:
 
 ```xml
 
@@ -567,19 +630,48 @@ On the server side, the following code needs to be added:
 
 ```
 
+### `SftpEventListener`
+
+(See above more details...) - users may register an `SftpEventListener` (or more...) in the `SftpSubsystemFactory` in
+order to monitor and even intervene in the susbsytem's functionality.
+
 ### Client-side SFTP
 
+In order to obtain an `SftpClient` instance one needs to use an `SftpClientFactory`:
+
+
 ```java
 
-    SftpClient client = SftpClientFactory.instance().createSftpClient(session);
+    ClientSession session = ...obtain session...
+    SftpClientFactory factory = ...obtain factory...
+    SftpClient client = factory.createSftpClient(session);
 
 ```
 
-### `SftpEventListener`
+A default client factory implementations is provided in the module - see `SftpClientFactory.instance()`
+
+
+### Using a custom `SftpClientFactory`
+
+The code creates `SftpClient`-s and `SftpFileSystem`-s using a default built-in `SftpClientFactory` instance (see
+`DefaultSftpClientFactory`). Users may choose to use a custom factory in order to provide their own
+implementations - e.g., in order to override some default behavior - e.g.:
+
+```java
+
+    SshClient client = ... setup client...
+
+    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
+        session.addPasswordIdentity(password);
+        session.auth.verify(timeout);
 
-See above...
-In addition to the `SftpEventListener` there are a few more SFTP-related special interfaces and modules.
+        // User-specific factory
+        try (SftpClient sftp = MySpecialSessionSftpClientFactory.INSTANCE.createSftpClient(session)) {
+            ... instance created through SpecialSessionSftpClientFactory ...
+        }
+    }
 
+```
 
 ### Version selection via `SftpVersionSelector`
 
@@ -603,7 +695,8 @@ range.
         session.addPasswordIdentity(password);
         session.auth.verify(timeout);
 
-        try (SftpClient sftp = SftpClientFactory.instance().createSftpClient(session, myVersionSelector)) {
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session, myVersionSelector)) {
             ... do SFTP related stuff...
         }
     }
@@ -615,30 +708,6 @@ the version, and all we can do at the server is require a **specific** version v
 configuration key. For more advanced restrictions one needs to sub-class `SftpSubSystem` and provide a non-default
 `SftpSubsystemFactory` that uses the sub-classed code.
 
-
-### Using a custom `SftpClientFactory`
-
-The code creates `SftpClient`-s and `SftpFileSystem`-s using a default built-in `SftpClientFactory` instance (see
-`DefaultSftpClientFactory`). Users may choose to use a custom factory in order to provide their own
-implementations - e.g., in order to override some default behavior - e.g.:
-
-```java
-
-    SshClient client = ... setup client...
-
-    try (ClientSession session = client.connect(user, host, port).verify(timeout).getSession()) {
-        session.addPasswordIdentity(password);
-        session.auth.verify(timeout);
-
-        // User-specific factory
-        try (SftpClient sftp = MySpecialSessionSftpClientFactory.INSTANCE.createSftpClient(session)) {
-            ... instance created through SpecialSessionSftpClientFactory ...
-        }
-    }
-
-```
-
-
 ### Using `SftpFileSystemProvider` to create an `SftpFileSystem`
 
 
@@ -796,7 +865,8 @@ UTF-8 is used. **Note:** the value can be a charset name or a `java.nio.charset.
          PropertyResolverUtils.updateProperty(session, SftpClient.NAME_DECODING_CHARSET, "ISO-8859-4");
          session.authenticate(...);
 
-         try (SftpClient sftp = SftpClientFactory.instance().createSftpClient(session)) {
+         SftpClientFactory factory = SftpClientFactory.instance();
+         try (SftpClient sftp = factory.createSftpClient(session)) {
              for (DirEntry entry : sftp.readDir(...some path...)) {
                  ...handle entry assuming ISO-8859-4 (inherited from the session) encoded names...
              }
@@ -848,7 +918,8 @@ On the client side, all the supported extensions are classes that implement `Sft
         session.addPasswordIdentity(password);
         session.auth().verify(timeout);
 
-        try (SftpClient sftp = SftpClientFactory.instance().createSftpClient(session)) {
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session)) {
             Map<String, byte[]> extensions = sftp.getServerExtensions();
             // Key=extension name, value=registered parser instance
             Map<String, ?> data = ParserUtils.parse(extensions);
@@ -880,7 +951,8 @@ One can skip all the conditional code if a specific known extension is required:
         session.addPasswordIdentity(password);
         session.auth().verify(timeout);
 
-        try (SftpClient sftp = SftpClientFactory.instance().createSftpClient(session)) {
+        SftpClientFactory factory = SftpClientFactory.instance();
+        try (SftpClient sftp = factory.createSftpClient(session)) {
             // Returns null if extension is not supported by remote server
             SpaceAvailableExtension space = sftp.getExtension(SpaceAvailableExtension.class);
             if (space != null) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/assembly/pom.xml
----------------------------------------------------------------------
diff --git a/assembly/pom.xml b/assembly/pom.xml
index 53db1ba..7b103e1 100644
--- a/assembly/pom.xml
+++ b/assembly/pom.xml
@@ -43,6 +43,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-scp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
             <artifactId>sshd-sftp</artifactId>
             <version>${project.version}</version>
         </dependency>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b88a195..f161f1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1006,6 +1006,7 @@
 
     <modules>
         <module>sshd-core</module>
+        <module>sshd-scp</module>
         <module>sshd-sftp</module>
         <module>sshd-mina</module>
         <module>sshd-netty</module>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-cli/pom.xml
----------------------------------------------------------------------
diff --git a/sshd-cli/pom.xml b/sshd-cli/pom.xml
index 0f9bb98..0925da8 100644
--- a/sshd-cli/pom.xml
+++ b/sshd-cli/pom.xml
@@ -44,6 +44,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-scp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
             <artifactId>sshd-sftp</artifactId>
             <version>${project.version}</version>
         </dependency>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
index 8a9e4a9..3f233ef 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/ScpCommandMain.java
@@ -35,11 +35,13 @@ import java.util.logging.Level;
 
 import org.apache.sshd.client.scp.ScpClient;
 import org.apache.sshd.client.scp.ScpClient.Option;
+import org.apache.sshd.client.scp.ScpClientCreator;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.scp.ScpLocation;
 import org.apache.sshd.common.scp.ScpTransferEventListener;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.apache.sshd.common.util.threads.ThreadUtils;
 
 /**
  * TODO Add javadoc
@@ -70,13 +72,14 @@ public class ScpCommandMain extends SshClientCliSupport {
             String argName = args[index];
             // handled by 'setupClientSession'
             if (isArgumentedOption(SCP_PORT_OPTION, argName)) {
-                if ((index + 1) >= numArgs) {
+                index++;
+                if (index >= numArgs) {
                     error = showError(stderr, "option requires an argument: " + argName);
                     break;
                 }
 
                 effective.add(argName);
-                effective.add(args[++index]);
+                effective.add(args[index]);
             } else if ("-r".equals(argName) || "-p".equals(argName)
                     || "-q".equals(argName) || "-C".equals(argName)
                     || "-v".equals(argName) || "-vv".equals(argName) || "-vvv".equals(argName)) {
@@ -85,13 +88,14 @@ public class ScpCommandMain extends SshClientCliSupport {
                 error = showError(stderr, "Unknown option: " + argName);
                 break;
             } else {
-                if ((index + 1) >= numArgs) {
+                index++;
+                if (index >= numArgs) {
                     error = showError(stderr, "Not enough arguments");
                     break;
                 }
 
                 ScpLocation source = new ScpLocation(argName);
-                ScpLocation target = new ScpLocation(args[++index]);
+                ScpLocation target = new ScpLocation(args[index]);
                 if (index < (numArgs - 1)) {
                     error = showError(stderr, "Unexpected extra arguments");
                     break;
@@ -117,6 +121,42 @@ public class ScpCommandMain extends SshClientCliSupport {
         return effective.toArray(new String[effective.size()]);
     }
 
+    public static ScpClientCreator resolveScpClientCreator(PrintStream stderr, String... args) {
+        String className = null;
+        for (int index = 0, numArgs = GenericUtils.length(args); index < numArgs; index++) {
+            String argName = args[index];
+            if ("-creator".equals(argName)) {
+                index++;
+                if (index >= numArgs) {
+                    showError(stderr, "option requires an argument: " + argName);
+                    return null;
+                }
+
+                className = args[index];
+            }
+        }
+
+        if (GenericUtils.isEmpty(className)) {
+            className = System.getProperty(ScpClientCreator.class.getName());
+        }
+
+        if (GenericUtils.isEmpty(className)) {
+            return ScpClientCreator.instance();
+        }
+
+        try {
+            ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(ScpClientCreator.class);
+            Class<?> clazz = cl.loadClass(className);
+            return ScpClientCreator.class.cast(clazz.newInstance());
+        } catch (Exception e) {
+            stderr.append("Failed (").append(e.getClass().getSimpleName()).append(')')
+                .append(" to instantiate ").append(className)
+                .append(": ").println(e.getMessage());
+            stderr.flush();
+            return null;
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         PrintStream stdout = System.out;
         PrintStream stderr = System.err;
@@ -134,11 +174,12 @@ public class ScpCommandMain extends SshClientCliSupport {
                 }
             }
 
-            ClientSession session = (logStream == null) || GenericUtils.isEmpty(args)
+            ScpClientCreator creator = resolveScpClientCreator(stderr, args);
+            ClientSession session = ((logStream == null) || (creator == null) || GenericUtils.isEmpty(args))
                 ? null : setupClientSession(SCP_PORT_OPTION, stdin, stdout, stderr, args);
             if (session == null) {
                 stderr.println("usage: scp [" + SCP_PORT_OPTION + " port] [-i identity] [-io nio2|mina|netty]"
-                         + " [-v[v][v]] [-E logoutput] [-r] [-p] [-q] [-o option=value]"
+                         + " [-v[v][v]] [-E logoutput] [-r] [-p] [-q] [-o option=value] [-o creator=class name]"
                          + " [-c cipherlist] [-m maclist] [-w password] [-C] <source> <target>");
                 stderr.println();
                 stderr.println("Where <source> or <target> are either 'user@host:file' or a local file path");
@@ -163,7 +204,7 @@ public class ScpCommandMain extends SshClientCliSupport {
                 }
 
                 if (!quiet) {
-                    session.setScpTransferEventListener(new ScpTransferEventListener() {
+                    creator.setScpTransferEventListener(new ScpTransferEventListener() {
                         @Override
                         public void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms) {
                             logEvent("startFolderEvent", op, file, -1L, perms, null);
@@ -200,7 +241,7 @@ public class ScpCommandMain extends SshClientCliSupport {
                     });
                 }
 
-                ScpClient client = session.createScpClient();
+                ScpClient client = creator.createScpClient(session);
                 ScpLocation source = new ScpLocation(args[numArgs - 2]);
                 ScpLocation target = new ScpLocation(args[numArgs - 1]);
                 if (source.isLocal()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
index cba9d24..05c1069 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
@@ -56,7 +56,6 @@ public class SshServerMain extends SshServerCliSupport {
 
     public static void main(String[] args) throws Exception {
         int port = 8000;
-        String provider;
         boolean error = false;
         String hostKeyType = AbstractGeneratorHostKeyProvider.DEFAULT_ALGORITHM;
         int hostKeySize = 0;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-contrib/pom.xml
----------------------------------------------------------------------
diff --git a/sshd-contrib/pom.xml b/sshd-contrib/pom.xml
index e904686..f0ff459 100644
--- a/sshd-contrib/pom.xml
+++ b/sshd-contrib/pom.xml
@@ -53,6 +53,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.sshd</groupId>
+            <artifactId>sshd-scp</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sshd</groupId>
             <artifactId>sshd-sftp</artifactId>
             <version>${project.version}</version>
         </dependency>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-contrib/src/test/java/org/apache/sshd/server/scp/SimpleAccessControlScpEventListenerTest.java
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/test/java/org/apache/sshd/server/scp/SimpleAccessControlScpEventListenerTest.java b/sshd-contrib/src/test/java/org/apache/sshd/server/scp/SimpleAccessControlScpEventListenerTest.java
index 70bcd44..4312dda 100644
--- a/sshd-contrib/src/test/java/org/apache/sshd/server/scp/SimpleAccessControlScpEventListenerTest.java
+++ b/sshd-contrib/src/test/java/org/apache/sshd/server/scp/SimpleAccessControlScpEventListenerTest.java
@@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.scp.ScpClient;
+import org.apache.sshd.client.scp.ScpClientCreator;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
@@ -89,7 +90,8 @@ public class SimpleAccessControlScpEventListenerTest extends BaseTestSupport {
                 session.addPasswordIdentity(getCurrentTestName());
                 session.auth().verify(5L, TimeUnit.SECONDS);
 
-                ScpClient scp = session.createScpClient();
+                ScpClientCreator creator = ScpClientCreator.instance();
+                ScpClient scp = creator.createScpClient(session);
                 Path targetPath = detectTargetFolder();
                 Path parentPath = targetPath.getParent();
                 Path scpRoot = Utils.resolve(targetPath, ScpHelper.SCP_COMMAND_PREFIX, getClass().getSimpleName(), getCurrentTestName());

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
index 31b2a22..26ca4bd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientFactoryManager.java
@@ -23,7 +23,6 @@ import org.apache.sshd.client.config.keys.ClientIdentityLoader;
 import org.apache.sshd.client.session.ClientProxyConnectorHolder;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
-import org.apache.sshd.common.scp.ScpFileOpenerHolder;
 
 /**
  * The <code>ClientFactoryManager</code> enable the retrieval of additional
@@ -33,7 +32,6 @@ import org.apache.sshd.common.scp.ScpFileOpenerHolder;
  */
 public interface ClientFactoryManager
         extends FactoryManager,
-                ScpFileOpenerHolder,
                 ClientProxyConnectorHolder,
                 ClientAuthenticationManager {
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
index 1d034c1..e387bb6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -74,7 +74,6 @@ import org.apache.sshd.common.io.IoConnectFuture;
 import org.apache.sshd.common.io.IoConnector;
 import org.apache.sshd.common.io.IoSession;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.scp.ScpFileOpener;
 import org.apache.sshd.common.session.helpers.AbstractSession;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -162,7 +161,6 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
     private ClientIdentityLoader clientIdentityLoader;
     private FilePasswordProvider filePasswordProvider;
     private PasswordIdentityProvider passwordIdentityProvider;
-    private ScpFileOpener scpOpener;
 
     private final List<Object> identities = new CopyOnWriteArrayList<>();
     private final AuthenticationIdentitiesProvider identitiesProvider;
@@ -191,16 +189,6 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
     }
 
     @Override
-    public ScpFileOpener getScpFileOpener() {
-        return scpOpener;
-    }
-
-    @Override
-    public void setScpFileOpener(ScpFileOpener opener) {
-        scpOpener = opener;
-    }
-
-    @Override
     public ServerKeyVerifier getServerKeyVerifier() {
         return serverKeyVerifier;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
deleted file mode 100644
index 81c20db..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.client.scp;
-
-import java.io.IOException;
-import java.nio.file.FileSystem;
-import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.channel.ChannelExec;
-import org.apache.sshd.client.channel.ClientChannel;
-import org.apache.sshd.client.channel.ClientChannelEvent;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.file.FileSystemFactory;
-import org.apache.sshd.common.scp.ScpException;
-import org.apache.sshd.common.scp.ScpHelper;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractScpClient extends AbstractLoggingBean implements ScpClient {
-    public static final Set<ClientChannelEvent> COMMAND_WAIT_EVENTS =
-            Collections.unmodifiableSet(EnumSet.of(ClientChannelEvent.EXIT_STATUS, ClientChannelEvent.CLOSED));
-
-    protected AbstractScpClient() {
-        super();
-    }
-
-    @Override
-    public final ClientSession getSession() {
-        return getClientSession();
-    }
-
-    @Override
-    public void download(String[] remote, String local, Collection<Option> options) throws IOException {
-        local = ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", local);
-        remote = ValidateUtils.checkNotNullAndNotEmpty(remote, "Invalid argument remote: %s", (Object) remote);
-
-        if (remote.length > 1) {
-            options = addTargetIsDirectory(options);
-        }
-
-        for (String r : remote) {
-            download(r, local, options);
-        }
-    }
-
-    @Override
-    public void download(String[] remote, Path local, Collection<Option> options) throws IOException {
-        remote = ValidateUtils.checkNotNullAndNotEmpty(remote, "Invalid argument remote: %s", (Object) remote);
-
-        if (remote.length > 1) {
-            options = addTargetIsDirectory(options);
-        }
-
-        for (String r : remote) {
-            download(r, local, options);
-        }
-    }
-
-    @Override
-    public void download(String remote, Path local, Collection<Option> options) throws IOException {
-        local = ValidateUtils.checkNotNull(local, "Invalid argument local: %s", local);
-        remote = ValidateUtils.checkNotNullAndNotEmpty(remote, "Invalid argument remote: %s", remote);
-
-        LinkOption[] opts = IoUtils.getLinkOptions(true);
-        if (Files.isDirectory(local, opts)) {
-            options = addTargetIsDirectory(options);
-        }
-
-        if (options.contains(Option.TargetIsDirectory)) {
-            Boolean status = IoUtils.checkFileExists(local, opts);
-            if (status == null) {
-                throw new SshException("Target directory " + local.toString() + " is probably inaccesible");
-            }
-
-            if (!status) {
-                throw new SshException("Target directory " + local.toString() + " does not exist");
-            }
-
-            if (!Files.isDirectory(local, opts)) {
-                throw new SshException("Target directory " + local.toString() + " is not a directory");
-            }
-        }
-
-        download(remote, local.getFileSystem(), local, options);
-    }
-
-    @Override
-    public void download(String remote, String local, Collection<Option> options) throws IOException {
-        local = ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", local);
-
-        ClientSession session = getClientSession();
-        FactoryManager manager = session.getFactoryManager();
-        FileSystemFactory factory = manager.getFileSystemFactory();
-        FileSystem fs = factory.createFileSystem(session);
-        try {
-            download(remote, fs, fs.getPath(local), options);
-        } finally {
-            try {
-                fs.close();
-            } catch (UnsupportedOperationException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug("download({}) {} => {} - failed ({}) to close file system={}: {}",
-                              session, remote, local, e.getClass().getSimpleName(), fs, e.getMessage());
-                }
-            }
-        }
-    }
-
-    protected abstract void download(String remote, FileSystem fs, Path local, Collection<Option> options) throws IOException;
-
-    @Override
-    public void upload(String[] local, String remote, Collection<Option> options) throws IOException {
-        final Collection<String> paths = Arrays.asList(ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", (Object) local));
-        runUpload(remote, options, paths, (helper, local1, sendOptions) ->
-                helper.send(local1,
-                            sendOptions.contains(Option.Recursive),
-                            sendOptions.contains(Option.PreserveAttributes),
-                            ScpHelper.DEFAULT_SEND_BUFFER_SIZE));
-    }
-
-    @Override
-    public void upload(Path[] local, String remote, Collection<Option> options) throws IOException {
-        final Collection<Path> paths = Arrays.asList(ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", (Object) local));
-        runUpload(remote, options, paths, (helper, local1, sendOptions) ->
-                helper.sendPaths(local1,
-                                 sendOptions.contains(Option.Recursive),
-                                 sendOptions.contains(Option.PreserveAttributes),
-                                 ScpHelper.DEFAULT_SEND_BUFFER_SIZE));
-    }
-
-    protected abstract <T> void runUpload(String remote, Collection<Option> options, Collection<T> local, AbstractScpClient.ScpOperationExecutor<T> executor) throws IOException;
-
-    /**
-     * Invoked by the various <code>upload/download</code> methods after having successfully
-     * completed the remote copy command and (optionally) having received an exit status
-     * from the remote server. If no exit status received within {@link FactoryManager#CHANNEL_CLOSE_TIMEOUT}
-     * the no further action is taken. Otherwise, the exit status is examined to ensure it
-     * is either OK or WARNING - if not, an {@link ScpException} is thrown
-     *
-     * @param cmd The attempted remote copy command
-     * @param channel The {@link ClientChannel} through which the command was sent - <B>Note:</B>
-     * then channel may be in the process of being closed
-     * @throws IOException If failed the command
-     * @see #handleCommandExitStatus(String, Integer)
-     */
-    protected void handleCommandExitStatus(String cmd, ClientChannel channel) throws IOException {
-        // give a chance for the exit status to be received
-        long timeout = channel.getLongProperty(SCP_EXEC_CHANNEL_EXIT_STATUS_TIMEOUT, DEFAULT_EXEC_CHANNEL_EXIT_STATUS_TIMEOUT);
-        if (timeout <= 0L) {
-            handleCommandExitStatus(cmd, (Integer) null);
-            return;
-        }
-
-        long waitStart = System.nanoTime();
-        Collection<ClientChannelEvent> events = channel.waitFor(COMMAND_WAIT_EVENTS, timeout);
-        long waitEnd = System.nanoTime();
-        if (log.isDebugEnabled()) {
-            log.debug("handleCommandExitStatus({}) cmd='{}', waited={} nanos, events={}",
-                      getClientSession(), cmd, waitEnd - waitStart, events);
-        }
-
-        /*
-         * There are sometimes race conditions in the order in which channels are closed and exit-status
-         * sent by the remote peer (if at all), thus there is no guarantee that we will have an exit
-         * status here
-         */
-        handleCommandExitStatus(cmd, channel.getExitStatus());
-    }
-
-    /**
-     * Invoked by the various <code>upload/download</code> methods after having successfully
-     * completed the remote copy command and (optionally) having received an exit status
-     * from the remote server
-     *
-     * @param cmd The attempted remote copy command
-     * @param exitStatus The exit status - if {@code null} then no status was reported
-     * @throws IOException If failed the command
-     */
-    protected void handleCommandExitStatus(String cmd, Integer exitStatus) throws IOException {
-        if (log.isDebugEnabled()) {
-            log.debug("handleCommandExitStatus({}) cmd='{}', exit-status={}", getClientSession(), cmd, ScpHelper.getExitStatusName(exitStatus));
-        }
-
-        if (exitStatus == null) {
-            return;
-        }
-
-        int statusCode = exitStatus;
-        switch (statusCode) {
-            case ScpHelper.OK:  // do nothing
-                break;
-            case ScpHelper.WARNING:
-                log.warn("handleCommandExitStatus({}) cmd='{}' may have terminated with some problems", getClientSession(), cmd);
-                break;
-            default:
-                throw new ScpException("Failed to run command='" + cmd + "': " + ScpHelper.getExitStatusName(exitStatus), exitStatus);
-        }
-    }
-
-    protected Collection<Option> addTargetIsDirectory(Collection<Option> options) {
-        if (GenericUtils.isEmpty(options) || (!options.contains(Option.TargetIsDirectory))) {
-            // create a copy in case the original collection is un-modifiable
-            options = GenericUtils.isEmpty(options) ? EnumSet.noneOf(Option.class) : GenericUtils.of(options);
-            options.add(Option.TargetIsDirectory);
-        }
-
-        return options;
-    }
-
-    protected ChannelExec openCommandChannel(ClientSession session, String cmd) throws IOException {
-        long waitTimeout = session.getLongProperty(SCP_EXEC_CHANNEL_OPEN_TIMEOUT, DEFAULT_EXEC_CHANNEL_OPEN_TIMEOUT);
-        ChannelExec channel = session.createExecChannel(cmd);
-
-        long startTime = System.nanoTime();
-        try {
-            channel.open().verify(waitTimeout);
-            long endTime = System.nanoTime();
-            long nanosWait = endTime - startTime;
-            if (log.isTraceEnabled()) {
-                log.trace("openCommandChannel(" + session + ")[" + cmd + "]"
-                        + " completed after " + nanosWait
-                        + " nanos out of " + TimeUnit.MILLISECONDS.toNanos(waitTimeout));
-            }
-
-            return channel;
-        } catch (IOException | RuntimeException e) {
-            long endTime = System.nanoTime();
-            long nanosWait = endTime - startTime;
-            if (log.isTraceEnabled()) {
-                log.trace("openCommandChannel(" + session + ")[" + cmd + "]"
-                        + " failed (" + e.getClass().getSimpleName() + ")"
-                        + " to complete after " + nanosWait
-                        + " nanos out of " + TimeUnit.MILLISECONDS.toNanos(waitTimeout)
-                        + ": " + e.getMessage());
-            }
-
-            channel.close(false);
-            throw e;
-        }
-    }
-
-    @FunctionalInterface
-    public interface ScpOperationExecutor<T> {
-        void execute(ScpHelper helper, Collection<T> local, Collection<Option> options) throws IOException;
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/CloseableScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/CloseableScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/CloseableScpClient.java
deleted file mode 100644
index 40afaf7..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/CloseableScpClient.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.client.scp;
-
-import java.nio.channels.Channel;
-
-/**
- * An {@link ScpClient} wrapper that also closes the underlying session
- * when closed
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface CloseableScpClient extends ScpClient, Channel {
-    // Marker interface
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
deleted file mode 100644
index 16d0cb2..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.scp;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.FileSystem;
-import java.nio.file.Path;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.Objects;
-
-import org.apache.sshd.client.channel.ChannelExec;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.file.FileSystemFactory;
-import org.apache.sshd.common.file.util.MockFileSystem;
-import org.apache.sshd.common.file.util.MockPath;
-import org.apache.sshd.common.scp.ScpFileOpener;
-import org.apache.sshd.common.scp.ScpHelper;
-import org.apache.sshd.common.scp.ScpTimestamp;
-import org.apache.sshd.common.scp.ScpTransferEventListener;
-import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener;
-import org.apache.sshd.common.util.ValidateUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DefaultScpClient extends AbstractScpClient {
-    protected final ScpFileOpener opener;
-    protected final ScpTransferEventListener listener;
-    private final ClientSession clientSession;
-
-    public DefaultScpClient(
-            ClientSession clientSession, ScpFileOpener fileOpener, ScpTransferEventListener eventListener) {
-        this.clientSession = Objects.requireNonNull(clientSession, "No client session");
-        this.opener = (fileOpener == null) ? DefaultScpFileOpener.INSTANCE : fileOpener;
-        this.listener = (eventListener == null) ? ScpTransferEventListener.EMPTY : eventListener;
-    }
-
-    @Override
-    public ClientSession getClientSession() {
-        return clientSession;
-    }
-
-    @Override
-    public void download(String remote, OutputStream local) throws IOException {
-        String cmd = ScpClient.createReceiveCommand(remote, Collections.emptyList());
-        ClientSession session = getClientSession();
-        ChannelExec channel = openCommandChannel(session, cmd);
-        try (InputStream invOut = channel.getInvertedOut();
-             OutputStream invIn = channel.getInvertedIn()) {
-            // NOTE: we use a mock file system since we expect no invocations for it
-            ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, listener);
-            helper.receiveFileStream(local, ScpHelper.DEFAULT_RECEIVE_BUFFER_SIZE);
-            handleCommandExitStatus(cmd, channel);
-        } finally {
-            channel.close(false);
-        }
-    }
-
-    @Override
-    protected void download(String remote, FileSystem fs, Path local, Collection<Option> options) throws IOException {
-        String cmd = ScpClient.createReceiveCommand(remote, options);
-        ClientSession session = getClientSession();
-        ChannelExec channel = openCommandChannel(session, cmd);
-        try (InputStream invOut = channel.getInvertedOut();
-             OutputStream invIn = channel.getInvertedIn()) {
-            ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, listener);
-            helper.receive(local,
-                    options.contains(Option.Recursive),
-                    options.contains(Option.TargetIsDirectory),
-                    options.contains(Option.PreserveAttributes),
-                    ScpHelper.DEFAULT_RECEIVE_BUFFER_SIZE);
-            handleCommandExitStatus(cmd, channel);
-        } finally {
-            channel.close(false);
-        }
-    }
-
-    @Override
-    public void upload(InputStream local, String remote, long size, Collection<PosixFilePermission> perms, ScpTimestamp time) throws IOException {
-        int namePos = ValidateUtils.checkNotNullAndNotEmpty(remote, "No remote location specified").lastIndexOf('/');
-        String name = (namePos < 0)
-            ? remote
-            : ValidateUtils.checkNotNullAndNotEmpty(remote.substring(namePos + 1), "No name value in remote=%s", remote);
-        Collection<Option> options = (time != null) ? EnumSet.of(Option.PreserveAttributes) : Collections.emptySet();
-        String cmd = ScpClient.createSendCommand(remote, options);
-        ClientSession session = getClientSession();
-        ChannelExec channel = openCommandChannel(session, cmd);
-        try (InputStream invOut = channel.getInvertedOut();
-             OutputStream invIn = channel.getInvertedIn()) {
-            // NOTE: we use a mock file system since we expect no invocations for it
-            ScpHelper helper = new ScpHelper(session, invOut, invIn, new MockFileSystem(remote), opener, listener);
-            Path mockPath = new MockPath(remote);
-            helper.sendStream(new DefaultScpStreamResolver(name, mockPath, perms, time, size, local, cmd),
-                    options.contains(Option.PreserveAttributes), ScpHelper.DEFAULT_SEND_BUFFER_SIZE);
-            handleCommandExitStatus(cmd, channel);
-        } finally {
-            channel.close(false);
-        }
-    }
-
-    @Override
-    protected <T> void runUpload(String remote, Collection<Option> options, Collection<T> local, AbstractScpClient.ScpOperationExecutor<T> executor) throws IOException {
-        local = ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", local);
-        remote = ValidateUtils.checkNotNullAndNotEmpty(remote, "Invalid argument remote: %s", remote);
-        if (local.size() > 1) {
-            options = addTargetIsDirectory(options);
-        }
-
-        String cmd = ScpClient.createSendCommand(remote, options);
-        ClientSession session = getClientSession();
-        ChannelExec channel = openCommandChannel(session, cmd);
-        try {
-            FactoryManager manager = session.getFactoryManager();
-            FileSystemFactory factory = manager.getFileSystemFactory();
-            FileSystem fs = factory.createFileSystem(session);
-
-            try (InputStream invOut = channel.getInvertedOut();
-                 OutputStream invIn = channel.getInvertedIn()) {
-                ScpHelper helper = new ScpHelper(session, invOut, invIn, fs, opener, listener);
-                executor.execute(helper, local, options);
-            } finally {
-                try {
-                    fs.close();
-                } catch (UnsupportedOperationException e) {
-                    if (log.isDebugEnabled()) {
-                        log.debug("runUpload({}) {} => {} - failed ({}) to close file system={}: {}",
-                                  session, remote, local, e.getClass().getSimpleName(), fs, e.getMessage());
-                    }
-                }
-            }
-            handleCommandExitStatus(cmd, channel);
-        } finally {
-            channel.close(false);
-        }
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpStreamResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpStreamResolver.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpStreamResolver.java
deleted file mode 100644
index e6362b8..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpStreamResolver.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.scp;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.OpenOption;
-import java.nio.file.Path;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Collection;
-
-import org.apache.sshd.common.scp.ScpSourceStreamResolver;
-import org.apache.sshd.common.scp.ScpTimestamp;
-import org.apache.sshd.common.session.Session;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class DefaultScpStreamResolver implements ScpSourceStreamResolver {
-    private final String name;
-    private final Path mockPath;
-    private final Collection<PosixFilePermission> perms;
-    private final ScpTimestamp time;
-    private final long size;
-    private final java.io.InputStream local;
-    private final String cmd;
-
-    public DefaultScpStreamResolver(String name, Path mockPath, Collection<PosixFilePermission> perms, ScpTimestamp time, long size, InputStream local, String cmd) {
-        this.name = name;
-        this.mockPath = mockPath;
-        this.perms = perms;
-        this.time = time;
-        this.size = size;
-        this.local = local;
-        this.cmd = cmd;
-    }
-
-    @Override
-    public String getFileName() throws java.io.IOException {
-        return name;
-    }
-
-    @Override
-    public Path getEventListenerFilePath() {
-        return mockPath;
-    }
-
-    @Override
-    public Collection<PosixFilePermission> getPermissions() throws IOException {
-        return perms;
-    }
-
-    @Override
-    public ScpTimestamp getTimestamp() throws IOException {
-        return time;
-    }
-
-    @Override
-    public long getSize() throws IOException {
-        return size;
-    }
-
-    @Override
-    public InputStream resolveSourceStream(Session session, OpenOption... options) throws IOException {
-        return local;
-    }
-
-    @Override
-    public String toString() {
-        return cmd;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClient.java
deleted file mode 100644
index b2a6091..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClient.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sshd.client.scp;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Path;
-import java.nio.file.attribute.PosixFilePermission;
-import java.util.Collection;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.client.session.ClientSessionHolder;
-import org.apache.sshd.common.scp.ScpHelper;
-import org.apache.sshd.common.scp.ScpTimestamp;
-import org.apache.sshd.common.session.SessionHolder;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface ScpClient extends SessionHolder<ClientSession>, ClientSessionHolder {
-    enum Option {
-        Recursive,
-        PreserveAttributes,
-        TargetIsDirectory
-    }
-
-    /**
-     * Configurable value of the {@link org.apache.sshd.common.FactoryManager}
-     * for controlling the wait timeout for opening a channel for an SCP command
-     * in milliseconds. If not specified, then {@link #DEFAULT_EXEC_CHANNEL_OPEN_TIMEOUT}
-     * value is used
-     */
-    String SCP_EXEC_CHANNEL_OPEN_TIMEOUT = "scp-exec-channel-open-timeout";
-    long DEFAULT_EXEC_CHANNEL_OPEN_TIMEOUT = TimeUnit.SECONDS.toMillis(30L);
-
-    /**
-     * Configurable value of the {@link org.apache.sshd.common.FactoryManager}
-     * for controlling the wait timeout for waiting on a channel exit status'
-     * for an SCP command in milliseconds. If not specified, then
-     * {@link #DEFAULT_EXEC_CHANNEL_EXIT_STATUS_TIMEOUT}
-     * value is used. If non-positive, then no wait is performed and the command
-     * is assumed to have completed successfully.
-     */
-    String SCP_EXEC_CHANNEL_EXIT_STATUS_TIMEOUT = "scp-exec-channel-exit-status-timeout";
-    long DEFAULT_EXEC_CHANNEL_EXIT_STATUS_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
-
-    default void download(String remote, String local, Option... options) throws IOException {
-        download(remote, local, GenericUtils.of(options));
-    }
-
-    void download(String remote, String local, Collection<Option> options) throws IOException;
-
-    default void download(String remote, Path local, Option... options) throws IOException {
-        download(remote, local, GenericUtils.of(options));
-    }
-
-    void download(String remote, Path local, Collection<Option> options) throws IOException;
-
-    // NOTE: the remote location MUST be a file or an exception is generated
-    void download(String remote, OutputStream local) throws IOException;
-
-    default byte[] downloadBytes(String remote) throws IOException {
-        try (ByteArrayOutputStream local = new ByteArrayOutputStream()) {
-            download(remote, local);
-            return local.toByteArray();
-        }
-    }
-
-    default void download(String[] remote, String local, Option... options) throws IOException {
-        download(remote, local, GenericUtils.of(options));
-    }
-
-    default void download(String[] remote, Path local, Option... options) throws IOException {
-        download(remote, local, GenericUtils.of(options));
-    }
-
-    void download(String[] remote, String local, Collection<Option> options) throws IOException;
-
-    void download(String[] remote, Path local, Collection<Option> options) throws IOException;
-
-    default void upload(String local, String remote, Option... options) throws IOException {
-        upload(local, remote, GenericUtils.of(options));
-    }
-
-    default void upload(String local, String remote, Collection<Option> options) throws IOException {
-        upload(new String[]{ValidateUtils.checkNotNullAndNotEmpty(local, "Invalid argument local: %s", local)}, remote, options);
-    }
-
-    default void upload(Path local, String remote, Option... options) throws IOException {
-        upload(local, remote, GenericUtils.of(options));
-    }
-
-    default void upload(Path local, String remote, Collection<Option> options) throws IOException {
-        upload(new Path[]{ValidateUtils.checkNotNull(local, "Invalid local argument: %s", local)}, remote, GenericUtils.of(options));
-    }
-
-    default void upload(String[] local, String remote, Option... options) throws IOException {
-        upload(local, remote, GenericUtils.of(options));
-    }
-
-    void upload(String[] local, String remote, Collection<Option> options) throws IOException;
-
-    default void upload(Path[] local, String remote, Option... options) throws IOException {
-        upload(local, remote, GenericUtils.of(options));
-    }
-
-    void upload(Path[] local, String remote, Collection<Option> options) throws IOException;
-
-    // NOTE: due to SCP command limitations, the amount of data to be uploaded must be known a-priori
-    // To upload a dynamic amount of data use SFTP
-    default void upload(byte[] data, String remote, Collection<PosixFilePermission> perms, ScpTimestamp time) throws IOException {
-        upload(data, 0, data.length, remote, perms, time);
-    }
-
-    default void upload(byte[] data, int offset, int len, String remote, Collection<PosixFilePermission> perms, ScpTimestamp time) throws IOException {
-        try (InputStream local = new ByteArrayInputStream(data, offset, len)) {
-            upload(local, remote, len, perms, time);
-        }
-    }
-
-    void upload(InputStream local, String remote, long size, Collection<PosixFilePermission> perms, ScpTimestamp time) throws IOException;
-
-    static String createSendCommand(String remote, Collection<Option> options) {
-        StringBuilder sb = new StringBuilder(remote.length() + Long.SIZE).append(ScpHelper.SCP_COMMAND_PREFIX);
-        if (options.contains(Option.Recursive)) {
-            sb.append(" -r");
-        }
-        if (options.contains(Option.TargetIsDirectory)) {
-            sb.append(" -d");
-        }
-        if (options.contains(Option.PreserveAttributes)) {
-            sb.append(" -p");
-        }
-
-        sb.append(" -t").append(" --").append(" ").append(remote);
-        return sb.toString();
-    }
-
-    static String createReceiveCommand(String remote, Collection<Option> options) {
-        ValidateUtils.checkNotNullAndNotEmpty(remote, "No remote location specified");
-        StringBuilder sb = new StringBuilder(remote.length() + Long.SIZE).append(ScpHelper.SCP_COMMAND_PREFIX);
-        if (options.contains(Option.Recursive)) {
-            sb.append(" -r");
-        }
-        if (options.contains(Option.PreserveAttributes)) {
-            sb.append(" -p");
-        }
-
-        sb.append(" -f").append(" --").append(' ').append(remote);
-        return sb.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java
deleted file mode 100644
index 8ae54a4..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/ScpClientCreator.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.client.scp;
-
-import org.apache.sshd.common.scp.ScpFileOpener;
-import org.apache.sshd.common.scp.ScpFileOpenerHolder;
-import org.apache.sshd.common.scp.ScpTransferEventListener;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface ScpClientCreator extends ScpFileOpenerHolder {
-    /**
-     * Create an SCP client from this session.
-     *
-     * @return An {@link ScpClient} instance. <B>Note:</B> uses the currently
-     * registered {@link ScpTransferEventListener} and {@link ScpFileOpener} if any
-     * @see #setScpFileOpener(ScpFileOpener)
-     * @see #setScpTransferEventListener(ScpTransferEventListener)
-     */
-    default ScpClient createScpClient() {
-        return createScpClient(getScpFileOpener(), getScpTransferEventListener());
-    }
-
-    /**
-     * Create an SCP client from this session.
-     *
-     * @param listener A {@link ScpTransferEventListener} that can be used
-     * to receive information about the SCP operations - may be {@code null}
-     * to indicate no more events are required. <B>Note:</B> this listener
-     * is used <U>instead</U> of any listener set via {@link #setScpTransferEventListener(ScpTransferEventListener)}
-     * @return An {@link ScpClient} instance
-     */
-    default ScpClient createScpClient(ScpTransferEventListener listener) {
-        return createScpClient(getScpFileOpener(), listener);
-    }
-
-    /**
-     * Create an SCP client from this session.
-     *
-     * @param opener The {@link ScpFileOpener} to use to control how local files
-     * are read/written. If {@code null} then a default opener is used.
-     * <B>Note:</B> this opener is used <U>instead</U> of any instance
-     * set via {@link #setScpFileOpener(ScpFileOpener)}
-     * @return An {@link ScpClient} instance
-     */
-    default ScpClient createScpClient(ScpFileOpener opener) {
-        return createScpClient(opener, getScpTransferEventListener());
-    }
-
-    /**
-     * Create an SCP client from this session.
-     *
-     * @param opener   The {@link ScpFileOpener} to use to control how local files
-     *                 are read/written. If {@code null} then a default opener is used.
-     *                 <B>Note:</B> this opener is used <U>instead</U> of any instance
-     *                 set via {@link #setScpFileOpener(ScpFileOpener)}
-     * @param listener A {@link ScpTransferEventListener} that can be used
-     *                 to receive information about the SCP operations - may be {@code null}
-     *                 to indicate no more events are required. <B>Note:</B> this listener
-     *                 is used <U>instead</U> of any listener set via
-     *                 {@link #setScpTransferEventListener(ScpTransferEventListener)}
-     * @return An {@link ScpClient} instance
-     */
-    ScpClient createScpClient(ScpFileOpener opener, ScpTransferEventListener listener);
-
-    /**
-     * @return The last {@link ScpTransferEventListener} set via
-     * {@link #setScpTransferEventListener(ScpTransferEventListener)}
-     */
-    ScpTransferEventListener getScpTransferEventListener();
-
-    /**
-     * @param listener A default {@link ScpTransferEventListener} that can be used
-     *                 to receive information about the SCP operations - may be {@code null}
-     *                 to indicate no more events are required
-     * @see #createScpClient(ScpTransferEventListener)
-     */
-    void setScpTransferEventListener(ScpTransferEventListener listener);
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
index d57a799..1cb309a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/AbstractClientSession.java
@@ -40,8 +40,6 @@ import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.channel.ChannelSubsystem;
 import org.apache.sshd.client.channel.ClientChannel;
 import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
-import org.apache.sshd.client.scp.DefaultScpClient;
-import org.apache.sshd.client.scp.ScpClient;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
@@ -59,8 +57,6 @@ import org.apache.sshd.common.io.IoSession;
 import org.apache.sshd.common.io.IoWriteFuture;
 import org.apache.sshd.common.kex.KexProposalOption;
 import org.apache.sshd.common.kex.KexState;
-import org.apache.sshd.common.scp.ScpFileOpener;
-import org.apache.sshd.common.scp.ScpTransferEventListener;
 import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.session.helpers.AbstractConnectionService;
@@ -82,8 +78,6 @@ public abstract class AbstractClientSession extends AbstractSession implements C
     private UserInteraction userInteraction;
     private PasswordIdentityProvider passwordIdentityProvider;
     private List<NamedFactory<UserAuth>> userAuthFactories;
-    private ScpTransferEventListener scpListener;
-    private ScpFileOpener scpOpener;
     private SocketAddress connectAddress;
     private ClientProxyConnector proxyConnector;
 
@@ -301,31 +295,6 @@ public abstract class AbstractClientSession extends AbstractSession implements C
     }
 
     @Override
-    public ScpFileOpener getScpFileOpener() {
-        return resolveEffectiveProvider(ScpFileOpener.class, scpOpener, getFactoryManager().getScpFileOpener());
-    }
-
-    @Override
-    public void setScpFileOpener(ScpFileOpener opener) {
-        scpOpener = opener;
-    }
-
-    @Override
-    public ScpTransferEventListener getScpTransferEventListener() {
-        return scpListener;
-    }
-
-    @Override
-    public void setScpTransferEventListener(ScpTransferEventListener listener) {
-        scpListener = listener;
-    }
-
-    @Override
-    public ScpClient createScpClient(ScpFileOpener opener, ScpTransferEventListener listener) {
-        return new DefaultScpClient(this, opener, listener);
-    }
-
-    @Override
     public SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, SshdSocketAddress remote) throws IOException {
         ForwardingFilter filter = getForwardingFilter();
         return filter.startLocalPortForwarding(local, remote);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
index 96caf2e..1d68a20 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
@@ -42,7 +42,6 @@ import org.apache.sshd.client.channel.ChannelSubsystem;
 import org.apache.sshd.client.channel.ClientChannel;
 import org.apache.sshd.client.channel.ClientChannelEvent;
 import org.apache.sshd.client.future.AuthFuture;
-import org.apache.sshd.client.scp.ScpClientCreator;
 import org.apache.sshd.client.session.forward.DynamicPortForwardingTracker;
 import org.apache.sshd.client.session.forward.ExplicitPortForwardingTracker;
 import org.apache.sshd.common.forward.PortForwardingManager;
@@ -81,9 +80,8 @@ import org.apache.sshd.common.util.net.SshdSocketAddress;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public interface ClientSession
-            extends Session, ScpClientCreator,
-            ClientProxyConnectorHolder, ClientAuthenticationManager,
-            PortForwardingManager {
+            extends Session, ClientProxyConnectorHolder,
+            ClientAuthenticationManager, PortForwardingManager {
     enum ClientSessionEvent {
         TIMEOUT,
         CLOSED,

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/simple/AbstractSimpleClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/simple/AbstractSimpleClient.java b/sshd-core/src/main/java/org/apache/sshd/client/simple/AbstractSimpleClient.java
index 247be60..dc5ef87 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/simple/AbstractSimpleClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/simple/AbstractSimpleClient.java
@@ -19,19 +19,6 @@
 
 package org.apache.sshd.client.simple;
 
-import java.io.IOException;
-import java.lang.reflect.Proxy;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.security.KeyPair;
-import java.util.Objects;
-
-import org.apache.sshd.client.scp.CloseableScpClient;
-import org.apache.sshd.client.scp.ScpClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 
 /**
@@ -41,97 +28,4 @@ public abstract class AbstractSimpleClient extends AbstractLoggingBean implement
     protected AbstractSimpleClient() {
         super();
     }
-
-    @Override
-    public CloseableScpClient scpLogin(String host, String username, String password) throws IOException {
-        return scpLogin(host, DEFAULT_PORT, username, password);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(String host, int port, String username, String password) throws IOException {
-        return scpLogin(InetAddress.getByName(ValidateUtils.checkNotNullAndNotEmpty(host, "No host")), port, username, password);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(String host, String username, KeyPair identity) throws IOException {
-        return scpLogin(host, DEFAULT_PORT, username, identity);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(String host, int port, String username, KeyPair identity) throws IOException {
-        return scpLogin(InetAddress.getByName(ValidateUtils.checkNotNullAndNotEmpty(host, "No host")), port, username, identity);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(InetAddress host, String username, String password) throws IOException {
-        return scpLogin(host, DEFAULT_PORT, username, password);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(InetAddress host, int port, String username, String password) throws IOException {
-        return scpLogin(new InetSocketAddress(Objects.requireNonNull(host, "No host address"), port), username, password);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(InetAddress host, String username, KeyPair identity) throws IOException {
-        return scpLogin(host, DEFAULT_PORT, username, identity);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(InetAddress host, int port, String username, KeyPair identity) throws IOException {
-        return scpLogin(new InetSocketAddress(Objects.requireNonNull(host, "No host address"), port), username, identity);
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(SocketAddress target, String username, String password) throws IOException {
-        return createScpClient(sessionLogin(target, username, password));
-    }
-
-    @Override
-    public CloseableScpClient scpLogin(SocketAddress target, String username, KeyPair identity) throws IOException {
-        return createScpClient(sessionLogin(target, username, identity));
-    }
-
-    protected CloseableScpClient createScpClient(ClientSession session) throws IOException {
-        try {
-            ScpClient client = Objects.requireNonNull(session, "No client session").createScpClient();
-            ClassLoader loader = getClass().getClassLoader();
-            Class<?>[] interfaces = {CloseableScpClient.class};
-            return (CloseableScpClient) Proxy.newProxyInstance(loader, interfaces, (proxy, method, args) -> {
-                String name = method.getName();
-                try {
-                    // The Channel implementation is provided by the session
-                    if (("close".equals(name) || "isOpen".equals(name)) && GenericUtils.isEmpty(args)) {
-                        return method.invoke(session, args);
-                    } else {
-                        return method.invoke(client, args);
-                    }
-                } catch (Throwable t) {
-                    if (log.isTraceEnabled()) {
-                        log.trace("invoke(CloseableScpClient#{}) failed ({}) to execute: {}",
-                                  name, t.getClass().getSimpleName(), t.getMessage());
-                    }
-                    throw t;
-                }
-            });
-        } catch (Exception e) {
-            log.warn("createScpClient({}) failed ({}) to create proxy: {}",
-                     session, e.getClass().getSimpleName(), e.getMessage());
-            try {
-                session.close();
-            } catch (Exception t) {
-                if (log.isDebugEnabled()) {
-                    log.debug("createScpClient({}) failed ({}) to close session: {}",
-                              session, t.getClass().getSimpleName(), t.getMessage());
-                }
-
-                if (log.isTraceEnabled()) {
-                    log.trace("createScpClient(" + session + ") session close failure details", t);
-                }
-                e.addSuppressed(t);
-            }
-
-            throw GenericUtils.toIOException(e);
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleClient.java b/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleClient.java
index 6fff133..174f600 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleClient.java
@@ -31,7 +31,6 @@ import java.nio.channels.Channel;
 public interface SimpleClient
         extends SimpleClientConfigurator,
                 SimpleSessionClient,
-                SimpleScpClient,
                 Channel {
     // marker interface
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/af415e5f/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleScpClient.java
deleted file mode 100644
index eeeb7a2..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/simple/SimpleScpClient.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.sshd.client.simple;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.SocketAddress;
-import java.nio.channels.Channel;
-import java.security.KeyPair;
-
-import org.apache.sshd.client.scp.CloseableScpClient;
-
-/**
- * A simplified <U>synchronous</U> API for obtaining SCP sessions.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface SimpleScpClient extends SimpleClientConfigurator, Channel {
-    /**
-     * Creates an SCP session on the default port and logs in using the provided credentials
-     *
-     * @param host The target host name or address
-     * @param username Username
-     * @param password Password
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(String host, String username, String password) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param host The target host name or address
-     * @param port The target port
-     * @param username Username
-     * @param password Password
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(String host, int port, String username, String password) throws IOException;
-
-    /**
-     * Creates an SCP session on the default port and logs in using the provided credentials
-     *
-     * @param host The target host name or address
-     * @param username Username
-     * @param identity The {@link KeyPair} identity
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(String host, String username, KeyPair identity) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param host The target host name or address
-     * @param port The target port
-     * @param username Username
-     * @param identity The {@link KeyPair} identity
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(String host, int port, String username, KeyPair identity) throws IOException;
-
-    /**
-     * Creates an SCP session on the default port and logs in using the provided credentials
-     *
-     * @param host The target host {@link InetAddress}
-     * @param username Username
-     * @param password Password
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(InetAddress host, String username, String password) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param host The target host {@link InetAddress}
-     * @param port The target port
-     * @param username Username
-     * @param password Password
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(InetAddress host, int port, String username, String password) throws IOException;
-
-    /**
-     * Creates an SCP session on the default port and logs in using the provided credentials
-     *
-     * @param host The target host {@link InetAddress}
-     * @param username Username
-     * @param identity The {@link KeyPair} identity
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(InetAddress host, String username, KeyPair identity) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param host The target host {@link InetAddress}
-     * @param port The target port
-     * @param username Username
-     * @param identity The {@link KeyPair} identity
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(InetAddress host, int port, String username, KeyPair identity) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param target The target {@link SocketAddress}
-     * @param username Username
-     * @param password Password
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(SocketAddress target, String username, String password) throws IOException;
-
-    /**
-     * Creates an SCP session using the provided credentials
-     *
-     * @param target The target {@link SocketAddress}
-     * @param username Username
-     * @param identity The {@link KeyPair} identity
-     * @return Created {@link CloseableScpClient} - <B>Note:</B> closing the client also closes its
-     * underlying session
-     * @throws IOException If failed to login or authenticate
-     */
-    CloseableScpClient scpLogin(SocketAddress target, String username, KeyPair identity) throws IOException;
-}