This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git


The following commit(s) were added to refs/heads/master by this push:
     new cb58ab6  [SSHD-913] Provide channel session instance to command and/or 
shell factories creators
cb58ab6 is described below

commit cb58ab67cdf75d23e6d7d59e8c072f6453aabf48
Author: Lyor Goldstein <[email protected]>
AuthorDate: Thu May 2 21:28:45 2019 +0300

    [SSHD-913] Provide channel session instance to command and/or shell 
factories creators
---
 CHANGES.md                                         |  5 +++
 .../org/apache/sshd/cli/server/SshFsMounter.java   |  7 ++--
 .../common/config/keys/KeyTypeNamesSupport.java    |  1 +
 .../common/kex/extension/KexExtensionParser.java   |  1 +
 .../parser/AbstractKexExtensionParser.java         |  1 +
 .../common/kex/extension/parser/NoFlowControl.java |  2 +-
 .../org/apache/sshd/common/util/buffer/Buffer.java |  4 +-
 .../sshd/common/util/functors/UnaryEquator.java    |  4 +-
 .../sshd/common/util/io/DirectoryScanner.java      |  5 ++-
 .../main/java/org/apache/sshd/server/Signal.java   |  3 --
 .../org/apache/sshd/common/FactoryManager.java     |  2 +-
 .../common/kex/extension/KexExtensionHandler.java  | 10 ++---
 .../apache/sshd/server/ServerFactoryManager.java   |  8 ++--
 .../java/org/apache/sshd/server/SshServer.java     |  7 ++--
 .../apache/sshd/server/channel/ChannelSession.java | 27 ++++++++------
 .../server/command/AbstractCommandSupport.java     |  9 +++--
 .../command/AbstractDelegatingCommandFactory.java  |  7 +++-
 .../server/command/AbstractFileSystemCommand.java  |  5 ++-
 .../apache/sshd/server/command/CommandFactory.java | 12 ++++--
 .../sshd/server/command/CommandLifecycle.java      |  9 ++++-
 .../shell/InteractiveProcessShellFactory.java      |  3 +-
 .../apache/sshd/server/shell/InvertedShell.java    |  7 ++++
 .../sshd/server/shell/InvertedShellWrapper.java    | 21 ++++++-----
 .../org/apache/sshd/server/shell/ProcessShell.java | 23 +++++++++---
 .../server/shell/ProcessShellCommandFactory.java   | 10 +++--
 .../sshd/server/shell/ProcessShellFactory.java     | 13 ++++---
 .../org/apache/sshd/server/shell/ShellFactory.java | 17 +++++++--
 .../apache/sshd/server/shell/UnknownCommand.java   |  5 ++-
 .../sshd/server/shell/UnknownCommandFactory.java   |  3 +-
 .../test/java/org/apache/sshd/KeepAliveTest.java   |  7 ++--
 .../java/org/apache/sshd/KeyReExchangeTest.java    |  5 ++-
 .../java/org/apache/sshd/WindowAdjustTest.java     | 15 +++++---
 .../test/java/org/apache/sshd/agent/AgentTest.java |  7 ++--
 .../java/org/apache/sshd/client/ClientTest.java    |  6 +--
 .../sshd/client/channel/ChannelExecTest.java       |  2 +-
 .../sshd/client/session/ClientSessionTest.java     |  6 +--
 .../org/apache/sshd/common/SshBuilderTest.java     |  2 +-
 .../org/apache/sshd/common/channel/WindowTest.java |  6 +--
 .../java/org/apache/sshd/server/ServerTest.java    | 25 +++++++------
 .../sshd/server/channel/ChannelSessionTest.java    |  2 +-
 .../server/shell/InvertedShellWrapperTest.java     | 43 +++++++++++++++-------
 .../sshd/util/test/AsyncEchoShellFactory.java      |  8 ++--
 .../apache/sshd/util/test/BogusInvertedShell.java  | 12 +++++-
 .../apache/sshd/util/test/EchoShellFactory.java    |  3 +-
 .../org/apache/sshd/git/AbstractGitCommand.java    |  3 +-
 .../org/apache/sshd/git/pack/GitPackCommand.java   |  9 +++--
 .../org/apache/sshd/git/pgm/GitPgmCommand.java     |  9 +++--
 .../org/apache/sshd/server/scp/ScpCommand.java     |  9 +++--
 .../java/org/apache/sshd/client/scp/ScpTest.java   |  3 +-
 .../sshd/server/subsystem/sftp/SftpSubsystem.java  |  4 +-
 .../sshd/client/subsystem/sftp/ClientTest.java     |  6 +--
 51 files changed, 265 insertions(+), 158 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 1a97a69..273852b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -40,6 +40,9 @@ to override the internal default ones.
 * The `ScpFileOpener` methods are also invoked in order to close input/output 
streams created through it
 when they are no longer needed once data has been successfully copied.
 
+* The `CommandFactory` and `ShellFactory` have been modified to accept the 
server's `ChannelSession` instance through
+which they are being invoked.
+
 ## Minor code helpers
 
 * The `Session` object provides a `isServerSession` method that can be used to 
distinguish between
@@ -122,3 +125,5 @@ in order to avoid client-side session timeout due to no 
traffic from server.
 and therefore closing all currently tracked file/directory handles.
 
 * [SSHD-909](https://issues.apache.org/jira/browse/SSHD-909) - SFTP versions 
extension handler ignores non-numerical versions when resolving the available 
ones.
+
+* [SSHD-913](https://issues.apache.org/jira/browse/SSHD-913) - Provide channel 
session instance to command and/or shell factories creators     
\ No newline at end of file
diff --git 
a/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java 
b/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
index a7ddba3..d75ab14 100644
--- a/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
+++ b/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
@@ -49,6 +49,7 @@ import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SessionAware;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
@@ -158,13 +159,13 @@ public final class SshFsMounter extends 
SshServerCliSupport {
         }
 
         @Override
-        public void start(Environment env) throws IOException {
+        public void start(ChannelSession channel, Environment env) throws 
IOException {
             executor = 
ThreadUtils.newSingleThreadExecutor(getClass().getSimpleName());
             future = executor.submit(this);
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) {
             stopCommand();
 
             if (stdout != null) {
@@ -239,7 +240,7 @@ public final class SshFsMounter extends SshServerCliSupport 
{
         }
 
         @Override
-        public Command createCommand(String command) {
+        public Command createCommand(ChannelSession channel, String command) {
             return new MounterCommand(command);
         }
     }
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyTypeNamesSupport.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyTypeNamesSupport.java
index fd7c7ba..c9cee51 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyTypeNamesSupport.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/KeyTypeNamesSupport.java
@@ -41,6 +41,7 @@ public interface KeyTypeNamesSupport {
     NavigableSet<String> getSupportedKeyTypes();
 
     /**
+     * @param <S> Generic supporter type
      * @param typeName The {@code OpenSSH} key type  e.g., {@code ssh-rsa, 
ssh-dss, ecdsa-sha2-nistp384}.
      * Ignored if {@code null}/empty.
      * @param supporters The {@link KeyTypeNamesSupport}-ers to query - 
ignored if {@code null}/empty.
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionParser.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionParser.java
index 6f70960..bc02804 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionParser.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionParser.java
@@ -28,6 +28,7 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 /**
  * Parses a known KEX extension
  *
+ * @param <T> Extension generic type
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
  */
 public interface KexExtensionParser<T> extends NamedResource {
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/AbstractKexExtensionParser.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/AbstractKexExtensionParser.java
index 75265f7..798e078 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/AbstractKexExtensionParser.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/AbstractKexExtensionParser.java
@@ -26,6 +26,7 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 
 /**
+ * @param <T> Generic extension type
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
  */
 public abstract class AbstractKexExtensionParser<T> implements 
KexExtensionParser<T> {
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/NoFlowControl.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/NoFlowControl.java
index 259adae..baf4067 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/NoFlowControl.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/kex/extension/parser/NoFlowControl.java
@@ -26,7 +26,7 @@ import org.apache.sshd.common.util.buffer.Buffer;
 
 /**
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
- * @see <A HREF="">https://tools.ietf.org/html/rfc8308#section-3.3";>RFC-8308 - 
section 3.3</A>
+ * @see <A HREF="https://tools.ietf.org/html/rfc8308#section-3.3";>RFC-8308 - 
section 3.3</A>
  */
 public class NoFlowControl extends AbstractKexExtensionParser<String> {
     public static final String NAME = "no-flow-control";
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java 
b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index 5afa514..ee2901f 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -745,9 +745,11 @@ public abstract class Buffer implements Readable {
 
     /**
      * According to <A HREF="https://tools.ietf.org/html/rfc4251#page-10";>RFC 
4251</A>:
-     *
+     * <CODE>
      *      A name-list is represented as a uint32 containing its length 
(number of bytes
      *      that follow) followed by a comma-separated list of zero or more 
names.
+     * </CODE>
+     * @param names The name list to put
      */
     public void putNameList(Collection<String> names) {
         putNameList(names, StandardCharsets.UTF_8);
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/functors/UnaryEquator.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/functors/UnaryEquator.java
index 4834065..ac91c10 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/util/functors/UnaryEquator.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/functors/UnaryEquator.java
@@ -71,7 +71,7 @@ public interface UnaryEquator<T> extends BiPredicate<T, T> {
     /**
      * @param <T> Type of entity
      * @return The default equality checker
-     * @see EqualityUtils#isEqualValue(Object, Object)
+     * @see Objects#equals(Object, Object)
      */
     static <T> UnaryEquator<T> defaultEquality() {
         return Objects::equals;
@@ -80,7 +80,7 @@ public interface UnaryEquator<T> extends BiPredicate<T, T> {
     /**
      * @param <T> Type of entity
      * @return An equator that checks reference equality
-     * @see EqualityUtils#isSameReference(Object, Object)
+     * @see GenericUtils#isSameReference(Object, Object)
      */
     static <T> UnaryEquator<T> referenceEquality() {
         return GenericUtils::isSameReference;
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
index 9758fac..0feb494 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/io/DirectoryScanner.java
@@ -258,11 +258,12 @@ public class DirectoryScanner {
      * is found, it is scanned recursively.
      *
      * @param <C> Target matches collection type
-     * @param dir The directory to scan. Must not be {@code null}.
-     * @param vpath The path relative to the base directory (needed to prevent
+     * @param rootDir The directory to scan. Must not be {@code null}.
+     * @param dir The path relative to the root directory (needed to prevent
      * problems with an absolute path when using <tt>dir</tt>). Must not be 
{@code null}.
      * @param filesList Target {@link Collection} to accumulate the relative
      * path matches
+     * @return Updated files list
      * @throws IOException if failed to scan the directory
      */
     protected <C extends Collection<Path>> C scandir(Path rootDir, Path dir, C 
filesList) throws IOException {
diff --git a/sshd-common/src/main/java/org/apache/sshd/server/Signal.java 
b/sshd-common/src/main/java/org/apache/sshd/server/Signal.java
index 79f2eef..1b22474 100644
--- a/sshd-common/src/main/java/org/apache/sshd/server/Signal.java
+++ b/sshd-common/src/main/java/org/apache/sshd/server/Signal.java
@@ -29,11 +29,8 @@ import org.apache.sshd.common.util.GenericUtils;
 
 /**
  * System signals definition that the shell can receive.
- *
- * @see Environment
  */
 public enum Signal {
-
     HUP(1),
     INT(2),
     QUIT(3),
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java 
b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
index a6c599c..02ea05a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java
@@ -263,7 +263,7 @@ public interface FactoryManager
     String NIO2_READ_BUFFER_SIZE = "nio2-read-buf-size";
 
     /**
-     * The default {@value #REPORTED_VERSION} of {@link #getVersion()} if the 
built-in
+     * The default {@code REPORTED_VERSION} of {@link #getVersion()} if the 
built-in
      * version information cannot be accessed
      */
     String DEFAULT_VERSION = "SSHD-UNKNOWN";
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionHandler.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionHandler.java
index d3d9326..5859572 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionHandler.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/kex/extension/KexExtensionHandler.java
@@ -79,7 +79,7 @@ public interface KexExtensionHandler {
     /**
      * Invoked when a peer is ready to send the KEX options proposal or has 
received
      * such a proposal. <B>Note:</B> this method is called during the 
negotiation phase
-     * even if {@link #isKexExtensionsAvailable(Session)} returns {@code 
false} for the session.
+     * even if {@code isKexExtensionsAvailable} returns {@code false} for the 
session.
      *
      * @param session The {@link Session} initiating or receiving the proposal
      * @param initiator {@code true} if the proposal is about to be sent, 
{@code false}
@@ -98,7 +98,7 @@ public interface KexExtensionHandler {
     /**
      * Invoked during the KEX negotiation phase to inform about option
      * being negotiated. <B>Note:</B> this method is called during the
-     * negotiation phase even if {@link #isKexExtensionsAvailable(Session)}
+     * negotiation phase even if {@code isKexExtensionsAvailable}
      * returns {@code false} for the session.
      *
      * @param session The {@link Session} executing the negotiation
@@ -132,7 +132,7 @@ public interface KexExtensionHandler {
 
     /**
      * Invoked in order to allow the handler to send an {@code 
SSH_MSG_EXT_INFO} message.
-     * <B>Note:</B> this method is called only if {@link 
#isKexExtensionsAvailable(Session)}
+     * <B>Note:</B> this method is called only if {@code 
isKexExtensionsAvailable}
      * returns {@code true} for the session.
      * @param session The {@link Session}
      * @param phase The phase at which the handler is invoked
@@ -145,7 +145,7 @@ public interface KexExtensionHandler {
 
     /**
      * Parses the {@code SSH_MSG_EXT_INFO} message. <B>Note:</B> this method
-     * is called regardless of whether {@link 
#isKexExtensionsAvailable(Session)} returns
+     * is called regardless of whether {@code isKexExtensionsAvailable} returns
      * {@code true} for the session.
      *
      * @param session The {@link Session} through which the message was 
received
@@ -171,7 +171,7 @@ public interface KexExtensionHandler {
 
     /**
      * Parses the {@code SSH_MSG_NEWCOMPRESS} message. <B>Note:</B> this method
-     * is called regardless of whether {@link 
#isKexExtensionsAvailable(Session)} returns
+     * is called regardless of whether {@code isKexExtensionsAvailable} returns
      * {@code true} for the session.
      *
      * @param session The {@link Session} through which the message was 
received
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java 
b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index 7992f61..6ea4586 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -21,12 +21,12 @@ package org.apache.sshd.server;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.session.ServerProxyAcceptorHolder;
+import org.apache.sshd.server.shell.ShellFactory;
 
 /**
  * The <code>ServerFactoryManager</code> enable the retrieval of additional
@@ -88,12 +88,12 @@ public interface ServerFactoryManager
     String MODULI_URL = "moduli-url";
 
     /**
-     * Retrieve the <code>ShellFactory</code> object to be used to create 
shells.
+     * Retrieve the {@link ShellFactory} object to be used to create shells.
      *
-     * @return a valid <code>ShellFactory</code> object or {@code null} if 
shells
+     * @return a valid {@link ShellFactory} object or {@code null} if shells
      * are not supported on this server
      */
-    Factory<Command> getShellFactory();
+    ShellFactory getShellFactory();
 
     /**
      * Retrieve the <code>CommandFactory</code> to be used to process commands 
requests.
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java 
b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index ef129f7..05da391 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -56,6 +56,7 @@ import 
org.apache.sshd.server.session.ServerConnectionServiceFactory;
 import org.apache.sshd.server.session.ServerProxyAcceptor;
 import org.apache.sshd.server.session.ServerUserAuthServiceFactory;
 import org.apache.sshd.server.session.SessionFactory;
+import org.apache.sshd.server.shell.ShellFactory;
 
 /**
  * <p>
@@ -99,7 +100,7 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
     protected int port;
 
     private ServerProxyAcceptor proxyAcceptor;
-    private Factory<Command> shellFactory;
+    private ShellFactory shellFactory;
     private SessionFactory sessionFactory;
     private CommandFactory commandFactory;
     private List<NamedFactory<Command>> subsystemFactories;
@@ -156,11 +157,11 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
     }
 
     @Override
-    public Factory<Command> getShellFactory() {
+    public ShellFactory getShellFactory() {
         return shellFactory;
     }
 
-    public void setShellFactory(Factory<Command> shellFactory) {
+    public void setShellFactory(ShellFactory shellFactory) {
         this.shellFactory = shellFactory;
     }
 
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java 
b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 2c2f6bd..906d0a5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -34,7 +34,6 @@ import org.apache.sshd.agent.SshAgent;
 import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.agent.common.AgentForwardSupport;
 import org.apache.sshd.common.Closeable;
-import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.PropertyResolverUtils;
@@ -74,6 +73,7 @@ import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.forward.AgentForwardingFilter;
 import org.apache.sshd.server.forward.X11ForwardingFilter;
 import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.shell.ShellFactory;
 import org.apache.sshd.server.x11.X11ForwardSupport;
 
 /**
@@ -205,7 +205,7 @@ public class ChannelSession extends AbstractServerChannel {
         boolean debugEnabled = log.isDebugEnabled();
         if (commandInstance != null) {
             try {
-                commandInstance.destroy();
+                commandInstance.destroy(this);
             } catch (Throwable e) {
                 log.warn("doCloseImmediately({}) failed ({}) to destroy 
command: {}",
                      this, e.getClass().getSimpleName(), e.getMessage());
@@ -217,7 +217,8 @@ public class ChannelSession extends AbstractServerChannel {
             }
         }
 
-        IOException e = IoUtils.closeQuietly(getRemoteWindow(), out, err, 
receiver, extendedDataWriter);
+        IOException e =
+            IoUtils.closeQuietly(getRemoteWindow(), out, err, receiver, 
extendedDataWriter);
         if (e != null) {
             if (debugEnabled) {
                 log.debug("doCloseImmediately({}) failed ({}) to close 
resources: {}",
@@ -400,7 +401,7 @@ public class ChannelSession extends AbstractServerChannel {
         if (log.isDebugEnabled()) {
             log.debug("sendResponse({}) request={} activate command", this, 
req);
         }
-        commandInstance.start(getEnvironment());
+        commandInstance.start(this, getEnvironment());
         return future;
     }
 
@@ -513,8 +514,9 @@ public class ChannelSession extends AbstractServerChannel {
             return RequestHandler.Result.ReplyFailure;
         }
 
-        ServerFactoryManager manager = 
Objects.requireNonNull(getServerSession(), "No server 
session").getFactoryManager();
-        Factory<Command> factory = Objects.requireNonNull(manager, "No server 
factory manager").getShellFactory();
+        ServerSession shellSession = 
Objects.requireNonNull(getServerSession(), "No server session");
+        ServerFactoryManager manager = shellSession.getFactoryManager();
+        ShellFactory factory = Objects.requireNonNull(manager, "No server 
factory manager").getShellFactory();
         if (factory == null) {
             if (log.isDebugEnabled()) {
                 log.debug("handleShell({}) - no shell factory", this);
@@ -523,8 +525,8 @@ public class ChannelSession extends AbstractServerChannel {
         }
 
         try {
-            commandInstance = factory.create();
-        } catch (RuntimeException | Error e) {
+            commandInstance = factory.createShell(this);
+        } catch (RuntimeException | IOException | Error e) {
             log.warn("handleShell({}) Failed ({}) to create shell: {}",
                  this, e.getClass().getSimpleName(), e.getMessage());
             if (log.isDebugEnabled()) {
@@ -550,7 +552,8 @@ public class ChannelSession extends AbstractServerChannel {
         }
 
         String commandLine = buffer.getString();
-        ServerFactoryManager manager = 
Objects.requireNonNull(getServerSession(), "No server 
session").getFactoryManager();
+        ServerSession cmdSession = Objects.requireNonNull(getServerSession(), 
"No server session");
+        ServerFactoryManager manager = cmdSession.getFactoryManager();
         CommandFactory factory = Objects.requireNonNull(manager, "No server 
factory manager").getCommandFactory();
         if (factory == null) {
             log.warn("handleExec({}) No command factory for command: {}", 
this, commandLine);
@@ -563,8 +566,8 @@ public class ChannelSession extends AbstractServerChannel {
         }
 
         try {
-            commandInstance = factory.createCommand(commandLine);
-        } catch (RuntimeException | Error e) {
+            commandInstance = factory.createCommand(this, commandLine);
+        } catch (RuntimeException | IOException | Error e) {
             log.warn("handleExec({}) Failed ({}) to create command for {}: {}",
                  this, e.getClass().getSimpleName(), commandLine, 
e.getMessage());
             if (debugEnabled) {
@@ -639,7 +642,7 @@ public class ChannelSession extends AbstractServerChannel {
      * For {@link Command} to install {@link ChannelDataReceiver}.
      * When you do this, {@link Command#setInputStream(java.io.InputStream)} or
      * {@link 
org.apache.sshd.server.command.AsyncCommand#setIoInputStream(org.apache.sshd.common.io.IoInputStream)}
-     * will no longer be invoked. If you call this method from {@link 
Command#start(Environment)},
+     * will no longer be invoked. If you call this method from {@code 
Command#start(ChannelSession, Environment)},
      * the input stream you received in {@link 
Command#setInputStream(java.io.InputStream)} will
      * not read any data.
      *
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
index 54b6ffd..67a636a 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
@@ -35,6 +35,7 @@ import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionHolder;
 
@@ -63,7 +64,9 @@ public abstract class AbstractCommandSupport
         this.command = command;
 
         if (executorService == null) {
-            String poolName = GenericUtils.isEmpty(command) ? 
getClass().getSimpleName() : command.replace(' ', '_').replace('/', ':');
+            String poolName = GenericUtils.isEmpty(command)
+                ? getClass().getSimpleName()
+                : command.replace(' ', '_').replace('/', ':');
             this.executorService = 
ThreadUtils.newSingleThreadExecutor(poolName);
         } else {
             this.executorService = executorService;
@@ -139,7 +142,7 @@ public abstract class AbstractCommandSupport
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
         environment = env;
         try {
             CloseableExecutorService executors = getExecutorService();
@@ -154,7 +157,7 @@ public abstract class AbstractCommandSupport
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) throws Exception {
         // if thread has not completed, cancel it
         boolean debugEnabled = log.isDebugEnabled();
         if ((cmdFuture != null) && (!cmdFuture.isDone()) && (cmdRunner != 
Thread.currentThread())) {
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
index 6005038..7334210 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
@@ -19,8 +19,11 @@
 
 package org.apache.sshd.server.command;
 
+import java.io.IOException;
+
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.server.channel.ChannelSession;
 
 /**
  * TODO Add javadoc
@@ -53,14 +56,14 @@ public abstract class AbstractDelegatingCommandFactory 
extends AbstractLoggingBe
     }
 
     @Override
-    public Command createCommand(String command) {
+    public Command createCommand(ChannelSession channel, String command) 
throws IOException {
         if (isSupportedCommand(command)) {
             return executeSupportedCommand(command);
         }
 
         CommandFactory factory = getDelegateCommandFactory();
         if (factory != null) {
-            return factory.createCommand(command);
+            return factory.createCommand(channel, command);
         }
 
         return createUnsupportedCommand(command);
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractFileSystemCommand.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractFileSystemCommand.java
index be5e578..ff330ed 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractFileSystemCommand.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractFileSystemCommand.java
@@ -24,6 +24,7 @@ import java.nio.file.FileSystem;
 
 import org.apache.sshd.common.file.FileSystemAware;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
+import org.apache.sshd.server.channel.ChannelSession;
 
 /**
  * Provides a basic useful skeleton for {@link Command} executions that 
require file system access
@@ -48,9 +49,9 @@ public abstract class AbstractFileSystemCommand extends 
AbstractCommandSupport i
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) throws Exception {
         try {
-            super.destroy();
+            super.destroy(channel);
         } finally {
             if (fileSystem != null) {
                 try {
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java 
b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java
index 807add1..f86d46c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java
@@ -18,9 +18,12 @@
  */
 package org.apache.sshd.server.command;
 
+import java.io.IOException;
+
+import org.apache.sshd.server.channel.ChannelSession;
+
 /**
- * A factory of commands.
- * Commands are executed on the server side when an "exec" channel is
+ * Commands are executed on the server side when an &quot;exec&quot; channel is
  * requested by the SSH client.
  *
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
@@ -33,8 +36,11 @@ public interface CommandFactory {
      * If the command is not known, a dummy command should be returned to allow
      * the display output to be sent back to the client.
      *
+     * @param channel The {@link ChannelSession} through which the command has 
been
+     * received
      * @param command The command that will be run
      * @return a non {@code null} {@link Command} instance
+     * @throws IOException if failed to create the instance
      */
-    Command createCommand(String command);
+    Command createCommand(ChannelSession channel, String command) throws 
IOException;
 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java 
b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java
index ac694d5..4e0b39a 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java
@@ -22,6 +22,7 @@ package org.apache.sshd.server.command;
 import java.io.IOException;
 
 import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.channel.ChannelSession;
 
 /**
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
@@ -35,16 +36,20 @@ public interface CommandLifecycle {
      * {@code Thread(this).start(); }
      * </pre>
      *
+     * @param channel The {@link ChannelSession} through which the command has 
been
+     * received
      * @param env The {@link Environment}
      * @throws IOException If failed to start
      */
-    void start(Environment env) throws IOException;
+    void start(ChannelSession channel, Environment env) throws IOException;
 
     /**
      * This method is called by the SSH server to destroy the command because
      * the client has disconnected somehow.
      *
+     * @param channel The {@link ChannelSession} through which the command has 
been
+     * received
      * @throws Exception if failed to destroy
      */
-    void destroy() throws Exception;
+    void destroy(ChannelSession channel) throws Exception;
 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/InteractiveProcessShellFactory.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/InteractiveProcessShellFactory.java
index a0ebee2..8011bf3 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/InteractiveProcessShellFactory.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/InteractiveProcessShellFactory.java
@@ -22,6 +22,7 @@ package org.apache.sshd.server.shell;
 import java.util.List;
 
 import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.server.channel.ChannelSession;
 
 /**
  * A simplistic interactive shell factory
@@ -36,7 +37,7 @@ public class InteractiveProcessShellFactory extends 
ProcessShellFactory {
     }
 
     @Override
-    protected List<String> resolveEffectiveCommand(List<String> original) {
+    protected List<String> resolveEffectiveCommand(ChannelSession channel, 
List<String> original) {
         return original;
     }
 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
index 7035e89..0377afa 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.CommandLifecycle;
 
 /**
@@ -34,6 +35,12 @@ import org.apache.sshd.server.command.CommandLifecycle;
  */
 public interface InvertedShell extends CommandLifecycle, SessionAware {
     /**
+     * @return The {@link ChannelSession} instance through which
+     * the shell was created - may be {@code null} if shell not started yet
+     */
+    ChannelSession getChannelSession();
+
+    /**
      * Returns the output stream used to feed the shell.
      * This method is called after the shell has been started.
      *
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
index dee1371..7ca1b3e 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
@@ -34,6 +34,7 @@ import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.session.ServerSession;
 
@@ -103,8 +104,8 @@ public class InvertedShellWrapper extends 
AbstractLoggingBean implements Command
     /**
      * @param shell            The {@link InvertedShell}
      * @param executor         The {@link Executor} to use in order to create 
the streams pump thread.
-     *                         If {@code null} one is auto-allocated and 
shutdown when wrapper is {@link #destroy()}-ed.
-     * @param shutdownExecutor If {@code true} the executor is shut down when 
shell wrapper is {@link #destroy()}-ed.
+     *                         If {@code null} one is auto-allocated and 
shutdown when wrapper is {@code destroy()}-ed.
+     * @param shutdownExecutor If {@code true} the executor is shut down when 
shell wrapper is {@code destroy()}-ed.
      *                         Ignored if executor service auto-allocated
      * @param bufferSize       Buffer size to use - must be above min. size 
({@link Byte#SIZE})
      */
@@ -144,9 +145,9 @@ public class InvertedShellWrapper extends 
AbstractLoggingBean implements Command
     }
 
     @Override
-    public synchronized void start(Environment env) throws IOException {
+    public synchronized void start(ChannelSession channel, Environment env) 
throws IOException {
         // TODO propagate the Environment itself and support signal sending.
-        shell.start(env);
+        shell.start(channel,  env);
         shellIn = shell.getInputStream();
         shellOut = shell.getOutputStream();
         shellErr = shell.getErrorStream();
@@ -154,14 +155,14 @@ public class InvertedShellWrapper extends 
AbstractLoggingBean implements Command
     }
 
     @Override
-    public synchronized void destroy() throws Exception {
+    public synchronized void destroy(ChannelSession channel) throws Exception {
         boolean debugEnabled = log.isDebugEnabled();
         Throwable err = null;
         try {
-            shell.destroy();
+            shell.destroy(channel);
         } catch (Throwable e) {
             log.warn("destroy({}) failed ({}) to destroy shell: {}",
-                     this, e.getClass().getSimpleName(), e.getMessage());
+                 this, e.getClass().getSimpleName(), e.getMessage());
             if (debugEnabled) {
                 log.debug("destroy(" + this + ") shell destruction failure 
details", e);
             }
@@ -173,7 +174,7 @@ public class InvertedShellWrapper extends 
AbstractLoggingBean implements Command
                 ((ExecutorService) executor).shutdown();
             } catch (Exception e) {
                 log.warn("destroy({}) failed ({}) to shut down executor: {}",
-                         this, e.getClass().getSimpleName(), e.getMessage());
+                     this, e.getClass().getSimpleName(), e.getMessage());
                 if (debugEnabled) {
                     log.debug("destroy(" + this + ") executor shutdown failure 
details", e);
                 }
@@ -223,10 +224,10 @@ public class InvertedShellWrapper extends 
AbstractLoggingBean implements Command
         } catch (Throwable e) {
             boolean debugEnabled = log.isDebugEnabled();
             try {
-                shell.destroy();
+                shell.destroy(shell.getChannelSession());
             } catch (Throwable err) {
                 log.warn("pumpStreams({}) failed ({}) to destroy shell: {}",
-                         this, e.getClass().getSimpleName(), e.getMessage());
+                     this, e.getClass().getSimpleName(), e.getMessage());
                 if (debugEnabled) {
                     log.debug("pumpStreams(" + this + ") shell destruction 
failure details", err);
                 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShell.java 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShell.java
index 2b4a023..a86eeb8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShell.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShell.java
@@ -35,6 +35,7 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.channel.PuttyRequestHandler;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionHolder;
@@ -48,6 +49,7 @@ public class ProcessShell extends AbstractLoggingBean 
implements InvertedShell,
     private final List<String> command;
     private String cmdValue;
     private ServerSession session;
+    private ChannelSession channel;
     private Process process;
     private TtyFilterOutputStream in;
     private TtyFilterInputStream out;
@@ -79,7 +81,14 @@ public class ProcessShell extends AbstractLoggingBean 
implements InvertedShell,
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public ChannelSession getChannelSession() {
+        return channel;
+    }
+
+    @Override
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
+        this.channel = channel;
+
         Map<String, String> varsMap = resolveShellEnvironment(env.getEnv());
         for (int i = 0; i < command.size(); i++) {
             String cmd = command.get(i);
@@ -163,16 +172,20 @@ public class ProcessShell extends AbstractLoggingBean 
implements InvertedShell,
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) {
         // NOTE !!! DO NOT NULL-IFY THE PROCESS SINCE "exitValue" is called 
subsequently
+        boolean debugEnabled = log.isDebugEnabled();
         if (process != null) {
-            log.debug("Destroy process for " + cmdValue);
+            if (debugEnabled) {
+                log.debug("destroy({}) Destroy process for {}", channel, 
cmdValue);
+            }
             process.destroy();
         }
 
-        IOException e = IoUtils.closeQuietly(getInputStream(), 
getOutputStream(), getErrorStream());
+        IOException e =
+            IoUtils.closeQuietly(getInputStream(), getOutputStream(), 
getErrorStream());
         if (e != null) {
-            if (log.isDebugEnabled()) {
+            if (debugEnabled) {
                 log.debug(e.getClass().getSimpleName() + " while destroy 
streams of '" + this + "': " + e.getMessage());
             }
 
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
index 8c33b6f..37628dd 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
@@ -19,8 +19,10 @@
 
 package org.apache.sshd.server.shell;
 
-import org.apache.sshd.common.Factory;
+import java.io.IOException;
+
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.command.CommandFactory;
 
@@ -43,8 +45,8 @@ public class ProcessShellCommandFactory implements 
CommandFactory {
     }
 
     @Override
-    public Command createCommand(String command) {
-        Factory<Command> factory = new 
ProcessShellFactory(GenericUtils.split(command, ' '));
-        return factory.create();
+    public Command createCommand(ChannelSession channel,  String command) 
throws IOException {
+        ShellFactory factory = new 
ProcessShellFactory(GenericUtils.split(command, ' '));
+        return factory.createShell(channel);
     }
 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
index 529b701..35e7f86 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
@@ -27,6 +27,7 @@ import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.OsUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 
 /**
@@ -63,15 +64,17 @@ public class ProcessShellFactory extends 
AbstractLoggingBean implements ShellFac
     }
 
     @Override
-    public Command create() {
-        return new InvertedShellWrapper(createInvertedShell());
+    public Command createShell(ChannelSession channel) {
+        InvertedShell shell = createInvertedShell(channel);
+        return new InvertedShellWrapper(shell);
     }
 
-    protected InvertedShell createInvertedShell() {
-        return new ProcessShell(resolveEffectiveCommand(getCommand()));
+    protected InvertedShell createInvertedShell(ChannelSession channel) {
+        return new ProcessShell(resolveEffectiveCommand(channel, 
getCommand()));
     }
 
-    protected List<String> resolveEffectiveCommand(List<String> original) {
+    protected List<String> resolveEffectiveCommand(
+            ChannelSession channel, List<String> original) {
         if (!OsUtils.isWin32()) {
             return original;
         }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/ShellFactory.java 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/ShellFactory.java
index d403d42..65fa296 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/ShellFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/ShellFactory.java
@@ -19,14 +19,23 @@
 
 package org.apache.sshd.server.shell;
 
-import org.apache.sshd.common.Factory;
+import java.io.IOException;
+
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 
 /**
- * Useful marker interface
+ * Shell(s) are executed on the server side when a &quot;shell&quot;
+ * channel is established
  *
  * @author <a href="mailto:[email protected]";>Apache MINA SSHD Project</a>
  */
-public interface ShellFactory extends Factory<Command> {
-    // Nothing extra
+public interface ShellFactory {
+    /**
+     * @param channel The {@link ChannelSession} through which the command has 
been
+     * received
+     * @return The {@link Command} representing the shell to be executed
+     * @throws IOException If failed to create the shell
+     */
+    Command createShell(ChannelSession channel) throws IOException;
 }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommand.java 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommand.java
index 43b9b9f..e7ac1dd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommand.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommand.java
@@ -27,6 +27,7 @@ import java.util.Objects;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 
 /**
@@ -100,14 +101,14 @@ public class UnknownCommand implements Command, Runnable {
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
         Thread thread = new Thread(this);
         thread.setDaemon(true);
         thread.start();
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) {
         // ignored
     }
 
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommandFactory.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommandFactory.java
index ef71d99..9ea15d9 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommandFactory.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommandFactory.java
@@ -19,6 +19,7 @@
 
 package org.apache.sshd.server.shell;
 
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.command.CommandFactory;
 
@@ -40,7 +41,7 @@ public class UnknownCommandFactory implements CommandFactory {
     }
 
     @Override
-    public Command createCommand(String command) {
+    public Command createCommand(ChannelSession channel, String command) {
         return new UnknownCommand(command);
     }
 }
diff --git a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java 
b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
index 906df28..b2a164e 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
@@ -33,6 +33,7 @@ import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.channel.Channel;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.CoreTestSupportUtils;
@@ -167,7 +168,7 @@ public class KeepAliveTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return new TestEchoShell();
         }
     }
@@ -182,11 +183,11 @@ public class KeepAliveTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) throws Exception {
             if (latch != null) {
                 latch.countDown();
             }
-            super.destroy();
+            super.destroy(channel);
         }
     }
 }
diff --git a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java 
b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
index 4595afa..1d6a3e7 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
@@ -56,6 +56,7 @@ import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.subsystem.SubsystemFactory;
 import org.apache.sshd.util.test.BaseTestSupport;
@@ -698,12 +699,12 @@ public class KeyReExchangeTest extends BaseTestSupport {
                 }
 
                 @Override
-                public void start(Environment env) throws IOException {
+                public void start(ChannelSession channel, Environment env) 
throws IOException {
                     // Do nothing
                 }
 
                 @Override
-                public void destroy() throws Exception {
+                public void destroy(ChannelSession channel) throws Exception {
                     callback.onExit(0);
                 }
             };
diff --git a/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java 
b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
index fd1fd84..f1e073b 100644
--- a/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
@@ -48,6 +48,7 @@ import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.AsyncCommand;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.util.test.BaseTestSupport;
@@ -84,9 +85,10 @@ public class WindowAdjustTest extends BaseTestSupport {
     public void setUp() throws Exception {
         sshServer = setupTestServer();
 
-        final byte[] msg = Files.readAllBytes(
-                Paths.get(getClass().getResource("/big-msg.txt").toURI()));
-        sshServer.setShellFactory(() -> new FloodingAsyncCommand(msg, 
BIG_MSG_SEND_COUNT, END_FILE));
+        byte[] msg = Files.readAllBytes(
+            Paths.get(getClass().getResource("/big-msg.txt").toURI()));
+        sshServer.setShellFactory(
+            channel -> new FloodingAsyncCommand(msg, BIG_MSG_SEND_COUNT, 
END_FILE));
 
         sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
         sshServer.start();
@@ -222,10 +224,11 @@ public class WindowAdjustTest extends BaseTestSupport {
         }
 
         @Override
-        public void start(Environment env) throws IOException {
+        public void start(ChannelSession channel, Environment env) throws 
IOException {
             log.info("Starting");
 
-            ExecutorService service = 
ThreadUtils.newSingleThreadExecutor(getClass().getSimpleName() + "-" + 
POOL_COUNT.incrementAndGet());
+            ExecutorService service =
+                ThreadUtils.newSingleThreadExecutor(getClass().getSimpleName() 
+ "-" + POOL_COUNT.incrementAndGet());
             executorHolder.set(service);
 
             futureHolder.set(service.submit((Runnable) () -> {
@@ -253,7 +256,7 @@ public class WindowAdjustTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) {
             log.info("Destroying");
 
             Future<?> future = futureHolder.getAndSet(null);
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java 
b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
index 3ce0f5b..5bb7fa9 100644
--- a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
@@ -41,6 +41,7 @@ import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
 import org.apache.sshd.util.test.BaseTestSupport;
@@ -204,7 +205,7 @@ public class AgentTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return shell;
         }
     }
@@ -219,8 +220,8 @@ public class AgentTest extends BaseTestSupport {
         }
 
         @Override
-        public synchronized void start(Environment env) throws IOException {
-            super.start(env);
+        public synchronized void start(ChannelSession channel, Environment 
env) throws IOException {
+            super.start(channel, env);
             started = true;
             notifyAll();
         }
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java 
b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
index 8ee4e9a..d06f0d6 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
@@ -1582,7 +1582,7 @@ public class ClientTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return new TestEchoShell();
         }
     }
@@ -1597,11 +1597,11 @@ public class ClientTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) throws Exception {
             if (latch != null) {
                 latch.countDown();
             }
-            super.destroy();
+            super.destroy(channel);
         }
     }
 
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecTest.java 
b/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecTest.java
index 6bc5213..a338713 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecTest.java
@@ -51,7 +51,7 @@ public class ChannelExecTest extends BaseTestSupport {
     @BeforeClass
     public static void setupClientAndServer() throws Exception {
         sshd = CoreTestSupportUtils.setupTestServer(ChannelExecTest.class);
-        sshd.setCommandFactory(command -> new CommandExecutionHelper(command) {
+        sshd.setCommandFactory((session, command) -> new 
CommandExecutionHelper(command) {
             @Override
             protected boolean handleCommandLine(String command) throws 
Exception {
                 OutputStream stdout = getOutputStream();
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionTest.java 
b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionTest.java
index 520c862..1a087a7 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionTest.java
@@ -90,7 +90,7 @@ public class ClientSessionTest extends BaseTestSupport {
     public void testDefaultExecuteCommandMethod() throws Exception {
         final String expectedCommand = getCurrentTestName() + "-CMD";
         final String expectedResponse = getCurrentTestName() + "-RSP";
-        sshd.setCommandFactory(command -> new CommandExecutionHelper(command) {
+        sshd.setCommandFactory((session, command) -> new 
CommandExecutionHelper(command) {
             private boolean cmdProcessed;
 
             @Override
@@ -121,7 +121,7 @@ public class ClientSessionTest extends BaseTestSupport {
     public void testExceptionThrownIfRemoteStderrWrittenTo() throws Exception {
         final String expectedCommand = getCurrentTestName() + "-CMD";
         final String expectedErrorMessage = getCurrentTestName() + "-ERR";
-        sshd.setCommandFactory(command -> new CommandExecutionHelper(command) {
+        sshd.setCommandFactory((session, command) -> new 
CommandExecutionHelper(command) {
             private boolean cmdProcessed;
 
             @Override
@@ -166,7 +166,7 @@ public class ClientSessionTest extends BaseTestSupport {
     public void testExceptionThrownIfNonZeroExitStatus() throws Exception {
         final String expectedCommand = getCurrentTestName() + "-CMD";
         final int expectedErrorCode = 7365;
-        sshd.setCommandFactory(command -> new CommandExecutionHelper(command) {
+        sshd.setCommandFactory((session, command) -> new 
CommandExecutionHelper(command) {
             private boolean cmdProcessed;
 
             @Override
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java 
b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
index e668670..89f8887 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/SshBuilderTest.java
@@ -71,7 +71,7 @@ public class SshBuilderTest extends BaseTestSupport {
 
     /**
      * Make sure that all values in {@link BuiltinSignatures} are
-     * listed in {@link BaseBuilder#DEFAULT_SIGNATURE_PREFERENCE}
+     * listed in {@link ServerBuilder#DEFAULT_SIGNATURE_PREFERENCE}
      */
     @Test
     public void testAllBuiltinSignaturesListed() {
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java 
b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java
index e32f3d8..c294b11 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java
@@ -350,7 +350,7 @@ public class WindowTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return new TestEchoShell();
         }
     }
@@ -363,9 +363,9 @@ public class WindowTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) throws Exception {
             LATCH.countDown();
-            super.destroy();
+            super.destroy(channel);
         }
     }
 }
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java 
b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
index 73cfc25..fb3b0fb 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
@@ -75,6 +75,7 @@ import 
org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.keyboard.PromptEntry;
 import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
 import org.apache.sshd.server.auth.pubkey.RejectAllPublickeyAuthenticator;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionImpl;
@@ -340,7 +341,7 @@ public class ServerTest extends BaseTestSupport {
         PropertyResolverUtils.updateProperty(sshd, 
FactoryManager.DISCONNECT_TIMEOUT, disconnectTimeoutValue);
 
         CountDownLatch latch = new CountDownLatch(1);
-        sshd.setCommandFactory(StreamCommand::new);
+        sshd.setCommandFactory((channel, command) -> new 
StreamCommand(command));
         sshd.addSessionListener(new SessionListener() {
             @Override
             public void sessionCreated(Session session) {
@@ -607,7 +608,7 @@ public class ServerTest extends BaseTestSupport {
     @Test   // see SSHD-645
     public void testChannelStateChangeNotifications() throws Exception {
         Semaphore exitSignal = new Semaphore(0);
-        sshd.setCommandFactory(command -> new Command() {
+        sshd.setCommandFactory((session, command) -> new Command() {
             private ExitCallback cb;
 
             @Override
@@ -631,12 +632,12 @@ public class ServerTest extends BaseTestSupport {
             }
 
             @Override
-            public void destroy() {
+            public void destroy(ChannelSession channel) {
                 // ignored
             }
 
             @Override
-            public void start(Environment env) throws IOException {
+            public void start(ChannelSession channel, Environment env) throws 
IOException {
                 exitSignal.release();
                 cb.onExit(0, command);
             }
@@ -676,7 +677,7 @@ public class ServerTest extends BaseTestSupport {
     @Test
     public void testEnvironmentVariablesPropagationToServer() throws Exception 
{
         AtomicReference<Environment> envHolder = new AtomicReference<>(null);
-        sshd.setCommandFactory(command -> new Command() {
+        sshd.setCommandFactory((session, command) -> new Command() {
             private ExitCallback cb;
 
             @Override
@@ -700,12 +701,12 @@ public class ServerTest extends BaseTestSupport {
             }
 
             @Override
-            public void destroy() {
+            public void destroy(ChannelSession channel) {
                 // ignored
             }
 
             @Override
-            public void start(Environment env) throws IOException {
+            public void start(ChannelSession channel, Environment env) throws 
IOException {
                 if (envHolder.getAndSet(env) != null) {
                     throw new StreamCorruptedException("Multiple starts for 
command=" + command);
                 }
@@ -1009,7 +1010,7 @@ public class ServerTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return new TestEchoShell();
         }
     }
@@ -1024,11 +1025,11 @@ public class ServerTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) throws Exception {
             if (latch != null) {
                 latch.countDown();
             }
-            super.destroy();
+            super.destroy(channel);
         }
     }
 
@@ -1065,12 +1066,12 @@ public class ServerTest extends BaseTestSupport {
         }
 
         @Override
-        public void start(Environment env) throws IOException {
+        public void start(ChannelSession channel, Environment env) throws 
IOException {
             new Thread(this).start();
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) {
             synchronized (name) {
                 if ("block".equals(name)) {
                     try {
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java
index 8b86012..13dc910 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/server/channel/ChannelSessionTest.java
@@ -60,7 +60,7 @@ public class ChannelSessionTest extends BaseTestSupport {
         try (SshServer server = setupTestServer();
              SshClient client = setupTestClient()) {
 
-            server.setShellFactory(() -> new CommandExecutionHelper(null) {
+            server.setShellFactory(session -> new CommandExecutionHelper(null) 
{
                 @Override
                 protected boolean handleCommandLine(String command) throws 
Exception {
                     OutputStream out = getOutputStream();
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/server/shell/InvertedShellWrapperTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/server/shell/InvertedShellWrapperTest.java
index b1b7297..7e6aaac 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/server/shell/InvertedShellWrapperTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/server/shell/InvertedShellWrapperTest.java
@@ -27,6 +27,7 @@ import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.BogusEnvironment;
@@ -37,6 +38,7 @@ import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.runners.MethodSorters;
+import org.mockito.Mockito;
 
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Category({ NoIoTestCase.class })
@@ -55,12 +57,13 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
              ByteArrayOutputStream err = new ByteArrayOutputStream()) {
 
             InvertedShellWrapper wrapper = new InvertedShellWrapper(shell);
+            ChannelSession channel = Mockito.mock(ChannelSession.class);
             try {
                 wrapper.setInputStream(in);
                 wrapper.setOutputStream(out);
                 wrapper.setErrorStream(err);
                 wrapper.setExitCallback(new BogusExitCallback());
-                wrapper.start(new BogusEnvironment());
+                wrapper.start(channel, new BogusEnvironment());
 
                 wrapper.pumpStreams();
 
@@ -69,7 +72,7 @@ public class InvertedShellWrapperTest extends BaseTestSupport 
{
                 assertEquals("stdout", "out", out.toString());
                 assertEquals("stderr", "err", err.toString());
             } finally {
-                wrapper.destroy();
+                wrapper.destroy(channel);
             }
         }
     }
@@ -84,8 +87,13 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
             private boolean destroyed;
 
             @Override
-            public void start(Environment env) throws IOException {
-                bogusShell.start(env);
+            public ChannelSession getChannelSession() {
+                return bogusShell.getChannelSession();
+            }
+
+            @Override
+            public void start(ChannelSession channel, Environment env) throws 
IOException {
+                bogusShell.start(channel, env);
             }
 
             @Override
@@ -119,8 +127,8 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
             }
 
             @Override
-            public void destroy() {
-                bogusShell.destroy();
+            public void destroy(ChannelSession channel) {
+                bogusShell.destroy(channel);
                 bogusShell.setAlive(false);
                 destroyed = true;
             }
@@ -149,17 +157,18 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
 
             BogusExitCallback exitCallback = new BogusExitCallback();
             InvertedShellWrapper wrapper = new InvertedShellWrapper(shell);
+            ChannelSession channel = Mockito.mock(ChannelSession.class);
             try {
                 wrapper.setInputStream(stdin);
                 wrapper.setOutputStream(out);
                 wrapper.setErrorStream(err);
 
                 wrapper.setExitCallback(exitCallback);
-                wrapper.start(new BogusEnvironment());
+                wrapper.start(channel, new BogusEnvironment());
 
                 wrapper.pumpStreams();
             } finally {
-                wrapper.destroy();
+                wrapper.destroy(channel);
             }
 
             assertEquals("Mismatched exit value", destroyedExitValue, 
exitCallback.getExitValue());
@@ -180,9 +189,16 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
              ByteArrayOutputStream stderr = new 
ByteArrayOutputStream(errorContent.length() + Byte.SIZE)) {
 
             InvertedShell shell = new InvertedShell() {
+                private ChannelSession channel;
+
                 @Override
-                public void start(Environment env) throws IOException {
-                    // ignored
+                public void start(ChannelSession channel, Environment env) 
throws IOException {
+                    this.channel = channel;
+                }
+
+                @Override
+                public ChannelSession getChannelSession() {
+                    return channel;
                 }
 
                 @Override
@@ -216,24 +232,25 @@ public class InvertedShellWrapperTest extends 
BaseTestSupport {
                 }
 
                 @Override
-                public void destroy() {
+                public void destroy(ChannelSession channel) {
                     // ignored
                 }
             };
 
             BogusExitCallback exitCallback = new BogusExitCallback();
             InvertedShellWrapper wrapper = new InvertedShellWrapper(shell);
+            ChannelSession channel = Mockito.mock(ChannelSession.class);
             try {
                 wrapper.setInputStream(stdin);
                 wrapper.setOutputStream(stdout);
                 wrapper.setErrorStream(stderr);
 
                 wrapper.setExitCallback(exitCallback);
-                wrapper.start(new BogusEnvironment());
+                wrapper.start(channel, new BogusEnvironment());
 
                 wrapper.pumpStreams();
             } finally {
-                wrapper.destroy();
+                wrapper.destroy(channel);
             }
 
             assertEquals("Mismatched STDIN value", inputContent, 
shellIn.toString(StandardCharsets.UTF_8.name()));
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/util/test/AsyncEchoShellFactory.java 
b/sshd-core/src/test/java/org/apache/sshd/util/test/AsyncEchoShellFactory.java
index de9dbf4..9084a13 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/util/test/AsyncEchoShellFactory.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/util/test/AsyncEchoShellFactory.java
@@ -49,7 +49,7 @@ public class AsyncEchoShellFactory implements ShellFactory {
     }
 
     @Override
-    public Command create() {
+    public Command createShell(ChannelSession channel) {
         return new EchoShell();
     }
 
@@ -118,7 +118,7 @@ public class AsyncEchoShellFactory implements ShellFactory {
         }
 
         @Override
-        public void start(Environment env) throws IOException {
+        public void start(ChannelSession channel, Environment env) throws 
IOException {
             environment = env;
             session.setDataReceiver(this);
         }
@@ -129,12 +129,12 @@ public class AsyncEchoShellFactory implements 
ShellFactory {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) {
             // ignored
         }
 
         @Override
-        public int data(final ChannelSession channel, byte[] buf, int start, 
int len) throws IOException {
+        public int data(ChannelSession channel, byte[] buf, int start, int 
len) throws IOException {
             buffer.append(new String(buf, start, len, StandardCharsets.UTF_8));
             for (int i = 0; i < buffer.length(); i++) {
                 if (buffer.charAt(i) == '\n') {
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/util/test/BogusInvertedShell.java 
b/sshd-core/src/test/java/org/apache/sshd/util/test/BogusInvertedShell.java
index ca7ae2c..6670529 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/BogusInvertedShell.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/BogusInvertedShell.java
@@ -26,6 +26,7 @@ import java.util.Map;
 
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionHolder;
 import org.apache.sshd.server.shell.InvertedShell;
@@ -38,6 +39,7 @@ public class BogusInvertedShell implements InvertedShell, 
ServerSessionHolder {
 
     // for test assertions
     private ServerSession session;
+    private ChannelSession channel;
     private boolean started;
     private boolean alive = true;
     private Map<String, String> env;
@@ -59,7 +61,13 @@ public class BogusInvertedShell implements InvertedShell, 
ServerSessionHolder {
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public ChannelSession getChannelSession() {
+        return channel;
+    }
+
+    @Override
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
+        this.channel = channel;
         this.started = true;
         this.env = Collections.unmodifiableMap(env.getEnv());
     }
@@ -90,7 +98,7 @@ public class BogusInvertedShell implements InvertedShell, 
ServerSessionHolder {
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) {
         IoUtils.closeQuietly(in, out, err);
     }
 
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/util/test/EchoShellFactory.java 
b/sshd-core/src/test/java/org/apache/sshd/util/test/EchoShellFactory.java
index a9ec9d3..8505e14 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/EchoShellFactory.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/EchoShellFactory.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sshd.util.test;
 
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.shell.ShellFactory;
 
@@ -34,7 +35,7 @@ public class EchoShellFactory implements ShellFactory {
     }
 
     @Override
-    public Command create() {
+    public Command createShell(ChannelSession channel) {
         return new EchoShell();
     }
 }
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/AbstractGitCommand.java 
b/sshd-git/src/main/java/org/apache/sshd/git/AbstractGitCommand.java
index 405d3c9..b4e425b 100644
--- a/sshd-git/src/main/java/org/apache/sshd/git/AbstractGitCommand.java
+++ b/sshd-git/src/main/java/org/apache/sshd/git/AbstractGitCommand.java
@@ -45,7 +45,8 @@ public abstract class AbstractGitCommand
     protected final GitLocationResolver rootDirResolver;
     protected FileSystem fileSystem;
 
-    protected AbstractGitCommand(GitLocationResolver rootDirResolver, String 
command, CloseableExecutorService executorService) {
+    protected AbstractGitCommand(
+            GitLocationResolver rootDirResolver, String command, 
CloseableExecutorService executorService) {
         super(command, executorService);
         this.rootDirResolver = Objects.requireNonNull(rootDirResolver, "No GIT 
root directory resolver provided");
     }
diff --git 
a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java 
b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
index 49c0181..db7bce0 100644
--- a/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pack/GitPackCommand.java
@@ -27,7 +27,6 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.git.AbstractGitCommand;
 import org.apache.sshd.git.GitLocationResolver;
-import org.apache.sshd.server.Environment;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryCache;
 import org.eclipse.jgit.transport.ReceivePack;
@@ -44,10 +43,12 @@ public class GitPackCommand extends AbstractGitCommand {
     /**
      * @param rootDirResolver Resolver for GIT root directory
      * @param command Command to execute
-     * @param executorService An {@link CloseableExecutorService} to be used 
when {@link #start(Environment)}-ing
-     * execution. If {@code null} an ad-hoc single-threaded service is created 
and used.
+     * @param executorService An {@link CloseableExecutorService} to be used
+     * when {@code start(ChannelSession, Environment)}-ing execution. If 
{@code null}
+     * an ad-hoc single-threaded service is created and used.
      */
-    public GitPackCommand(GitLocationResolver rootDirResolver, String command, 
CloseableExecutorService executorService) {
+    public GitPackCommand(
+            GitLocationResolver rootDirResolver, String command, 
CloseableExecutorService executorService) {
         super(rootDirResolver, command, executorService);
     }
 
diff --git a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java 
b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
index ea828dc..eba0919 100644
--- a/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
+++ b/sshd-git/src/main/java/org/apache/sshd/git/pgm/GitPgmCommand.java
@@ -28,7 +28,6 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.git.AbstractGitCommand;
 import org.apache.sshd.git.GitLocationResolver;
-import org.apache.sshd.server.Environment;
 
 /**
  * TODO Add javadoc
@@ -39,10 +38,12 @@ public class GitPgmCommand extends AbstractGitCommand {
     /**
      * @param rootDirResolver Resolver for GIT root directory
      * @param command Command to execute
-     * @param executorService An {@link CloseableExecutorService} to be used 
when {@link #start(Environment)}-ing
-     * execution. If {@code null} an ad-hoc single-threaded service is created 
and used.
+     * @param executorService An {@link CloseableExecutorService} to be used
+     * when {@code start(ChannelSession, Environment)}-ing execution. If 
{@code null}
+     * an ad-hoc single-threaded service is created and used.
      */
-    public GitPgmCommand(GitLocationResolver rootDirResolver, String command, 
CloseableExecutorService executorService) {
+    public GitPgmCommand(
+            GitLocationResolver rootDirResolver, String command, 
CloseableExecutorService executorService) {
         super(rootDirResolver, command, executorService);
     }
 
diff --git a/sshd-scp/src/main/java/org/apache/sshd/server/scp/ScpCommand.java 
b/sshd-scp/src/main/java/org/apache/sshd/server/scp/ScpCommand.java
index bd628a9..e26f896 100644
--- a/sshd-scp/src/main/java/org/apache/sshd/server/scp/ScpCommand.java
+++ b/sshd-scp/src/main/java/org/apache/sshd/server/scp/ScpCommand.java
@@ -30,6 +30,7 @@ import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.AbstractFileSystemCommand;
 import org.apache.sshd.server.session.ServerSession;
 
@@ -58,8 +59,8 @@ public class ScpCommand
     /**
      * @param command         The command to be executed
      * @param executorService An {@link CloseableExecutorService} to be used 
when
-     *                        {@link #start(Environment)}-ing execution. If 
{@code null} an ad-hoc
-     *                        single-threaded service is created and used.
+     *                        {@code start(ChannelSession, Environment)}-ing 
execution.
+     *                        If {@code null} an ad-hoc single-threaded 
service is created and used.
      * @param sendSize        Size (in bytes) of buffer to use when sending 
files
      * @param receiveSize     Size (in bytes) of buffer to use when receiving 
files
      * @param fileOpener      The {@link ScpFileOpener} - if {@code null} then 
{@link DefaultScpFileOpener} is used
@@ -146,11 +147,11 @@ public class ScpCommand
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
         if (error != null) {
             throw error;
         }
-        super.start(env);
+        super.start(channel, env);
     }
 
     @Override
diff --git a/sshd-scp/src/test/java/org/apache/sshd/client/scp/ScpTest.java 
b/sshd-scp/src/test/java/org/apache/sshd/client/scp/ScpTest.java
index 4cf0475..b622f53 100644
--- a/sshd-scp/src/test/java/org/apache/sshd/client/scp/ScpTest.java
+++ b/sshd-scp/src/test/java/org/apache/sshd/client/scp/ScpTest.java
@@ -60,6 +60,7 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.threads.CloseableExecutorService;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.scp.ScpCommand;
 import org.apache.sshd.server.scp.ScpCommandFactory;
@@ -902,7 +903,7 @@ public class ScpTest extends BaseTestSupport {
         ScpCommandFactory factory = (ScpCommandFactory) 
sshd.getCommandFactory();
         sshd.setCommandFactory(new ScpCommandFactory() {
             @Override
-            public Command createCommand(String command) {
+            public Command createCommand(ChannelSession channel, String 
command) {
                 
ValidateUtils.checkTrue(command.startsWith(ScpHelper.SCP_COMMAND_PREFIX), "Bad 
SCP command: %s", command);
                 return new InternalScpCommand(command,
                         getExecutorService(),
diff --git 
a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
 
b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 0382eb7..92a2b29 100644
--- 
a/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ 
b/sshd-sftp/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -269,7 +269,7 @@ public class SftpSubsystem
     }
 
     @Override
-    public void start(Environment env) throws IOException {
+    public void start(ChannelSession channel, Environment env) throws 
IOException {
         this.env = env;
         try {
             CloseableExecutorService executor = getExecutorService();
@@ -964,7 +964,7 @@ public class SftpSubsystem
     }
 
     @Override
-    public void destroy() {
+    public void destroy(ChannelSession channel) {
         if (closed.getAndSet(true)) {
             return; // ignore if already closed
         }
diff --git 
a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java 
b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
index d5238b6..2affc1b 100644
--- 
a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
+++ 
b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/ClientTest.java
@@ -415,7 +415,7 @@ public class ClientTest extends BaseTestSupport {
         }
 
         @Override
-        public Command create() {
+        public Command createShell(ChannelSession channel) {
             return new TestEchoShell();
         }
     }
@@ -430,11 +430,11 @@ public class ClientTest extends BaseTestSupport {
         }
 
         @Override
-        public void destroy() {
+        public void destroy(ChannelSession channel) throws Exception {
             if (latch != null) {
                 latch.countDown();
             }
-            super.destroy();
+            super.destroy(channel);
         }
     }
 }

Reply via email to