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/05/15 07:48:13 UTC

[2/2] mina-sshd git commit: [SSHD-819] Standardized the DelegateCommandFactory behavior

[SSHD-819] Standardized the DelegateCommandFactory behavior


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

Branch: refs/heads/master
Commit: f1a8077be3875184b067095b236793e4801c2ad5
Parents: 3182ad8
Author: Goldstein Lyor <ly...@c-b4.com>
Authored: Tue May 15 10:41:24 2018 +0300
Committer: Goldstein Lyor <ly...@c-b4.com>
Committed: Tue May 15 10:48:02 2018 +0300

----------------------------------------------------------------------
 .../sshd/cli/server/SshServerCliSupport.java    |   2 +-
 .../apache/sshd/cli/server/SshServerMain.java   |   6 +-
 .../apache/sshd/cli/server/SshFsMounter.java    |   9 +-
 .../sshd/server/AbstractCommandSupport.java     | 168 ------------------
 .../org/apache/sshd/server/AsyncCommand.java    |  52 ------
 .../apache/sshd/server/ChannelSessionAware.java |   1 +
 .../java/org/apache/sshd/server/Command.java    |  65 -------
 .../org/apache/sshd/server/CommandFactory.java  |  40 -----
 .../apache/sshd/server/CommandLifecycle.java    |  48 ------
 .../sshd/server/ServerFactoryManager.java       |   2 +
 .../java/org/apache/sshd/server/SshServer.java  |   2 +
 .../server/channel/ChannelDataReceiver.java     |   4 +-
 .../sshd/server/channel/ChannelSession.java     |   8 +-
 .../server/command/AbstractCommandSupport.java  | 170 +++++++++++++++++++
 .../AbstractDelegatingCommandFactory.java       |  76 +++++++++
 .../sshd/server/command/AsyncCommand.java       |  52 ++++++
 .../org/apache/sshd/server/command/Command.java |  67 ++++++++
 .../sshd/server/command/CommandFactory.java     |  41 +++++
 .../sshd/server/command/CommandLifecycle.java   |  50 ++++++
 .../command/DelegatingCommandFactory.java       |  43 +++++
 .../apache/sshd/server/shell/InvertedShell.java |   2 +-
 .../sshd/server/shell/InvertedShellWrapper.java |   2 +-
 .../shell/ProcessShellCommandFactory.java       |  50 ++++++
 .../sshd/server/shell/ProcessShellFactory.java  |   2 +-
 .../apache/sshd/server/shell/ShellFactory.java  |   2 +-
 .../sshd/server/shell/UnknownCommand.java       |   2 +-
 .../server/shell/UnknownCommandFactory.java     |  11 +-
 .../sshd/server/subsystem/SubsystemFactory.java |   2 +-
 .../java/org/apache/sshd/KeepAliveTest.java     |   2 +-
 .../java/org/apache/sshd/KeyReExchangeTest.java |   2 +-
 .../java/org/apache/sshd/WindowAdjustTest.java  |   2 +-
 .../java/org/apache/sshd/agent/AgentTest.java   |   2 +-
 .../java/org/apache/sshd/client/ClientTest.java |   2 +-
 .../sshd/client/channel/ChannelExecTest.java    |  24 ++-
 .../sshd/client/session/ClientSessionTest.java  |  69 +++++---
 .../apache/sshd/common/channel/WindowTest.java  |   2 +-
 .../java/org/apache/sshd/server/ServerTest.java | 149 +++++++++-------
 .../sshd/util/test/AsyncEchoShellFactory.java   |   4 +-
 .../sshd/util/test/CommandExecutionHelper.java  |   2 +-
 .../apache/sshd/util/test/EchoShellFactory.java |   2 +-
 .../org/apache/sshd/git/AbstractGitCommand.java |   2 +-
 .../sshd/git/AbstractGitCommandFactory.java     |  47 ++---
 .../sshd/git/pack/GitPackCommandFactory.java    |   7 +-
 .../sshd/git/pgm/GitPgmCommandFactory.java      |   7 +-
 .../org/apache/sshd/server/scp/ScpCommand.java  |   2 +-
 .../sshd/server/scp/ScpCommandFactory.java      |  63 +++----
 .../org/apache/sshd/client/scp/ScpTest.java     |   2 +-
 .../sshd/server/scp/ScpCommandFactoryTest.java  |   2 +-
 .../server/subsystem/sftp/SftpSubsystem.java    |   4 +-
 .../subsystem/sftp/SftpSubsystemFactory.java    |   2 +-
 .../sshd/client/subsystem/sftp/ClientTest.java  |   2 +-
 .../sshd/client/subsystem/sftp/SftpTest.java    |   2 +-
 .../client/subsystem/sftp/SftpVersionsTest.java |   2 +-
 .../SpaceAvailableExtensionImplTest.java        |   2 +-
 .../openssh/helpers/OpenSSHExtensionsTest.java  |   2 +-
 55 files changed, 815 insertions(+), 574 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
----------------------------------------------------------------------
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
index 910566f..8b392bc 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
@@ -49,10 +49,10 @@ import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.threads.ThreadUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.ServerAuthenticationManager;
 import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.config.SshServerConfigFileReader;
 import org.apache.sshd.server.forward.ForwardingFilter;
 import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/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 cba6fc2..b9f6d1e 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
@@ -33,13 +33,13 @@ import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.config.SshConfigFileReader;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.config.keys.ServerIdentity;
 import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
 import org.apache.sshd.server.scp.ScpCommandFactory;
-import org.apache.sshd.server.shell.ProcessShellFactory;
+import org.apache.sshd.server.shell.ProcessShellCommandFactory;
 import org.apache.sshd.server.shell.ShellFactory;
 
 /**
@@ -181,7 +181,7 @@ public class SshServerMain extends SshServerCliSupport {
         sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
         setupServerForwarding(sshd, resolver);
         sshd.setCommandFactory(new ScpCommandFactory.Builder()
-            .withDelegate(command -> new ProcessShellFactory(GenericUtils.split(command, ' ')).create())
+            .withDelegate(ProcessShellCommandFactory.INSTANCE)
             .build());
 
         List<NamedFactory<Command>> subsystems = resolveServerSubsystems(System.err, resolver);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-cli/src/test/java/org/apache/sshd/cli/server/SshFsMounter.java
----------------------------------------------------------------------
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 74a5a83..c270be7 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
@@ -43,13 +43,13 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.apache.sshd.common.util.threads.ThreadUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
 import org.apache.sshd.server.Environment;
 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.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.scp.ScpCommandFactory;
@@ -232,6 +232,11 @@ public final class SshFsMounter extends SshServerCliSupport {
         }
 
         @Override
+        public String getName() {
+            return "mounter";
+        }
+
+        @Override
         public Command createCommand(String command) {
             return new MounterCommand(command);
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/AbstractCommandSupport.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/AbstractCommandSupport.java b/sshd-core/src/main/java/org/apache/sshd/server/AbstractCommandSupport.java
deleted file mode 100644
index 7533157..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/AbstractCommandSupport.java
+++ /dev/null
@@ -1,168 +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.server;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collection;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
-import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
-import org.apache.sshd.common.util.threads.ThreadUtils;
-
-/**
- * Provides a basic useful skeleton for {@link Command} executions
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public abstract class AbstractCommandSupport
-        extends AbstractLoggingBean
-        implements Command, Runnable, ExitCallback, ExecutorServiceCarrier {
-    private final String command;
-    private InputStream in;
-    private OutputStream out;
-    private OutputStream err;
-    private ExitCallback callback;
-    private Environment environment;
-    private Future<?> cmdFuture;
-    private ExecutorService executorService;
-    private boolean shutdownOnExit;
-    private boolean cbCalled;
-
-    protected AbstractCommandSupport(String command, ExecutorService executorService, boolean shutdownOnExit) {
-        this.command = command;
-
-        if (executorService == null) {
-            String poolName = GenericUtils.isEmpty(command) ? getClass().getSimpleName() : command.replace(' ', '_').replace('/', ':');
-            this.executorService = ThreadUtils.newSingleThreadExecutor(poolName);
-            this.shutdownOnExit = true;    // we always close the ad-hoc executor service
-        } else {
-            this.executorService = executorService;
-            this.shutdownOnExit = shutdownOnExit;
-        }
-    }
-
-    public String getCommand() {
-        return command;
-    }
-
-    @Override
-    public ExecutorService getExecutorService() {
-        return executorService;
-    }
-
-    @Override
-    public boolean isShutdownOnExit() {
-        return shutdownOnExit;
-    }
-
-    public InputStream getInputStream() {
-        return in;
-    }
-
-    @Override
-    public void setInputStream(InputStream in) {
-        this.in = in;
-    }
-
-    public OutputStream getOutputStream() {
-        return out;
-    }
-
-    @Override
-    public void setOutputStream(OutputStream out) {
-        this.out = out;
-    }
-
-    public OutputStream getErrorStream() {
-        return err;
-    }
-
-    @Override
-    public void setErrorStream(OutputStream err) {
-        this.err = err;
-    }
-
-    public ExitCallback getExitCallback() {
-        return callback;
-    }
-
-    @Override
-    public void setExitCallback(ExitCallback callback) {
-        this.callback = callback;
-    }
-
-    public Environment getEnvironment() {
-        return environment;
-    }
-
-    protected Future<?> getStartedCommandFuture() {
-        return cmdFuture;
-    }
-
-    @Override
-    public void start(Environment env) throws IOException {
-        environment = env;
-        ExecutorService executors = getExecutorService();
-        cmdFuture = executors.submit(this);
-    }
-
-    @Override
-    public void destroy() {
-        ExecutorService executors = getExecutorService();
-        if ((executors != null) && (!executors.isShutdown()) && isShutdownOnExit()) {
-            Collection<Runnable> runners = executors.shutdownNow();
-            if (log.isDebugEnabled()) {
-                log.debug("destroy() - shutdown executor service - runners count=" + runners.size());
-            }
-        }
-        this.executorService = null;
-    }
-
-    @Override
-    public void onExit(int exitValue, String exitMessage) {
-        if (cbCalled) {
-            if (log.isTraceEnabled()) {
-                log.trace("onExit({}) ignore exitValue={}, message={} - already called",
-                        this, exitValue, exitMessage);
-            }
-            return;
-        }
-
-        ExitCallback cb = getExitCallback();
-        try {
-            if (log.isDebugEnabled()) {
-                log.debug("onExit({}) exiting - value={}, message={}", this, exitValue, exitMessage);
-            }
-            cb.onExit(exitValue, exitMessage);
-        } finally {
-            cbCalled = true;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return getClass().getSimpleName() + "[" + getCommand() + "]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java b/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
deleted file mode 100644
index b49af64..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
+++ /dev/null
@@ -1,52 +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.server;
-
-import org.apache.sshd.common.io.IoInputStream;
-import org.apache.sshd.common.io.IoOutputStream;
-
-/**
- * Represents a command capable of doing non-blocking io.
- * If this interface is implemented by a command, the usual
- * blocking input / output / error streams won't be set.
- */
-public interface AsyncCommand extends Command {
-
-    /**
-     * Set the input stream that can be used by the shell to read input.
-     *
-     * @param in The {@link IoInputStream} used by the shell to read input
-     */
-    void setIoInputStream(IoInputStream in);
-
-    /**
-     * Set the output stream that can be used by the shell to write its output.
-     *
-     * @param out The {@link IoOutputStream} used by the shell to write its output
-     */
-    void setIoOutputStream(IoOutputStream out);
-
-    /**
-     * Set the error stream that can be used by the shell to write its errors.
-     *
-     * @param err The {@link IoOutputStream} used by the shell to write its errors
-     */
-    void setIoErrorStream(IoOutputStream err);
-
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java b/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
index 150e719..d6d7c8b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
@@ -19,6 +19,7 @@
 package org.apache.sshd.server;
 
 import org.apache.sshd.server.channel.ChannelSession;
+import org.apache.sshd.server.command.Command;
 
 /**
  * {@link Command} can implement this optional interface

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/Command.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/Command.java b/sshd-core/src/main/java/org/apache/sshd/server/Command.java
deleted file mode 100644
index 4043e48..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/Command.java
+++ /dev/null
@@ -1,65 +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.server;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * <p>
- * Represents a command, shell or subsystem that can be used to send command.
- * </p>
- *
- * <p>
- * This command have direct streams, meaning those streams will be provided by the ssh server
- * for the shell to use directly. This interface is suitable for implementing commands in java,
- * rather than using external processes.  For wrapping such processes or using inverted streams,
- * </p>
- * see {@link org.apache.sshd.server.shell.InvertedShellWrapper}.
- */
-public interface Command extends CommandLifecycle {
-
-    /**
-     * Set the input stream that can be used by the shell to read input.
-     *
-     * @param in The {@link InputStream}  used by the shell to read input.
-     */
-    void setInputStream(InputStream in);
-
-    /**
-     * Set the output stream that can be used by the shell to write its output.
-     *
-     * @param out The {@link OutputStream} used by the shell to write its output
-     */
-    void setOutputStream(OutputStream out);
-
-    /**
-     * Set the error stream that can be used by the shell to write its errors.
-     *
-     * @param err The {@link OutputStream} used by the shell to write its errors
-     */
-    void setErrorStream(OutputStream err);
-
-    /**
-     * Set the callback that the shell has to call when it is closed.
-     *
-     * @param callback The {@link ExitCallback} to call when shell is closed
-     */
-    void setExitCallback(ExitCallback callback);
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
deleted file mode 100644
index 650abe1..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
+++ /dev/null
@@ -1,40 +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.server;
-
-/**
- * A factory of commands.
- * Commands are executed on the server side when an "exec" channel is
- * requested by the SSH client.
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-@FunctionalInterface
-public interface CommandFactory {
-
-    /**
-     * Create a command with the given name.
-     * 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 command The command that will be run
-     * @return a non {@code null} {@link Command} instance
-     */
-    Command createCommand(String command);
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java b/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
deleted file mode 100644
index cbe3cf0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
+++ /dev/null
@@ -1,48 +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.server;
-
-import java.io.IOException;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface CommandLifecycle {
-    /**
-     * Starts the command execution. All streams must have been set <U>before</U>
-     * calling this method. The command should implement {@link java.lang.Runnable},
-     * and this method should spawn a new thread like:
-     * <pre>
-     * {@code Thread(this).start(); }
-     * </pre>
-     *
-     * @param env The {@link Environment}
-     * @throws IOException If failed to start
-     */
-    void start(Environment env) throws IOException;
-
-    /**
-     * This method is called by the SSH server to destroy the command because
-     * the client has disconnected somehow.
-     *
-     * @throws Exception if failed to destroy
-     */
-    void destroy() throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
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 68531ed..60bd655 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
@@ -24,6 +24,8 @@ 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;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
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 f93c5d0..35b72cc 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
@@ -49,6 +49,8 @@ import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.session.ServerConnectionServiceFactory;
 import org.apache.sshd.server.session.ServerProxyAcceptor;
 import org.apache.sshd.server.session.ServerUserAuthServiceFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java
index f336c89..59ade13 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java
@@ -30,10 +30,10 @@ import java.io.IOException;
  * Sequence of bytes that SSH client sends to the server is eventually sent to this interface
  * to be passed on to the final consumer.
  * By default {@link ChannelSession} spools this in a buffer so that you can read it from
- * the input stream you get from {@link org.apache.sshd.server.Command#setInputStream(java.io.InputStream)}, but if command
+ * the input stream you get from {@link org.apache.sshd.server.command.Command#setInputStream(java.io.InputStream)}, but if command
  * wants to do a callback-driven I/O for the data it receives from the client, it can
  * call {@link ChannelSession#setDataReceiver(ChannelDataReceiver)} to do so.
- * (And to grab a reference to {@link ChannelSession}, a {@link org.apache.sshd.server.Command} should implement
+ * (And to grab a reference to {@link ChannelSession}, a {@link org.apache.sshd.server.command.Command} should implement
  * {@link org.apache.sshd.server.ChannelSessionAware}.)
  * </p>
  *

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
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 b884d80..cfaa499 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
@@ -62,15 +62,15 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.closeable.IoBaseCloseable;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.io.LoggingFilterOutputStream;
-import org.apache.sshd.server.AsyncCommand;
 import org.apache.sshd.server.ChannelSessionAware;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ServerFactoryManager;
 import org.apache.sshd.server.SessionAware;
 import org.apache.sshd.server.Signal;
 import org.apache.sshd.server.StandardEnvironment;
+import org.apache.sshd.server.command.AsyncCommand;
+import org.apache.sshd.server.command.Command;
+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;
@@ -602,7 +602,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.AsyncCommand#setIoInputStream(org.apache.sshd.common.io.IoInputStream)}
+     * {@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)},
      * the input stream you received in {@link Command#setInputStream(java.io.InputStream)} will
      * not read any data.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..58cf034
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractCommandSupport.java
@@ -0,0 +1,170 @@
+/*
+ * 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.server.command;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
+import org.apache.sshd.common.util.threads.ThreadUtils;
+import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.ExitCallback;
+
+/**
+ * Provides a basic useful skeleton for {@link Command} executions
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractCommandSupport
+        extends AbstractLoggingBean
+        implements Command, Runnable, ExitCallback, ExecutorServiceCarrier {
+    private final String command;
+    private InputStream in;
+    private OutputStream out;
+    private OutputStream err;
+    private ExitCallback callback;
+    private Environment environment;
+    private Future<?> cmdFuture;
+    private ExecutorService executorService;
+    private boolean shutdownOnExit;
+    private boolean cbCalled;
+
+    protected AbstractCommandSupport(String command, ExecutorService executorService, boolean shutdownOnExit) {
+        this.command = command;
+
+        if (executorService == null) {
+            String poolName = GenericUtils.isEmpty(command) ? getClass().getSimpleName() : command.replace(' ', '_').replace('/', ':');
+            this.executorService = ThreadUtils.newSingleThreadExecutor(poolName);
+            this.shutdownOnExit = true;    // we always close the ad-hoc executor service
+        } else {
+            this.executorService = executorService;
+            this.shutdownOnExit = shutdownOnExit;
+        }
+    }
+
+    public String getCommand() {
+        return command;
+    }
+
+    @Override
+    public ExecutorService getExecutorService() {
+        return executorService;
+    }
+
+    @Override
+    public boolean isShutdownOnExit() {
+        return shutdownOnExit;
+    }
+
+    public InputStream getInputStream() {
+        return in;
+    }
+
+    @Override
+    public void setInputStream(InputStream in) {
+        this.in = in;
+    }
+
+    public OutputStream getOutputStream() {
+        return out;
+    }
+
+    @Override
+    public void setOutputStream(OutputStream out) {
+        this.out = out;
+    }
+
+    public OutputStream getErrorStream() {
+        return err;
+    }
+
+    @Override
+    public void setErrorStream(OutputStream err) {
+        this.err = err;
+    }
+
+    public ExitCallback getExitCallback() {
+        return callback;
+    }
+
+    @Override
+    public void setExitCallback(ExitCallback callback) {
+        this.callback = callback;
+    }
+
+    public Environment getEnvironment() {
+        return environment;
+    }
+
+    protected Future<?> getStartedCommandFuture() {
+        return cmdFuture;
+    }
+
+    @Override
+    public void start(Environment env) throws IOException {
+        environment = env;
+        ExecutorService executors = getExecutorService();
+        cmdFuture = executors.submit(this);
+    }
+
+    @Override
+    public void destroy() {
+        ExecutorService executors = getExecutorService();
+        if ((executors != null) && (!executors.isShutdown()) && isShutdownOnExit()) {
+            Collection<Runnable> runners = executors.shutdownNow();
+            if (log.isDebugEnabled()) {
+                log.debug("destroy() - shutdown executor service - runners count=" + runners.size());
+            }
+        }
+        this.executorService = null;
+    }
+
+    @Override
+    public void onExit(int exitValue, String exitMessage) {
+        if (cbCalled) {
+            if (log.isTraceEnabled()) {
+                log.trace("onExit({}) ignore exitValue={}, message={} - already called",
+                        this, exitValue, exitMessage);
+            }
+            return;
+        }
+
+        ExitCallback cb = getExitCallback();
+        try {
+            if (log.isDebugEnabled()) {
+                log.debug("onExit({}) exiting - value={}, message={}", this, exitValue, exitMessage);
+            }
+            cb.onExit(exitValue, exitMessage);
+        } finally {
+            cbCalled = true;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + getCommand() + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..3169958
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/AbstractDelegatingCommandFactory.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.command;
+
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class AbstractDelegatingCommandFactory extends AbstractLoggingBean implements DelegatingCommandFactory {
+    private final String name;
+    /*
+     * NOTE: we expose setters since there is no problem to change these settings between
+     * successive invocations of the 'createCommand' method
+     */
+    private CommandFactory delegate;
+
+    protected AbstractDelegatingCommandFactory(String name) {
+        this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No delegating command factory name provided");
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public CommandFactory getDelegateCommandFactory() {
+        return delegate;
+    }
+
+    @Override
+    public void setDelegateCommandFactory(CommandFactory factory) {
+        delegate = factory;
+    }
+
+    @Override
+    public Command createCommand(String command) {
+        if (isSupportedCommand(command)) {
+            return executeSupportedCommand(command);
+        }
+
+        CommandFactory factory = getDelegateCommandFactory();
+        if (factory != null) {
+            return factory.createCommand(command);
+        }
+
+        return createUnsupportedCommand(command);
+    }
+
+    protected abstract Command executeSupportedCommand(String command);
+
+    protected Command createUnsupportedCommand(String command) {
+        throw new IllegalArgumentException("Unknown command to execute: " + command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java b/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java
new file mode 100644
index 0000000..f3d2173
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java
@@ -0,0 +1,52 @@
+/*
+ * 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.server.command;
+
+import org.apache.sshd.common.io.IoInputStream;
+import org.apache.sshd.common.io.IoOutputStream;
+
+/**
+ * Represents a command capable of doing non-blocking io.
+ * If this interface is implemented by a command, the usual
+ * blocking input / output / error streams won't be set.
+ */
+public interface AsyncCommand extends Command {
+
+    /**
+     * Set the input stream that can be used by the shell to read input.
+     *
+     * @param in The {@link IoInputStream} used by the shell to read input
+     */
+    void setIoInputStream(IoInputStream in);
+
+    /**
+     * Set the output stream that can be used by the shell to write its output.
+     *
+     * @param out The {@link IoOutputStream} used by the shell to write its output
+     */
+    void setIoOutputStream(IoOutputStream out);
+
+    /**
+     * Set the error stream that can be used by the shell to write its errors.
+     *
+     * @param err The {@link IoOutputStream} used by the shell to write its errors
+     */
+    void setIoErrorStream(IoOutputStream err);
+
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java b/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
new file mode 100644
index 0000000..5425d3a
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
@@ -0,0 +1,67 @@
+/*
+ * 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.server.command;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.sshd.server.ExitCallback;
+
+/**
+ * <p>
+ * Represents a command, shell or subsystem that can be used to send command.
+ * </p>
+ *
+ * <p>
+ * This command have direct streams, meaning those streams will be provided by the ssh server
+ * for the shell to use directly. This interface is suitable for implementing commands in java,
+ * rather than using external processes.  For wrapping such processes or using inverted streams,
+ * </p>
+ * see {@link org.apache.sshd.server.shell.InvertedShellWrapper}.
+ */
+public interface Command extends CommandLifecycle {
+
+    /**
+     * Set the input stream that can be used by the shell to read input.
+     *
+     * @param in The {@link InputStream}  used by the shell to read input.
+     */
+    void setInputStream(InputStream in);
+
+    /**
+     * Set the output stream that can be used by the shell to write its output.
+     *
+     * @param out The {@link OutputStream} used by the shell to write its output
+     */
+    void setOutputStream(OutputStream out);
+
+    /**
+     * Set the error stream that can be used by the shell to write its errors.
+     *
+     * @param err The {@link OutputStream} used by the shell to write its errors
+     */
+    void setErrorStream(OutputStream err);
+
+    /**
+     * Set the callback that the shell has to call when it is closed.
+     *
+     * @param callback The {@link ExitCallback} to call when shell is closed
+     */
+    void setExitCallback(ExitCallback callback);
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..aff407b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandFactory.java
@@ -0,0 +1,41 @@
+/*
+ * 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.server.command;
+
+import org.apache.sshd.common.NamedResource;
+
+/**
+ * A factory of commands.
+ * Commands are executed on the server side when an "exec" channel is
+ * requested by the SSH client.
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface CommandFactory extends NamedResource {
+
+    /**
+     * Create a command with the given name.
+     * 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 command The command that will be run
+     * @return a non {@code null} {@link Command} instance
+     */
+    Command createCommand(String command);
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..ac694d5
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/CommandLifecycle.java
@@ -0,0 +1,50 @@
+/*
+ * 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.server.command;
+
+import java.io.IOException;
+
+import org.apache.sshd.server.Environment;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface CommandLifecycle {
+    /**
+     * Starts the command execution. All streams must have been set <U>before</U>
+     * calling this method. The command should implement {@link java.lang.Runnable},
+     * and this method should spawn a new thread like:
+     * <pre>
+     * {@code Thread(this).start(); }
+     * </pre>
+     *
+     * @param env The {@link Environment}
+     * @throws IOException If failed to start
+     */
+    void start(Environment env) throws IOException;
+
+    /**
+     * This method is called by the SSH server to destroy the command because
+     * the client has disconnected somehow.
+     *
+     * @throws Exception if failed to destroy
+     */
+    void destroy() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/DelegatingCommandFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/DelegatingCommandFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/command/DelegatingCommandFactory.java
new file mode 100644
index 0000000..e1ce89c
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/command/DelegatingCommandFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.command;
+
+/**
+ * Represents a {@link CommandFactory} that filters the commands it recognizes
+ * and delegates the ones it doesn't to another delegate factory. The behavior
+ * of such a delegating factory is undefined if it receives a command it does
+ * not recognize and not delegate has been set. The recommended behavior in this
+ * case is to throw some exception - though this is not mandatory
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface DelegatingCommandFactory extends CommandFactory {
+    CommandFactory getDelegateCommandFactory();
+
+    void setDelegateCommandFactory(CommandFactory factory);
+
+    /**
+     * @param command The command about to be executed
+     * @return {@code true} if this command is supported by the command
+     * factory, {@code false} if it will be passed on to the
+     * {@link #getDelegateCommandFactory() delegate} factory
+     */
+    boolean isSupportedCommand(String command);
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShell.java
----------------------------------------------------------------------
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 3d7de3c..3abc523 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
@@ -21,8 +21,8 @@ package org.apache.sshd.server.shell;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import org.apache.sshd.server.CommandLifecycle;
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.command.CommandLifecycle;
 
 /**
  * This shell have inverted streams, such as the one obtained when launching a

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/InvertedShellWrapper.java
----------------------------------------------------------------------
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 4819064..3c19e2c 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
@@ -31,10 +31,10 @@ 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.common.util.threads.ThreadUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.session.ServerSession;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..af9af82
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellCommandFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.server.shell;
+
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
+
+/**
+ * Executes commands by invoking the underlying shell
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class ProcessShellCommandFactory implements CommandFactory {
+    public static final String FACTORY_NAME = "shell-command";
+    public static final ProcessShellCommandFactory INSTANCE = new ProcessShellCommandFactory();
+
+    public ProcessShellCommandFactory() {
+        super();
+    }
+
+    @Override
+    public String getName() {
+        return FACTORY_NAME;
+    }
+
+    @Override
+    public Command createCommand(String command) {
+        Factory<Command> factory = new ProcessShellFactory(GenericUtils.split(command, ' '));
+        return factory.create();
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/ProcessShellFactory.java
----------------------------------------------------------------------
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 3398e63..529b701 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,7 +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.Command;
+import org.apache.sshd.server.command.Command;
 
 /**
  * A {@link Factory} of {@link Command} that will create a new process and bridge

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/ShellFactory.java
----------------------------------------------------------------------
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 0a80f67..d403d42 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
@@ -20,7 +20,7 @@
 package org.apache.sshd.server.shell;
 
 import org.apache.sshd.common.Factory;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
 
 /**
  * Useful marker interface

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommand.java
----------------------------------------------------------------------
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 59d970c..43b9b9f 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
@@ -25,9 +25,9 @@ import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
 import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.command.Command;
 
 /**
  * Implementation of an unknown command that can be returned by <code>CommandFactory</code>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/UnknownCommandFactory.java
----------------------------------------------------------------------
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 871ca60..ea94525 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,13 +19,15 @@
 
 package org.apache.sshd.server.shell;
 
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class UnknownCommandFactory implements CommandFactory {
+    public static final String FACTORY_NAME = "unknown";
+
     public static final UnknownCommandFactory INSTANCE = new UnknownCommandFactory();
 
     public UnknownCommandFactory() {
@@ -33,6 +35,11 @@ public class UnknownCommandFactory implements CommandFactory {
     }
 
     @Override
+    public String getName() {
+        return FACTORY_NAME;
+    }
+
+    @Override
     public Command createCommand(String command) {
         return new UnknownCommand(command);
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java
index f9dbf0f..8b0cc3f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java
@@ -20,7 +20,7 @@
 package org.apache.sshd.server.subsystem;
 
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
----------------------------------------------------------------------
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 dd649e5..4e09447 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
@@ -32,8 +32,8 @@ import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.channel.Channel;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.EchoShell;
 import org.apache.sshd.util.test.EchoShellFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
----------------------------------------------------------------------
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 f2ca9df..4fdb932 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
@@ -55,10 +55,10 @@ import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.session.SessionListener;
 import org.apache.sshd.common.util.io.NullOutputStream;
 import org.apache.sshd.common.util.security.SecurityUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.subsystem.SubsystemFactory;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.JSchLogger;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
----------------------------------------------------------------------
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 cac8e32..fd1fd84 100644
--- a/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
@@ -45,10 +45,10 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.io.NoCloseOutputStream;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 import org.apache.sshd.common.util.threads.ThreadUtils;
-import org.apache.sshd.server.AsyncCommand;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.AsyncCommand;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.junit.After;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
----------------------------------------------------------------------
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 f252be7..7deebfc 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
@@ -38,9 +38,9 @@ import org.apache.sshd.client.channel.ChannelShell;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.keyprovider.KeyPairProvider;
 import org.apache.sshd.common.util.security.SecurityUtils;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.EchoShell;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
----------------------------------------------------------------------
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 f3d94a8..0026cc3 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
@@ -95,13 +95,13 @@ import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.common.util.io.NoCloseOutputStream;
 import org.apache.sshd.common.util.net.SshdSocketAddress;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
 import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.channel.ChannelSessionFactory;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.forward.DirectTcpipFactory;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerConnectionServiceFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecTest.java
----------------------------------------------------------------------
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 038ce55..8a48daf 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
@@ -26,6 +26,8 @@ import java.util.concurrent.TimeUnit;
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.CommandExecutionHelper;
 import org.apache.sshd.util.test.Utils;
@@ -51,13 +53,23 @@ public class ChannelExecTest extends BaseTestSupport {
     @BeforeClass
     public static void setupClientAndServer() throws Exception {
         sshd = Utils.setupTestServer(ChannelExecTest.class);
-        sshd.setCommandFactory(command -> new CommandExecutionHelper(command) {
+        sshd.setCommandFactory(new CommandFactory() {
             @Override
-            protected boolean handleCommandLine(String command) throws Exception {
-                OutputStream stdout = getOutputStream();
-                stdout.write(command.getBytes(StandardCharsets.US_ASCII));
-                stdout.flush();
-                return false;
+            public String getName() {
+                return ChannelExecTest.class.getSimpleName();
+            }
+
+            @Override
+            public Command createCommand(String command) {
+                return new CommandExecutionHelper(command) {
+                    @Override
+                    protected boolean handleCommandLine(String command) throws Exception {
+                        OutputStream stdout = getOutputStream();
+                        stdout.write(command.getBytes(StandardCharsets.US_ASCII));
+                        stdout.flush();
+                        return false;
+                    }
+                };
             }
         });
         sshd.start();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/session/ClientSessionTest.java
----------------------------------------------------------------------
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 aeb5e3b..517b07c 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
@@ -26,9 +26,9 @@ import java.rmi.ServerException;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.client.SshClient;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
 import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.CommandExecutionHelper;
 import org.apache.sshd.util.test.Utils;
@@ -84,18 +84,28 @@ 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) {
-            private boolean cmdProcessed;
+        sshd.setCommandFactory(new CommandFactory() {
+            @Override
+            public String getName() {
+                return getCurrentTestName();
+            }
 
             @Override
-            protected boolean handleCommandLine(String command) throws Exception {
-                assertEquals("Mismatched incoming command", expectedCommand, command);
-                assertFalse("Duplicated command call", cmdProcessed);
-                OutputStream stdout = getOutputStream();
-                stdout.write(expectedResponse.getBytes(StandardCharsets.US_ASCII));
-                stdout.flush();
-                cmdProcessed = true;
-                return false;
+            public Command createCommand(String command) {
+                return new CommandExecutionHelper(command) {
+                    private boolean cmdProcessed;
+
+                    @Override
+                    protected boolean handleCommandLine(String command) throws Exception {
+                        assertEquals("Mismatched incoming command", expectedCommand, command);
+                        assertFalse("Duplicated command call", cmdProcessed);
+                        OutputStream stdout = getOutputStream();
+                        stdout.write(expectedResponse.getBytes(StandardCharsets.US_ASCII));
+                        stdout.flush();
+                        cmdProcessed = true;
+                        return false;
+                    }
+                };
             }
         });
 
@@ -113,18 +123,28 @@ 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) {
-            private boolean cmdProcessed;
+        sshd.setCommandFactory(new CommandFactory() {
+            @Override
+            public String getName() {
+                return getCurrentTestName();
+            }
 
             @Override
-            protected boolean handleCommandLine(String command) throws Exception {
-                assertEquals("Mismatched incoming command", expectedCommand, command);
-                assertFalse("Duplicated command call", cmdProcessed);
-                OutputStream stderr = getErrorStream();
-                stderr.write(expectedErrorMessage.getBytes(StandardCharsets.US_ASCII));
-                stderr.flush();
-                cmdProcessed = true;
-                return false;
+            public Command createCommand(String command) {
+                return new CommandExecutionHelper(command) {
+                    private boolean cmdProcessed;
+
+                    @Override
+                    protected boolean handleCommandLine(String command) throws Exception {
+                        assertEquals("Mismatched incoming command", expectedCommand, command);
+                        assertFalse("Duplicated command call", cmdProcessed);
+                        OutputStream stderr = getErrorStream();
+                        stderr.write(expectedErrorMessage.getBytes(StandardCharsets.US_ASCII));
+                        stderr.flush();
+                        cmdProcessed = true;
+                        return false;
+                    }
+                };
             }
         });
 
@@ -158,6 +178,11 @@ public class ClientSessionTest extends BaseTestSupport {
         final int exepectedErrorCode = 7365;
         sshd.setCommandFactory(new CommandFactory() {
             @Override
+            public String getName() {
+                return getCurrentTestName();
+            }
+
+            @Override
             public Command createCommand(String command) {
                 return new CommandExecutionHelper(command) {
                     private boolean cmdProcessed;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/common/channel/WindowTest.java
----------------------------------------------------------------------
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 93c37be..864fc23 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
@@ -45,10 +45,10 @@ import org.apache.sshd.common.io.IoReadFuture;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.channel.ChannelSessionFactory;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.forward.DirectTcpipFactory;
 import org.apache.sshd.server.session.ServerConnectionService;
 import org.apache.sshd.server.session.ServerConnectionServiceFactory;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
----------------------------------------------------------------------
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 8c083a3..d1955ef 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
@@ -72,6 +72,8 @@ 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.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionImpl;
 import org.apache.sshd.util.test.BaseTestSupport;
@@ -522,43 +524,51 @@ public class ServerTest extends BaseTestSupport {
     @Test   // see SSHD-645
     public void testChannelStateChangeNotifications() throws Exception {
         final Semaphore exitSignal = new Semaphore(0);
-        sshd.setCommandFactory(command -> {
-            ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command, getCurrentTestName()) == 0, "Unexpected command: %s", command);
+        sshd.setCommandFactory(new CommandFactory() {
+            @Override
+            public String getName() {
+                return getCurrentTestName();
+            }
 
-            return new Command() {
-                private ExitCallback cb;
+            @Override
+            public Command createCommand(String command) {
+                ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command, getCurrentTestName()) == 0, "Unexpected command: %s", command);
 
-                @Override
-                public void setOutputStream(OutputStream out) {
-                    // ignored
-                }
+                return new Command() {
+                    private ExitCallback cb;
 
-                @Override
-                public void setInputStream(InputStream in) {
-                    // ignored
-                }
+                    @Override
+                    public void setOutputStream(OutputStream out) {
+                        // ignored
+                    }
 
-                @Override
-                public void setExitCallback(ExitCallback callback) {
-                    cb = callback;
-                }
+                    @Override
+                    public void setInputStream(InputStream in) {
+                        // ignored
+                    }
 
-                @Override
-                public void setErrorStream(OutputStream err) {
-                    // ignored
-                }
+                    @Override
+                    public void setExitCallback(ExitCallback callback) {
+                        cb = callback;
+                    }
 
-                @Override
-                public void destroy() {
-                    // ignored
-                }
+                    @Override
+                    public void setErrorStream(OutputStream err) {
+                        // ignored
+                    }
 
-                @Override
-                public void start(Environment env) throws IOException {
-                    exitSignal.release();
-                    cb.onExit(0, command);
-                }
-            };
+                    @Override
+                    public void destroy() {
+                        // ignored
+                    }
+
+                    @Override
+                    public void start(Environment env) throws IOException {
+                        exitSignal.release();
+                        cb.onExit(0, command);
+                    }
+                };
+            }
         });
         sshd.start();
         client.start();
@@ -595,46 +605,54 @@ public class ServerTest extends BaseTestSupport {
     @Test
     public void testEnvironmentVariablesPropagationToServer() throws Exception {
         final AtomicReference<Environment> envHolder = new AtomicReference<>(null);
-        sshd.setCommandFactory(command -> {
-            ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command, getCurrentTestName()) == 0, "Unexpected command: %s", command);
+        sshd.setCommandFactory(new CommandFactory() {
+            @Override
+            public String getName() {
+                return getCurrentTestName();
+            }
 
-            return new Command() {
-                private ExitCallback cb;
+            @Override
+            public Command createCommand(String command) {
+                ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command, getCurrentTestName()) == 0, "Unexpected command: %s", command);
 
-                @Override
-                public void setOutputStream(OutputStream out) {
-                    // ignored
-                }
+                return new Command() {
+                    private ExitCallback cb;
 
-                @Override
-                public void setInputStream(InputStream in) {
-                    // ignored
-                }
+                    @Override
+                    public void setOutputStream(OutputStream out) {
+                        // ignored
+                    }
 
-                @Override
-                public void setExitCallback(ExitCallback callback) {
-                    cb = callback;
-                }
+                    @Override
+                    public void setInputStream(InputStream in) {
+                        // ignored
+                    }
 
-                @Override
-                public void setErrorStream(OutputStream err) {
-                    // ignored
-                }
+                    @Override
+                    public void setExitCallback(ExitCallback callback) {
+                        cb = callback;
+                    }
 
-                @Override
-                public void destroy() {
-                    // ignored
-                }
+                    @Override
+                    public void setErrorStream(OutputStream err) {
+                        // ignored
+                    }
 
-                @Override
-                public void start(Environment env) throws IOException {
-                    if (envHolder.getAndSet(env) != null) {
-                        throw new StreamCorruptedException("Multiple starts for command=" + command);
+                    @Override
+                    public void destroy() {
+                        // ignored
                     }
 
-                    cb.onExit(0, command);
-                }
-            };
+                    @Override
+                    public void start(Environment env) throws IOException {
+                        if (envHolder.getAndSet(env) != null) {
+                            throw new StreamCorruptedException("Multiple starts for command=" + command);
+                        }
+
+                        cb.onExit(0, command);
+                    }
+                };
+            }
         });
 
         TestChannelListener channelListener = new TestChannelListener(getCurrentTestName());
@@ -934,6 +952,15 @@ public class ServerTest extends BaseTestSupport {
         // CHECKSTYLE:ON
 
         public static class Factory implements CommandFactory {
+            public Factory() {
+                super();
+            }
+
+            @Override
+            public String getName() {
+                return getClass().getSimpleName();
+            }
+
             @Override
             public Command createCommand(String name) {
                 return new StreamCommand(name);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/test/AsyncEchoShellFactory.java
----------------------------------------------------------------------
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 5193cec..de9dbf4 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
@@ -29,13 +29,13 @@ import org.apache.sshd.common.io.IoInputStream;
 import org.apache.sshd.common.io.IoOutputStream;
 import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
-import org.apache.sshd.server.AsyncCommand;
 import org.apache.sshd.server.ChannelSessionAware;
-import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
 import org.apache.sshd.server.channel.ChannelDataReceiver;
 import org.apache.sshd.server.channel.ChannelSession;
+import org.apache.sshd.server.command.AsyncCommand;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.shell.ShellFactory;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java b/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java
index c44a2ad..c199a38 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java
@@ -26,7 +26,7 @@ import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 
-import org.apache.sshd.server.AbstractCommandSupport;
+import org.apache.sshd.server.command.AbstractCommandSupport;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/test/EchoShellFactory.java
----------------------------------------------------------------------
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 fe97a2f..a9ec9d3 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,7 +18,7 @@
  */
 package org.apache.sshd.util.test;
 
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.shell.ShellFactory;
 
 /**

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/f1a8077b/sshd-git/src/main/java/org/apache/sshd/git/AbstractGitCommand.java
----------------------------------------------------------------------
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 d4dacfa..7315610 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
@@ -29,8 +29,8 @@ import java.util.concurrent.ExecutorService;
 
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.file.FileSystemAware;
-import org.apache.sshd.server.AbstractCommandSupport;
 import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.command.AbstractCommandSupport;
 import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.ServerSessionHolder;
 


Re: [2/2] mina-sshd git commit: [SSHD-819] Standardized the DelegateCommandFactory behavior

Posted by Guillaume Nodet <gn...@apache.org>.
Please revert the change and implement it again without turning the
CommandFactory into a NamedResource.
A CommandFactory is not limited to implement a single command, so having a
named on it does not make much sense to me, and it breaks all existing
implementations for no benefit.

2018-05-15 9:48 GMT+02:00 <lg...@apache.org>:

> [SSHD-819] Standardized the DelegateCommandFactory behavior
>
>
> Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
> Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/f1a8077b
> Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/f1a8077b
> Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/f1a8077b
>
> Branch: refs/heads/master
> Commit: f1a8077be3875184b067095b236793e4801c2ad5
> Parents: 3182ad8
> Author: Goldstein Lyor <ly...@c-b4.com>
> Authored: Tue May 15 10:41:24 2018 +0300
> Committer: Goldstein Lyor <ly...@c-b4.com>
> Committed: Tue May 15 10:48:02 2018 +0300
>
> ----------------------------------------------------------------------
>  .../sshd/cli/server/SshServerCliSupport.java    |   2 +-
>  .../apache/sshd/cli/server/SshServerMain.java   |   6 +-
>  .../apache/sshd/cli/server/SshFsMounter.java    |   9 +-
>  .../sshd/server/AbstractCommandSupport.java     | 168 ------------------
>  .../org/apache/sshd/server/AsyncCommand.java    |  52 ------
>  .../apache/sshd/server/ChannelSessionAware.java |   1 +
>  .../java/org/apache/sshd/server/Command.java    |  65 -------
>  .../org/apache/sshd/server/CommandFactory.java  |  40 -----
>  .../apache/sshd/server/CommandLifecycle.java    |  48 ------
>  .../sshd/server/ServerFactoryManager.java       |   2 +
>  .../java/org/apache/sshd/server/SshServer.java  |   2 +
>  .../server/channel/ChannelDataReceiver.java     |   4 +-
>  .../sshd/server/channel/ChannelSession.java     |   8 +-
>  .../server/command/AbstractCommandSupport.java  | 170 +++++++++++++++++++
>  .../AbstractDelegatingCommandFactory.java       |  76 +++++++++
>  .../sshd/server/command/AsyncCommand.java       |  52 ++++++
>  .../org/apache/sshd/server/command/Command.java |  67 ++++++++
>  .../sshd/server/command/CommandFactory.java     |  41 +++++
>  .../sshd/server/command/CommandLifecycle.java   |  50 ++++++
>  .../command/DelegatingCommandFactory.java       |  43 +++++
>  .../apache/sshd/server/shell/InvertedShell.java |   2 +-
>  .../sshd/server/shell/InvertedShellWrapper.java |   2 +-
>  .../shell/ProcessShellCommandFactory.java       |  50 ++++++
>  .../sshd/server/shell/ProcessShellFactory.java  |   2 +-
>  .../apache/sshd/server/shell/ShellFactory.java  |   2 +-
>  .../sshd/server/shell/UnknownCommand.java       |   2 +-
>  .../server/shell/UnknownCommandFactory.java     |  11 +-
>  .../sshd/server/subsystem/SubsystemFactory.java |   2 +-
>  .../java/org/apache/sshd/KeepAliveTest.java     |   2 +-
>  .../java/org/apache/sshd/KeyReExchangeTest.java |   2 +-
>  .../java/org/apache/sshd/WindowAdjustTest.java  |   2 +-
>  .../java/org/apache/sshd/agent/AgentTest.java   |   2 +-
>  .../java/org/apache/sshd/client/ClientTest.java |   2 +-
>  .../sshd/client/channel/ChannelExecTest.java    |  24 ++-
>  .../sshd/client/session/ClientSessionTest.java  |  69 +++++---
>  .../apache/sshd/common/channel/WindowTest.java  |   2 +-
>  .../java/org/apache/sshd/server/ServerTest.java | 149 +++++++++-------
>  .../sshd/util/test/AsyncEchoShellFactory.java   |   4 +-
>  .../sshd/util/test/CommandExecutionHelper.java  |   2 +-
>  .../apache/sshd/util/test/EchoShellFactory.java |   2 +-
>  .../org/apache/sshd/git/AbstractGitCommand.java |   2 +-
>  .../sshd/git/AbstractGitCommandFactory.java     |  47 ++---
>  .../sshd/git/pack/GitPackCommandFactory.java    |   7 +-
>  .../sshd/git/pgm/GitPgmCommandFactory.java      |   7 +-
>  .../org/apache/sshd/server/scp/ScpCommand.java  |   2 +-
>  .../sshd/server/scp/ScpCommandFactory.java      |  63 +++----
>  .../org/apache/sshd/client/scp/ScpTest.java     |   2 +-
>  .../sshd/server/scp/ScpCommandFactoryTest.java  |   2 +-
>  .../server/subsystem/sftp/SftpSubsystem.java    |   4 +-
>  .../subsystem/sftp/SftpSubsystemFactory.java    |   2 +-
>  .../sshd/client/subsystem/sftp/ClientTest.java  |   2 +-
>  .../sshd/client/subsystem/sftp/SftpTest.java    |   2 +-
>  .../client/subsystem/sftp/SftpVersionsTest.java |   2 +-
>  .../SpaceAvailableExtensionImplTest.java        |   2 +-
>  .../openssh/helpers/OpenSSHExtensionsTest.java  |   2 +-
>  55 files changed, 815 insertions(+), 574 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-cli/src/main/java/org/apache/sshd/cli/
> server/SshServerCliSupport.java
> ----------------------------------------------------------------------
> diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerCliSupport.java
> b/sshd-cli/src/main/java/org/apache/sshd/cli/server/
> SshServerCliSupport.java
> index 910566f..8b392bc 100644
> --- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/
> SshServerCliSupport.java
> +++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/
> SshServerCliSupport.java
> @@ -49,10 +49,10 @@ import org.apache.sshd.common.util.GenericUtils;
>  import org.apache.sshd.common.util.ValidateUtils;
>  import org.apache.sshd.common.util.security.SecurityUtils;
>  import org.apache.sshd.common.util.threads.ThreadUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.ServerAuthenticationManager;
>  import org.apache.sshd.server.ServerFactoryManager;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.config.SshServerConfigFileReader;
>  import org.apache.sshd.server.forward.ForwardingFilter;
>  import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvid
> er;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/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 cba6fc2..b9f6d1e 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
> @@ -33,13 +33,13 @@ import org.apache.sshd.common.PropertyResolverUtils;
>  import org.apache.sshd.common.config.SshConfigFileReader;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.util.GenericUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.SshServer;
>  import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticato
> r;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.config.keys.ServerIdentity;
>  import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvid
> er;
>  import org.apache.sshd.server.scp.ScpCommandFactory;
> -import org.apache.sshd.server.shell.ProcessShellFactory;
> +import org.apache.sshd.server.shell.ProcessShellCommandFactory;
>  import org.apache.sshd.server.shell.ShellFactory;
>
>  /**
> @@ -181,7 +181,7 @@ public class SshServerMain extends SshServerCliSupport
> {
>          sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticato
> r.INSTANCE);
>          setupServerForwarding(sshd, resolver);
>          sshd.setCommandFactory(new ScpCommandFactory.Builder()
> -            .withDelegate(command -> new ProcessShellFactory(GenericUtils.split(command,
> ' ')).create())
> +            .withDelegate(ProcessShellCommandFactory.INSTANCE)
>              .build());
>
>          List<NamedFactory<Command>> subsystems = resolveServerSubsystems(System.err,
> resolver);
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-cli/src/test/java/org/apache/sshd/cli/
> server/SshFsMounter.java
> ----------------------------------------------------------------------
> 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 74a5a83..c270be7 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
> @@ -43,13 +43,13 @@ import org.apache.sshd.common.util.ValidateUtils;
>  import org.apache.sshd.common.util.logging.AbstractLoggingBean;
>  import org.apache.sshd.common.util.security.SecurityUtils;
>  import org.apache.sshd.common.util.threads.ThreadUtils;
> -import org.apache.sshd.server.Command;
> -import org.apache.sshd.server.CommandFactory;
>  import org.apache.sshd.server.Environment;
>  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.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
>  import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
>  import org.apache.sshd.server.scp.ScpCommandFactory;
> @@ -232,6 +232,11 @@ public final class SshFsMounter extends
> SshServerCliSupport {
>          }
>
>          @Override
> +        public String getName() {
> +            return "mounter";
> +        }
> +
> +        @Override
>          public Command createCommand(String command) {
>              return new MounterCommand(command);
>          }
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> AbstractCommandSupport.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/AbstractCommandSupport.java
> b/sshd-core/src/main/java/org/apache/sshd/server/
> AbstractCommandSupport.java
> deleted file mode 100644
> index 7533157..0000000
> --- a/sshd-core/src/main/java/org/apache/sshd/server/
> AbstractCommandSupport.java
> +++ /dev/null
> @@ -1,168 +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.server;
> -
> -import java.io.IOException;
> -import java.io.InputStream;
> -import java.io.OutputStream;
> -import java.util.Collection;
> -import java.util.concurrent.ExecutorService;
> -import java.util.concurrent.Future;
> -
> -import org.apache.sshd.common.util.GenericUtils;
> -import org.apache.sshd.common.util.logging.AbstractLoggingBean;
> -import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
> -import org.apache.sshd.common.util.threads.ThreadUtils;
> -
> -/**
> - * Provides a basic useful skeleton for {@link Command} executions
> - *
> - * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> - */
> -public abstract class AbstractCommandSupport
> -        extends AbstractLoggingBean
> -        implements Command, Runnable, ExitCallback,
> ExecutorServiceCarrier {
> -    private final String command;
> -    private InputStream in;
> -    private OutputStream out;
> -    private OutputStream err;
> -    private ExitCallback callback;
> -    private Environment environment;
> -    private Future<?> cmdFuture;
> -    private ExecutorService executorService;
> -    private boolean shutdownOnExit;
> -    private boolean cbCalled;
> -
> -    protected AbstractCommandSupport(String command, ExecutorService
> executorService, boolean shutdownOnExit) {
> -        this.command = command;
> -
> -        if (executorService == null) {
> -            String poolName = GenericUtils.isEmpty(command) ?
> getClass().getSimpleName() : command.replace(' ', '_').replace('/', ':');
> -            this.executorService = ThreadUtils.newSingleThreadExecutor(
> poolName);
> -            this.shutdownOnExit = true;    // we always close the ad-hoc
> executor service
> -        } else {
> -            this.executorService = executorService;
> -            this.shutdownOnExit = shutdownOnExit;
> -        }
> -    }
> -
> -    public String getCommand() {
> -        return command;
> -    }
> -
> -    @Override
> -    public ExecutorService getExecutorService() {
> -        return executorService;
> -    }
> -
> -    @Override
> -    public boolean isShutdownOnExit() {
> -        return shutdownOnExit;
> -    }
> -
> -    public InputStream getInputStream() {
> -        return in;
> -    }
> -
> -    @Override
> -    public void setInputStream(InputStream in) {
> -        this.in = in;
> -    }
> -
> -    public OutputStream getOutputStream() {
> -        return out;
> -    }
> -
> -    @Override
> -    public void setOutputStream(OutputStream out) {
> -        this.out = out;
> -    }
> -
> -    public OutputStream getErrorStream() {
> -        return err;
> -    }
> -
> -    @Override
> -    public void setErrorStream(OutputStream err) {
> -        this.err = err;
> -    }
> -
> -    public ExitCallback getExitCallback() {
> -        return callback;
> -    }
> -
> -    @Override
> -    public void setExitCallback(ExitCallback callback) {
> -        this.callback = callback;
> -    }
> -
> -    public Environment getEnvironment() {
> -        return environment;
> -    }
> -
> -    protected Future<?> getStartedCommandFuture() {
> -        return cmdFuture;
> -    }
> -
> -    @Override
> -    public void start(Environment env) throws IOException {
> -        environment = env;
> -        ExecutorService executors = getExecutorService();
> -        cmdFuture = executors.submit(this);
> -    }
> -
> -    @Override
> -    public void destroy() {
> -        ExecutorService executors = getExecutorService();
> -        if ((executors != null) && (!executors.isShutdown()) &&
> isShutdownOnExit()) {
> -            Collection<Runnable> runners = executors.shutdownNow();
> -            if (log.isDebugEnabled()) {
> -                log.debug("destroy() - shutdown executor service -
> runners count=" + runners.size());
> -            }
> -        }
> -        this.executorService = null;
> -    }
> -
> -    @Override
> -    public void onExit(int exitValue, String exitMessage) {
> -        if (cbCalled) {
> -            if (log.isTraceEnabled()) {
> -                log.trace("onExit({}) ignore exitValue={}, message={} -
> already called",
> -                        this, exitValue, exitMessage);
> -            }
> -            return;
> -        }
> -
> -        ExitCallback cb = getExitCallback();
> -        try {
> -            if (log.isDebugEnabled()) {
> -                log.debug("onExit({}) exiting - value={}, message={}",
> this, exitValue, exitMessage);
> -            }
> -            cb.onExit(exitValue, exitMessage);
> -        } finally {
> -            cbCalled = true;
> -        }
> -    }
> -
> -    @Override
> -    public String toString() {
> -        return getClass().getSimpleName() + "[" + getCommand() + "]";
> -    }
> -}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
> b/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
> deleted file mode 100644
> index b49af64..0000000
> --- a/sshd-core/src/main/java/org/apache/sshd/server/AsyncCommand.java
> +++ /dev/null
> @@ -1,52 +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.server;
> -
> -import org.apache.sshd.common.io.IoInputStream;
> -import org.apache.sshd.common.io.IoOutputStream;
> -
> -/**
> - * Represents a command capable of doing non-blocking io.
> - * If this interface is implemented by a command, the usual
> - * blocking input / output / error streams won't be set.
> - */
> -public interface AsyncCommand extends Command {
> -
> -    /**
> -     * Set the input stream that can be used by the shell to read input.
> -     *
> -     * @param in The {@link IoInputStream} used by the shell to read input
> -     */
> -    void setIoInputStream(IoInputStream in);
> -
> -    /**
> -     * Set the output stream that can be used by the shell to write its
> output.
> -     *
> -     * @param out The {@link IoOutputStream} used by the shell to write
> its output
> -     */
> -    void setIoOutputStream(IoOutputStream out);
> -
> -    /**
> -     * Set the error stream that can be used by the shell to write its
> errors.
> -     *
> -     * @param err The {@link IoOutputStream} used by the shell to write
> its errors
> -     */
> -    void setIoErrorStream(IoOutputStream err);
> -
> -}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> ChannelSessionAware.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
> b/sshd-core/src/main/java/org/apache/sshd/server/ChannelSessionAware.java
> index 150e719..d6d7c8b 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/
> ChannelSessionAware.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/
> ChannelSessionAware.java
> @@ -19,6 +19,7 @@
>  package org.apache.sshd.server;
>
>  import org.apache.sshd.server.channel.ChannelSession;
> +import org.apache.sshd.server.command.Command;
>
>  /**
>   * {@link Command} can implement this optional interface
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/Command.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/Command.java
> b/sshd-core/src/main/java/org/apache/sshd/server/Command.java
> deleted file mode 100644
> index 4043e48..0000000
> --- a/sshd-core/src/main/java/org/apache/sshd/server/Command.java
> +++ /dev/null
> @@ -1,65 +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.server;
> -
> -import java.io.InputStream;
> -import java.io.OutputStream;
> -
> -/**
> - * <p>
> - * Represents a command, shell or subsystem that can be used to send
> command.
> - * </p>
> - *
> - * <p>
> - * This command have direct streams, meaning those streams will be
> provided by the ssh server
> - * for the shell to use directly. This interface is suitable for
> implementing commands in java,
> - * rather than using external processes.  For wrapping such processes or
> using inverted streams,
> - * </p>
> - * see {@link org.apache.sshd.server.shell.InvertedShellWrapper}.
> - */
> -public interface Command extends CommandLifecycle {
> -
> -    /**
> -     * Set the input stream that can be used by the shell to read input.
> -     *
> -     * @param in The {@link InputStream}  used by the shell to read input.
> -     */
> -    void setInputStream(InputStream in);
> -
> -    /**
> -     * Set the output stream that can be used by the shell to write its
> output.
> -     *
> -     * @param out The {@link OutputStream} used by the shell to write its
> output
> -     */
> -    void setOutputStream(OutputStream out);
> -
> -    /**
> -     * Set the error stream that can be used by the shell to write its
> errors.
> -     *
> -     * @param err The {@link OutputStream} used by the shell to write its
> errors
> -     */
> -    void setErrorStream(OutputStream err);
> -
> -    /**
> -     * Set the callback that the shell has to call when it is closed.
> -     *
> -     * @param callback The {@link ExitCallback} to call when shell is
> closed
> -     */
> -    void setExitCallback(ExitCallback callback);
> -}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> CommandFactory.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
> b/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
> deleted file mode 100644
> index 650abe1..0000000
> --- a/sshd-core/src/main/java/org/apache/sshd/server/CommandFactory.java
> +++ /dev/null
> @@ -1,40 +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.server;
> -
> -/**
> - * A factory of commands.
> - * Commands are executed on the server side when an "exec" channel is
> - * requested by the SSH client.
> - *
> - * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> - */
> -@FunctionalInterface
> -public interface CommandFactory {
> -
> -    /**
> -     * Create a command with the given name.
> -     * 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 command The command that will be run
> -     * @return a non {@code null} {@link Command} instance
> -     */
> -    Command createCommand(String command);
> -}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> CommandLifecycle.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
> b/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
> deleted file mode 100644
> index cbe3cf0..0000000
> --- a/sshd-core/src/main/java/org/apache/sshd/server/CommandLifecycle.java
> +++ /dev/null
> @@ -1,48 +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.server;
> -
> -import java.io.IOException;
> -
> -/**
> - * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> - */
> -public interface CommandLifecycle {
> -    /**
> -     * Starts the command execution. All streams must have been set
> <U>before</U>
> -     * calling this method. The command should implement {@link
> java.lang.Runnable},
> -     * and this method should spawn a new thread like:
> -     * <pre>
> -     * {@code Thread(this).start(); }
> -     * </pre>
> -     *
> -     * @param env The {@link Environment}
> -     * @throws IOException If failed to start
> -     */
> -    void start(Environment env) throws IOException;
> -
> -    /**
> -     * This method is called by the SSH server to destroy the command
> because
> -     * the client has disconnected somehow.
> -     *
> -     * @throws Exception if failed to destroy
> -     */
> -    void destroy() throws Exception;
> -}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> ServerFactoryManager.java
> ----------------------------------------------------------------------
> 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 68531ed..60bd655 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
> @@ -24,6 +24,8 @@ 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;
>
>  /**
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
> ----------------------------------------------------------------------
> 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 f93c5d0..35b72cc 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
> @@ -49,6 +49,8 @@ import org.apache.sshd.server.auth.hostbased.
> HostBasedAuthenticator;
>  import org.apache.sshd.server.auth.keyboard.
> KeyboardInteractiveAuthenticator;
>  import org.apache.sshd.server.auth.password.PasswordAuthenticator;
>  import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.server.session.ServerConnectionServiceFactory;
>  import org.apache.sshd.server.session.ServerProxyAcceptor;
>  import org.apache.sshd.server.session.ServerUserAuthServiceFactory;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> channel/ChannelDataReceiver.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelDataReceiver.java
> b/sshd-core/src/main/java/org/apache/sshd/server/channel/
> ChannelDataReceiver.java
> index f336c89..59ade13 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/channel/
> ChannelDataReceiver.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/
> ChannelDataReceiver.java
> @@ -30,10 +30,10 @@ import java.io.IOException;
>   * Sequence of bytes that SSH client sends to the server is eventually
> sent to this interface
>   * to be passed on to the final consumer.
>   * By default {@link ChannelSession} spools this in a buffer so that you
> can read it from
> - * the input stream you get from {@link org.apache.sshd.server.
> Command#setInputStream(java.io.InputStream)}, but if command
> + * the input stream you get from {@link org.apache.sshd.server.
> command.Command#setInputStream(java.io.InputStream)}, but if command
>   * wants to do a callback-driven I/O for the data it receives from the
> client, it can
>   * call {@link ChannelSession#setDataReceiver(ChannelDataReceiver)} to
> do so.
> - * (And to grab a reference to {@link ChannelSession}, a {@link
> org.apache.sshd.server.Command} should implement
> + * (And to grab a reference to {@link ChannelSession}, a {@link
> org.apache.sshd.server.command.Command} should implement
>   * {@link org.apache.sshd.server.ChannelSessionAware}.)
>   * </p>
>   *
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> channel/ChannelSession.java
> ----------------------------------------------------------------------
> 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 b884d80..cfaa499 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
> @@ -62,15 +62,15 @@ import org.apache.sshd.common.util.
> buffer.ByteArrayBuffer;
>  import org.apache.sshd.common.util.closeable.IoBaseCloseable;
>  import org.apache.sshd.common.util.io.IoUtils;
>  import org.apache.sshd.common.util.io.LoggingFilterOutputStream;
> -import org.apache.sshd.server.AsyncCommand;
>  import org.apache.sshd.server.ChannelSessionAware;
> -import org.apache.sshd.server.Command;
> -import org.apache.sshd.server.CommandFactory;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ServerFactoryManager;
>  import org.apache.sshd.server.SessionAware;
>  import org.apache.sshd.server.Signal;
>  import org.apache.sshd.server.StandardEnvironment;
> +import org.apache.sshd.server.command.AsyncCommand;
> +import org.apache.sshd.server.command.Command;
> +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;
> @@ -602,7 +602,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.AsyncCommand#setIoInputStream(
> org.apache.sshd.common.io.IoInputStream)}
> +     * {@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)},
>       * the input stream you received in {@link
> Command#setInputStream(java.io.InputStream)} will
>       * not read any data.
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/
> AbstractCommandSupport.java
> ----------------------------------------------------------------------
> 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
> new file mode 100644
> index 0000000..58cf034
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> AbstractCommandSupport.java
> @@ -0,0 +1,170 @@
> +/*
> + * 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.server.command;
> +
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.io.OutputStream;
> +import java.util.Collection;
> +import java.util.concurrent.ExecutorService;
> +import java.util.concurrent.Future;
> +
> +import org.apache.sshd.common.util.GenericUtils;
> +import org.apache.sshd.common.util.logging.AbstractLoggingBean;
> +import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
> +import org.apache.sshd.common.util.threads.ThreadUtils;
> +import org.apache.sshd.server.Environment;
> +import org.apache.sshd.server.ExitCallback;
> +
> +/**
> + * Provides a basic useful skeleton for {@link Command} executions
> + *
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public abstract class AbstractCommandSupport
> +        extends AbstractLoggingBean
> +        implements Command, Runnable, ExitCallback,
> ExecutorServiceCarrier {
> +    private final String command;
> +    private InputStream in;
> +    private OutputStream out;
> +    private OutputStream err;
> +    private ExitCallback callback;
> +    private Environment environment;
> +    private Future<?> cmdFuture;
> +    private ExecutorService executorService;
> +    private boolean shutdownOnExit;
> +    private boolean cbCalled;
> +
> +    protected AbstractCommandSupport(String command, ExecutorService
> executorService, boolean shutdownOnExit) {
> +        this.command = command;
> +
> +        if (executorService == null) {
> +            String poolName = GenericUtils.isEmpty(command) ?
> getClass().getSimpleName() : command.replace(' ', '_').replace('/', ':');
> +            this.executorService = ThreadUtils.newSingleThreadExecutor(
> poolName);
> +            this.shutdownOnExit = true;    // we always close the ad-hoc
> executor service
> +        } else {
> +            this.executorService = executorService;
> +            this.shutdownOnExit = shutdownOnExit;
> +        }
> +    }
> +
> +    public String getCommand() {
> +        return command;
> +    }
> +
> +    @Override
> +    public ExecutorService getExecutorService() {
> +        return executorService;
> +    }
> +
> +    @Override
> +    public boolean isShutdownOnExit() {
> +        return shutdownOnExit;
> +    }
> +
> +    public InputStream getInputStream() {
> +        return in;
> +    }
> +
> +    @Override
> +    public void setInputStream(InputStream in) {
> +        this.in = in;
> +    }
> +
> +    public OutputStream getOutputStream() {
> +        return out;
> +    }
> +
> +    @Override
> +    public void setOutputStream(OutputStream out) {
> +        this.out = out;
> +    }
> +
> +    public OutputStream getErrorStream() {
> +        return err;
> +    }
> +
> +    @Override
> +    public void setErrorStream(OutputStream err) {
> +        this.err = err;
> +    }
> +
> +    public ExitCallback getExitCallback() {
> +        return callback;
> +    }
> +
> +    @Override
> +    public void setExitCallback(ExitCallback callback) {
> +        this.callback = callback;
> +    }
> +
> +    public Environment getEnvironment() {
> +        return environment;
> +    }
> +
> +    protected Future<?> getStartedCommandFuture() {
> +        return cmdFuture;
> +    }
> +
> +    @Override
> +    public void start(Environment env) throws IOException {
> +        environment = env;
> +        ExecutorService executors = getExecutorService();
> +        cmdFuture = executors.submit(this);
> +    }
> +
> +    @Override
> +    public void destroy() {
> +        ExecutorService executors = getExecutorService();
> +        if ((executors != null) && (!executors.isShutdown()) &&
> isShutdownOnExit()) {
> +            Collection<Runnable> runners = executors.shutdownNow();
> +            if (log.isDebugEnabled()) {
> +                log.debug("destroy() - shutdown executor service -
> runners count=" + runners.size());
> +            }
> +        }
> +        this.executorService = null;
> +    }
> +
> +    @Override
> +    public void onExit(int exitValue, String exitMessage) {
> +        if (cbCalled) {
> +            if (log.isTraceEnabled()) {
> +                log.trace("onExit({}) ignore exitValue={}, message={} -
> already called",
> +                        this, exitValue, exitMessage);
> +            }
> +            return;
> +        }
> +
> +        ExitCallback cb = getExitCallback();
> +        try {
> +            if (log.isDebugEnabled()) {
> +                log.debug("onExit({}) exiting - value={}, message={}",
> this, exitValue, exitMessage);
> +            }
> +            cb.onExit(exitValue, exitMessage);
> +        } finally {
> +            cbCalled = true;
> +        }
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return getClass().getSimpleName() + "[" + getCommand() + "]";
> +    }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/
> AbstractDelegatingCommandFactory.java
> ----------------------------------------------------------------------
> 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
> new file mode 100644
> index 0000000..3169958
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> AbstractDelegatingCommandFactory.java
> @@ -0,0 +1,76 @@
> +/*
> + * 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.server.command;
> +
> +import org.apache.sshd.common.util.ValidateUtils;
> +import org.apache.sshd.common.util.logging.AbstractLoggingBean;
> +
> +/**
> + * TODO Add javadoc
> + *
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public abstract class AbstractDelegatingCommandFactory extends
> AbstractLoggingBean implements DelegatingCommandFactory {
> +    private final String name;
> +    /*
> +     * NOTE: we expose setters since there is no problem to change these
> settings between
> +     * successive invocations of the 'createCommand' method
> +     */
> +    private CommandFactory delegate;
> +
> +    protected AbstractDelegatingCommandFactory(String name) {
> +        this.name = ValidateUtils.checkNotNullAndNotEmpty(name, "No
> delegating command factory name provided");
> +    }
> +
> +    @Override
> +    public String getName() {
> +        return name;
> +    }
> +
> +    @Override
> +    public CommandFactory getDelegateCommandFactory() {
> +        return delegate;
> +    }
> +
> +    @Override
> +    public void setDelegateCommandFactory(CommandFactory factory) {
> +        delegate = factory;
> +    }
> +
> +    @Override
> +    public Command createCommand(String command) {
> +        if (isSupportedCommand(command)) {
> +            return executeSupportedCommand(command);
> +        }
> +
> +        CommandFactory factory = getDelegateCommandFactory();
> +        if (factory != null) {
> +            return factory.createCommand(command);
> +        }
> +
> +        return createUnsupportedCommand(command);
> +    }
> +
> +    protected abstract Command executeSupportedCommand(String command);
> +
> +    protected Command createUnsupportedCommand(String command) {
> +        throw new IllegalArgumentException("Unknown command to execute:
> " + command);
> +    }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> command/AsyncCommand.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java
> b/sshd-core/src/main/java/org/apache/sshd/server/command/AsyncCommand.java
> new file mode 100644
> index 0000000..f3d2173
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> AsyncCommand.java
> @@ -0,0 +1,52 @@
> +/*
> + * 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.server.command;
> +
> +import org.apache.sshd.common.io.IoInputStream;
> +import org.apache.sshd.common.io.IoOutputStream;
> +
> +/**
> + * Represents a command capable of doing non-blocking io.
> + * If this interface is implemented by a command, the usual
> + * blocking input / output / error streams won't be set.
> + */
> +public interface AsyncCommand extends Command {
> +
> +    /**
> +     * Set the input stream that can be used by the shell to read input.
> +     *
> +     * @param in The {@link IoInputStream} used by the shell to read input
> +     */
> +    void setIoInputStream(IoInputStream in);
> +
> +    /**
> +     * Set the output stream that can be used by the shell to write its
> output.
> +     *
> +     * @param out The {@link IoOutputStream} used by the shell to write
> its output
> +     */
> +    void setIoOutputStream(IoOutputStream out);
> +
> +    /**
> +     * Set the error stream that can be used by the shell to write its
> errors.
> +     *
> +     * @param err The {@link IoOutputStream} used by the shell to write
> its errors
> +     */
> +    void setIoErrorStream(IoOutputStream err);
> +
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> command/Command.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
> b/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
> new file mode 100644
> index 0000000..5425d3a
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/Command.java
> @@ -0,0 +1,67 @@
> +/*
> + * 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.server.command;
> +
> +import java.io.InputStream;
> +import java.io.OutputStream;
> +
> +import org.apache.sshd.server.ExitCallback;
> +
> +/**
> + * <p>
> + * Represents a command, shell or subsystem that can be used to send
> command.
> + * </p>
> + *
> + * <p>
> + * This command have direct streams, meaning those streams will be
> provided by the ssh server
> + * for the shell to use directly. This interface is suitable for
> implementing commands in java,
> + * rather than using external processes.  For wrapping such processes or
> using inverted streams,
> + * </p>
> + * see {@link org.apache.sshd.server.shell.InvertedShellWrapper}.
> + */
> +public interface Command extends CommandLifecycle {
> +
> +    /**
> +     * Set the input stream that can be used by the shell to read input.
> +     *
> +     * @param in The {@link InputStream}  used by the shell to read input.
> +     */
> +    void setInputStream(InputStream in);
> +
> +    /**
> +     * Set the output stream that can be used by the shell to write its
> output.
> +     *
> +     * @param out The {@link OutputStream} used by the shell to write its
> output
> +     */
> +    void setOutputStream(OutputStream out);
> +
> +    /**
> +     * Set the error stream that can be used by the shell to write its
> errors.
> +     *
> +     * @param err The {@link OutputStream} used by the shell to write its
> errors
> +     */
> +    void setErrorStream(OutputStream err);
> +
> +    /**
> +     * Set the callback that the shell has to call when it is closed.
> +     *
> +     * @param callback The {@link ExitCallback} to call when shell is
> closed
> +     */
> +    void setExitCallback(ExitCallback callback);
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> command/CommandFactory.java
> ----------------------------------------------------------------------
> 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
> new file mode 100644
> index 0000000..aff407b
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> CommandFactory.java
> @@ -0,0 +1,41 @@
> +/*
> + * 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.server.command;
> +
> +import org.apache.sshd.common.NamedResource;
> +
> +/**
> + * A factory of commands.
> + * Commands are executed on the server side when an "exec" channel is
> + * requested by the SSH client.
> + *
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public interface CommandFactory extends NamedResource {
> +
> +    /**
> +     * Create a command with the given name.
> +     * 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 command The command that will be run
> +     * @return a non {@code null} {@link Command} instance
> +     */
> +    Command createCommand(String command);
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> command/CommandLifecycle.java
> ----------------------------------------------------------------------
> 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
> new file mode 100644
> index 0000000..ac694d5
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> CommandLifecycle.java
> @@ -0,0 +1,50 @@
> +/*
> + * 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.server.command;
> +
> +import java.io.IOException;
> +
> +import org.apache.sshd.server.Environment;
> +
> +/**
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public interface CommandLifecycle {
> +    /**
> +     * Starts the command execution. All streams must have been set
> <U>before</U>
> +     * calling this method. The command should implement {@link
> java.lang.Runnable},
> +     * and this method should spawn a new thread like:
> +     * <pre>
> +     * {@code Thread(this).start(); }
> +     * </pre>
> +     *
> +     * @param env The {@link Environment}
> +     * @throws IOException If failed to start
> +     */
> +    void start(Environment env) throws IOException;
> +
> +    /**
> +     * This method is called by the SSH server to destroy the command
> because
> +     * the client has disconnected somehow.
> +     *
> +     * @throws Exception if failed to destroy
> +     */
> +    void destroy() throws Exception;
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/command/
> DelegatingCommandFactory.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/command/DelegatingCommandFactory.java
> b/sshd-core/src/main/java/org/apache/sshd/server/command/
> DelegatingCommandFactory.java
> new file mode 100644
> index 0000000..e1ce89c
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/command/
> DelegatingCommandFactory.java
> @@ -0,0 +1,43 @@
> +/*
> + * 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.server.command;
> +
> +/**
> + * Represents a {@link CommandFactory} that filters the commands it
> recognizes
> + * and delegates the ones it doesn't to another delegate factory. The
> behavior
> + * of such a delegating factory is undefined if it receives a command it
> does
> + * not recognize and not delegate has been set. The recommended behavior
> in this
> + * case is to throw some exception - though this is not mandatory
> + *
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public interface DelegatingCommandFactory extends CommandFactory {
> +    CommandFactory getDelegateCommandFactory();
> +
> +    void setDelegateCommandFactory(CommandFactory factory);
> +
> +    /**
> +     * @param command The command about to be executed
> +     * @return {@code true} if this command is supported by the command
> +     * factory, {@code false} if it will be passed on to the
> +     * {@link #getDelegateCommandFactory() delegate} factory
> +     */
> +    boolean isSupportedCommand(String command);
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/InvertedShell.java
> ----------------------------------------------------------------------
> 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 3d7de3c..3abc523 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
> @@ -21,8 +21,8 @@ package org.apache.sshd.server.shell;
>  import java.io.InputStream;
>  import java.io.OutputStream;
>
> -import org.apache.sshd.server.CommandLifecycle;
>  import org.apache.sshd.server.SessionAware;
> +import org.apache.sshd.server.command.CommandLifecycle;
>
>  /**
>   * This shell have inverted streams, such as the one obtained when
> launching a
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/InvertedShellWrapper.java
> ----------------------------------------------------------------------
> 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 4819064..3c19e2c 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
> @@ -31,10 +31,10 @@ 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.common.util.threads.ThreadUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ExitCallback;
>  import org.apache.sshd.server.SessionAware;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.session.ServerSession;
>
>  /**
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/shell/
> ProcessShellCommandFactory.java
> ----------------------------------------------------------------------
> 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
> new file mode 100644
> index 0000000..af9af82
> --- /dev/null
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/shell/
> ProcessShellCommandFactory.java
> @@ -0,0 +1,50 @@
> +/*
> + * 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.server.shell;
> +
> +import org.apache.sshd.common.Factory;
> +import org.apache.sshd.common.util.GenericUtils;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
> +
> +/**
> + * Executes commands by invoking the underlying shell
> + *
> + * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
> + */
> +public class ProcessShellCommandFactory implements CommandFactory {
> +    public static final String FACTORY_NAME = "shell-command";
> +    public static final ProcessShellCommandFactory INSTANCE = new
> ProcessShellCommandFactory();
> +
> +    public ProcessShellCommandFactory() {
> +        super();
> +    }
> +
> +    @Override
> +    public String getName() {
> +        return FACTORY_NAME;
> +    }
> +
> +    @Override
> +    public Command createCommand(String command) {
> +        Factory<Command> factory = new ProcessShellFactory(GenericUtils.split(command,
> ' '));
> +        return factory.create();
> +    }
> +}
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/ProcessShellFactory.java
> ----------------------------------------------------------------------
> 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 3398e63..529b701 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,7 +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.Command;
> +import org.apache.sshd.server.command.Command;
>
>  /**
>   * A {@link Factory} of {@link Command} that will create a new process
> and bridge
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/ShellFactory.java
> ----------------------------------------------------------------------
> 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 0a80f67..d403d42 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
> @@ -20,7 +20,7 @@
>  package org.apache.sshd.server.shell;
>
>  import org.apache.sshd.common.Factory;
> -import org.apache.sshd.server.Command;
> +import org.apache.sshd.server.command.Command;
>
>  /**
>   * Useful marker interface
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/UnknownCommand.java
> ----------------------------------------------------------------------
> 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 59d970c..43b9b9f 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
> @@ -25,9 +25,9 @@ import java.nio.charset.StandardCharsets;
>  import java.util.Objects;
>
>  import org.apache.sshd.common.util.ValidateUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ExitCallback;
> +import org.apache.sshd.server.command.Command;
>
>  /**
>   * Implementation of an unknown command that can be returned by
> <code>CommandFactory</code>
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> shell/UnknownCommandFactory.java
> ----------------------------------------------------------------------
> 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 871ca60..ea94525 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,13 +19,15 @@
>
>  package org.apache.sshd.server.shell;
>
> -import org.apache.sshd.server.Command;
> -import org.apache.sshd.server.CommandFactory;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>
>  /**
>   * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
>   */
>  public class UnknownCommandFactory implements CommandFactory {
> +    public static final String FACTORY_NAME = "unknown";
> +
>      public static final UnknownCommandFactory INSTANCE = new
> UnknownCommandFactory();
>
>      public UnknownCommandFactory() {
> @@ -33,6 +35,11 @@ public class UnknownCommandFactory implements
> CommandFactory {
>      }
>
>      @Override
> +    public String getName() {
> +        return FACTORY_NAME;
> +    }
> +
> +    @Override
>      public Command createCommand(String command) {
>          return new UnknownCommand(command);
>      }
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/main/java/org/apache/sshd/server/
> subsystem/SubsystemFactory.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/SubsystemFactory.java
> b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/
> SubsystemFactory.java
> index f9dbf0f..8b0cc3f 100644
> --- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/
> SubsystemFactory.java
> +++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/
> SubsystemFactory.java
> @@ -20,7 +20,7 @@
>  package org.apache.sshd.server.subsystem;
>
>  import org.apache.sshd.common.NamedFactory;
> -import org.apache.sshd.server.Command;
> +import org.apache.sshd.server.command.Command;
>
>  /**
>   * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
> ----------------------------------------------------------------------
> 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 dd649e5..4e09447 100644
> --- a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
> +++ b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
> @@ -32,8 +32,8 @@ import org.apache.sshd.client.session.ClientSession;
>  import org.apache.sshd.common.FactoryManager;
>  import org.apache.sshd.common.PropertyResolverUtils;
>  import org.apache.sshd.common.channel.Channel;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.apache.sshd.util.test.EchoShell;
>  import org.apache.sshd.util.test.EchoShellFactory;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
> ----------------------------------------------------------------------
> 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 f2ca9df..4fdb932 100644
> --- a/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
> +++ b/sshd-core/src/test/java/org/apache/sshd/KeyReExchangeTest.java
> @@ -55,10 +55,10 @@ import org.apache.sshd.common.session.Session;
>  import org.apache.sshd.common.session.SessionListener;
>  import org.apache.sshd.common.util.io.NullOutputStream;
>  import org.apache.sshd.common.util.security.SecurityUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ExitCallback;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.subsystem.SubsystemFactory;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.apache.sshd.util.test.JSchLogger;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
> ----------------------------------------------------------------------
> 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 cac8e32..fd1fd84 100644
> --- a/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
> +++ b/sshd-core/src/test/java/org/apache/sshd/WindowAdjustTest.java
> @@ -45,10 +45,10 @@ import org.apache.sshd.common.util.
> buffer.ByteArrayBuffer;
>  import org.apache.sshd.common.util.io.NoCloseOutputStream;
>  import org.apache.sshd.common.util.logging.AbstractLoggingBean;
>  import org.apache.sshd.common.util.threads.ThreadUtils;
> -import org.apache.sshd.server.AsyncCommand;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ExitCallback;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.AsyncCommand;
>  import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.junit.After;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
> ----------------------------------------------------------------------
> 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 f252be7..7deebfc 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
> @@ -38,9 +38,9 @@ import org.apache.sshd.client.channel.ChannelShell;
>  import org.apache.sshd.client.session.ClientSession;
>  import org.apache.sshd.common.keyprovider.KeyPairProvider;
>  import org.apache.sshd.common.util.security.SecurityUtils;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.apache.sshd.util.test.EchoShell;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/ClientTest.java
> ----------------------------------------------------------------------
> 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 f3d94a8..0026cc3 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
> @@ -95,13 +95,13 @@ import org.apache.sshd.common.util.buffer.Buffer;
>  import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
>  import org.apache.sshd.common.util.io.NoCloseOutputStream;
>  import org.apache.sshd.common.util.net.SshdSocketAddress;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.SshServer;
>  import org.apache.sshd.server.auth.keyboard.
> DefaultKeyboardInteractiveAuthenticator;
>  import org.apache.sshd.server.auth.keyboard.
> KeyboardInteractiveAuthenticator;
>  import org.apache.sshd.server.auth.password.
> RejectAllPasswordAuthenticator;
>  import org.apache.sshd.server.channel.ChannelSession;
>  import org.apache.sshd.server.channel.ChannelSessionFactory;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.forward.DirectTcpipFactory;
>  import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
>  import org.apache.sshd.server.session.ServerConnectionServiceFactory;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/
> channel/ChannelExecTest.java
> ----------------------------------------------------------------------
> 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 038ce55..8a48daf 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
> @@ -26,6 +26,8 @@ import java.util.concurrent.TimeUnit;
>  import org.apache.sshd.client.SshClient;
>  import org.apache.sshd.client.session.ClientSession;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.apache.sshd.util.test.CommandExecutionHelper;
>  import org.apache.sshd.util.test.Utils;
> @@ -51,13 +53,23 @@ public class ChannelExecTest extends BaseTestSupport {
>      @BeforeClass
>      public static void setupClientAndServer() throws Exception {
>          sshd = Utils.setupTestServer(ChannelExecTest.class);
> -        sshd.setCommandFactory(command -> new CommandExecutionHelper(command)
> {
> +        sshd.setCommandFactory(new CommandFactory() {
>              @Override
> -            protected boolean handleCommandLine(String command) throws
> Exception {
> -                OutputStream stdout = getOutputStream();
> -                stdout.write(command.getBytes(
> StandardCharsets.US_ASCII));
> -                stdout.flush();
> -                return false;
> +            public String getName() {
> +                return ChannelExecTest.class.getSimpleName();
> +            }
> +
> +            @Override
> +            public Command createCommand(String command) {
> +                return new CommandExecutionHelper(command) {
> +                    @Override
> +                    protected boolean handleCommandLine(String command)
> throws Exception {
> +                        OutputStream stdout = getOutputStream();
> +                        stdout.write(command.getBytes(
> StandardCharsets.US_ASCII));
> +                        stdout.flush();
> +                        return false;
> +                    }
> +                };
>              }
>          });
>          sshd.start();
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/client/
> session/ClientSessionTest.java
> ----------------------------------------------------------------------
> 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 aeb5e3b..517b07c 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
> @@ -26,9 +26,9 @@ import java.rmi.ServerException;
>  import java.util.concurrent.TimeUnit;
>
>  import org.apache.sshd.client.SshClient;
> -import org.apache.sshd.server.Command;
> -import org.apache.sshd.server.CommandFactory;
>  import org.apache.sshd.server.SshServer;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.util.test.BaseTestSupport;
>  import org.apache.sshd.util.test.CommandExecutionHelper;
>  import org.apache.sshd.util.test.Utils;
> @@ -84,18 +84,28 @@ 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)
> {
> -            private boolean cmdProcessed;
> +        sshd.setCommandFactory(new CommandFactory() {
> +            @Override
> +            public String getName() {
> +                return getCurrentTestName();
> +            }
>
>              @Override
> -            protected boolean handleCommandLine(String command) throws
> Exception {
> -                assertEquals("Mismatched incoming command",
> expectedCommand, command);
> -                assertFalse("Duplicated command call", cmdProcessed);
> -                OutputStream stdout = getOutputStream();
> -                stdout.write(expectedResponse.
> getBytes(StandardCharsets.US_ASCII));
> -                stdout.flush();
> -                cmdProcessed = true;
> -                return false;
> +            public Command createCommand(String command) {
> +                return new CommandExecutionHelper(command) {
> +                    private boolean cmdProcessed;
> +
> +                    @Override
> +                    protected boolean handleCommandLine(String command)
> throws Exception {
> +                        assertEquals("Mismatched incoming command",
> expectedCommand, command);
> +                        assertFalse("Duplicated command call",
> cmdProcessed);
> +                        OutputStream stdout = getOutputStream();
> +                        stdout.write(expectedResponse.
> getBytes(StandardCharsets.US_ASCII));
> +                        stdout.flush();
> +                        cmdProcessed = true;
> +                        return false;
> +                    }
> +                };
>              }
>          });
>
> @@ -113,18 +123,28 @@ 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)
> {
> -            private boolean cmdProcessed;
> +        sshd.setCommandFactory(new CommandFactory() {
> +            @Override
> +            public String getName() {
> +                return getCurrentTestName();
> +            }
>
>              @Override
> -            protected boolean handleCommandLine(String command) throws
> Exception {
> -                assertEquals("Mismatched incoming command",
> expectedCommand, command);
> -                assertFalse("Duplicated command call", cmdProcessed);
> -                OutputStream stderr = getErrorStream();
> -                stderr.write(expectedErrorMessage.getBytes(
> StandardCharsets.US_ASCII));
> -                stderr.flush();
> -                cmdProcessed = true;
> -                return false;
> +            public Command createCommand(String command) {
> +                return new CommandExecutionHelper(command) {
> +                    private boolean cmdProcessed;
> +
> +                    @Override
> +                    protected boolean handleCommandLine(String command)
> throws Exception {
> +                        assertEquals("Mismatched incoming command",
> expectedCommand, command);
> +                        assertFalse("Duplicated command call",
> cmdProcessed);
> +                        OutputStream stderr = getErrorStream();
> +                        stderr.write(expectedErrorMessage.getBytes(
> StandardCharsets.US_ASCII));
> +                        stderr.flush();
> +                        cmdProcessed = true;
> +                        return false;
> +                    }
> +                };
>              }
>          });
>
> @@ -158,6 +178,11 @@ public class ClientSessionTest extends
> BaseTestSupport {
>          final int exepectedErrorCode = 7365;
>          sshd.setCommandFactory(new CommandFactory() {
>              @Override
> +            public String getName() {
> +                return getCurrentTestName();
> +            }
> +
> +            @Override
>              public Command createCommand(String command) {
>                  return new CommandExecutionHelper(command) {
>                      private boolean cmdProcessed;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/common/
> channel/WindowTest.java
> ----------------------------------------------------------------------
> 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 93c37be..864fc23 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
> @@ -45,10 +45,10 @@ import org.apache.sshd.common.io.IoReadFuture;
>  import org.apache.sshd.common.session.Session;
>  import org.apache.sshd.common.util.buffer.Buffer;
>  import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.SshServer;
>  import org.apache.sshd.server.channel.ChannelSession;
>  import org.apache.sshd.server.channel.ChannelSessionFactory;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.forward.DirectTcpipFactory;
>  import org.apache.sshd.server.session.ServerConnectionService;
>  import org.apache.sshd.server.session.ServerConnectionServiceFactory;
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/server/ServerTest.java
> ----------------------------------------------------------------------
> 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 8c083a3..d1955ef 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
> @@ -72,6 +72,8 @@ 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.RejectAllPublickeyAuthenticato
> r;
> +import org.apache.sshd.server.command.Command;
> +import org.apache.sshd.server.command.CommandFactory;
>  import org.apache.sshd.server.session.ServerSession;
>  import org.apache.sshd.server.session.ServerSessionImpl;
>  import org.apache.sshd.util.test.BaseTestSupport;
> @@ -522,43 +524,51 @@ public class ServerTest extends BaseTestSupport {
>      @Test   // see SSHD-645
>      public void testChannelStateChangeNotifications() throws Exception {
>          final Semaphore exitSignal = new Semaphore(0);
> -        sshd.setCommandFactory(command -> {
> -            ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command,
> getCurrentTestName()) == 0, "Unexpected command: %s", command);
> +        sshd.setCommandFactory(new CommandFactory() {
> +            @Override
> +            public String getName() {
> +                return getCurrentTestName();
> +            }
>
> -            return new Command() {
> -                private ExitCallback cb;
> +            @Override
> +            public Command createCommand(String command) {
> +                ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command,
> getCurrentTestName()) == 0, "Unexpected command: %s", command);
>
> -                @Override
> -                public void setOutputStream(OutputStream out) {
> -                    // ignored
> -                }
> +                return new Command() {
> +                    private ExitCallback cb;
>
> -                @Override
> -                public void setInputStream(InputStream in) {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setOutputStream(OutputStream out) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void setExitCallback(ExitCallback callback) {
> -                    cb = callback;
> -                }
> +                    @Override
> +                    public void setInputStream(InputStream in) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void setErrorStream(OutputStream err) {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setExitCallback(ExitCallback callback) {
> +                        cb = callback;
> +                    }
>
> -                @Override
> -                public void destroy() {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setErrorStream(OutputStream err) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void start(Environment env) throws IOException {
> -                    exitSignal.release();
> -                    cb.onExit(0, command);
> -                }
> -            };
> +                    @Override
> +                    public void destroy() {
> +                        // ignored
> +                    }
> +
> +                    @Override
> +                    public void start(Environment env) throws IOException
> {
> +                        exitSignal.release();
> +                        cb.onExit(0, command);
> +                    }
> +                };
> +            }
>          });
>          sshd.start();
>          client.start();
> @@ -595,46 +605,54 @@ public class ServerTest extends BaseTestSupport {
>      @Test
>      public void testEnvironmentVariablesPropagationToServer() throws
> Exception {
>          final AtomicReference<Environment> envHolder = new
> AtomicReference<>(null);
> -        sshd.setCommandFactory(command -> {
> -            ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command,
> getCurrentTestName()) == 0, "Unexpected command: %s", command);
> +        sshd.setCommandFactory(new CommandFactory() {
> +            @Override
> +            public String getName() {
> +                return getCurrentTestName();
> +            }
>
> -            return new Command() {
> -                private ExitCallback cb;
> +            @Override
> +            public Command createCommand(String command) {
> +                ValidateUtils.checkTrue(String.CASE_INSENSITIVE_ORDER.compare(command,
> getCurrentTestName()) == 0, "Unexpected command: %s", command);
>
> -                @Override
> -                public void setOutputStream(OutputStream out) {
> -                    // ignored
> -                }
> +                return new Command() {
> +                    private ExitCallback cb;
>
> -                @Override
> -                public void setInputStream(InputStream in) {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setOutputStream(OutputStream out) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void setExitCallback(ExitCallback callback) {
> -                    cb = callback;
> -                }
> +                    @Override
> +                    public void setInputStream(InputStream in) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void setErrorStream(OutputStream err) {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setExitCallback(ExitCallback callback) {
> +                        cb = callback;
> +                    }
>
> -                @Override
> -                public void destroy() {
> -                    // ignored
> -                }
> +                    @Override
> +                    public void setErrorStream(OutputStream err) {
> +                        // ignored
> +                    }
>
> -                @Override
> -                public void start(Environment env) throws IOException {
> -                    if (envHolder.getAndSet(env) != null) {
> -                        throw new StreamCorruptedException("Multiple
> starts for command=" + command);
> +                    @Override
> +                    public void destroy() {
> +                        // ignored
>                      }
>
> -                    cb.onExit(0, command);
> -                }
> -            };
> +                    @Override
> +                    public void start(Environment env) throws IOException
> {
> +                        if (envHolder.getAndSet(env) != null) {
> +                            throw new StreamCorruptedException("Multiple
> starts for command=" + command);
> +                        }
> +
> +                        cb.onExit(0, command);
> +                    }
> +                };
> +            }
>          });
>
>          TestChannelListener channelListener = new TestChannelListener(
> getCurrentTestName());
> @@ -934,6 +952,15 @@ public class ServerTest extends BaseTestSupport {
>          // CHECKSTYLE:ON
>
>          public static class Factory implements CommandFactory {
> +            public Factory() {
> +                super();
> +            }
> +
> +            @Override
> +            public String getName() {
> +                return getClass().getSimpleName();
> +            }
> +
>              @Override
>              public Command createCommand(String name) {
>                  return new StreamCommand(name);
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/
> test/AsyncEchoShellFactory.java
> ----------------------------------------------------------------------
> 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 5193cec..de9dbf4 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
> @@ -29,13 +29,13 @@ import org.apache.sshd.common.io.IoInputStream;
>  import org.apache.sshd.common.io.IoOutputStream;
>  import org.apache.sshd.common.session.Session;
>  import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
> -import org.apache.sshd.server.AsyncCommand;
>  import org.apache.sshd.server.ChannelSessionAware;
> -import org.apache.sshd.server.Command;
>  import org.apache.sshd.server.Environment;
>  import org.apache.sshd.server.ExitCallback;
>  import org.apache.sshd.server.channel.ChannelDataReceiver;
>  import org.apache.sshd.server.channel.ChannelSession;
> +import org.apache.sshd.server.command.AsyncCommand;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.shell.ShellFactory;
>
>  /**
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/
> test/CommandExecutionHelper.java
> ----------------------------------------------------------------------
> diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/CommandExecutionHelper.java
> b/sshd-core/src/test/java/org/apache/sshd/util/test/
> CommandExecutionHelper.java
> index c44a2ad..c199a38 100644
> --- a/sshd-core/src/test/java/org/apache/sshd/util/test/
> CommandExecutionHelper.java
> +++ b/sshd-core/src/test/java/org/apache/sshd/util/test/
> CommandExecutionHelper.java
> @@ -26,7 +26,7 @@ import java.io.InterruptedIOException;
>  import java.io.OutputStream;
>  import java.nio.charset.StandardCharsets;
>
> -import org.apache.sshd.server.AbstractCommandSupport;
> +import org.apache.sshd.server.command.AbstractCommandSupport;
>
>  /**
>   * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD
> Project</a>
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-core/src/test/java/org/apache/sshd/util/
> test/EchoShellFactory.java
> ----------------------------------------------------------------------
> 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 fe97a2f..a9ec9d3 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,7 +18,7 @@
>   */
>  package org.apache.sshd.util.test;
>
> -import org.apache.sshd.server.Command;
> +import org.apache.sshd.server.command.Command;
>  import org.apache.sshd.server.shell.ShellFactory;
>
>  /**
>
> http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/
> f1a8077b/sshd-git/src/main/java/org/apache/sshd/git/
> AbstractGitCommand.java
> ----------------------------------------------------------------------
> 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 d4dacfa..7315610 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
> @@ -29,8 +29,8 @@ import java.util.concurrent.ExecutorService;
>
>  import org.apache.sshd.common.channel.ChannelOutputStream;
>  import org.apache.sshd.common.file.FileSystemAware;
> -import org.apache.sshd.server.AbstractCommandSupport;
>  import org.apache.sshd.server.SessionAware;
> +import org.apache.sshd.server.command.AbstractCommandSupport;
>  import org.apache.sshd.server.session.ServerSession;
>  import org.apache.sshd.server.session.ServerSessionHolder;
>
>
>


-- 
------------------------
Guillaume Nodet