Class Example-Java SSH Client

远程连接SSH,执行shell command

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.rmi.UnexpectedException;

import org.apache.log4j.Logger;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
* create an ssh client using username, password, host/connection IP, and port
*
*/
public class SSHClient {
    private JSch jschSSH;
    private String userName;
    private String hostip;
    private int intConnectionPort;
    private String password;
    private Session sesConnection;
    private int timeOut;
    private Channel channel = null;
    private static final Logger LOG = Logger.getLogger(SSHClient.class);
    private StringBuffer outputstream, errorstream = null;
    private String result = null;
    private String prvKey; // just for debug purposes.

    /**
    ** initialize SSH machine config
    */
    public SSHClient(String user, String passwd, String connectionIP, int port) {
        jschSSH = new JSch();
        userName = user;
        password = passwd;
        hostip = connectionIP;
        intConnectionPort = port;
        timeOut = 30000;
    }

    public SSHClient(String user, String connectionIP, int port, String prvKey) throws JSchException {
        this(user, null, connectionIP, port);
        if (prvKey == null) {
            throw new IllegalArgumentException("prvKey must not be null");
        }
        jschSSH.addIdentity(prvKey);
        this.prvKey = prvKey;
    }

    /**
    ** Connect to the remote SSH machine
    */
    public void connect() throws JSchException {
        String keyFileMessage = (prvKey == null) ? "without ssh key file."
                : String.format("using ssh key file: [%s].", this.prvKey);
        String passwordMessage = (this.password != null) ? ":" + this.password : "";
        LOG.info(String.format("SSH connecting to: %s%s@%s:%d %s", userName, passwordMessage, hostip, intConnectionPort,
                keyFileMessage));
        sesConnection = jschSSH.getSession(userName, hostip, intConnectionPort);

        if (this.prvKey == null) {
            sesConnection.setPassword(password);
        }
        sesConnection.setConfig("StrictHostKeyChecking", "no");
        /**
        * Used to / bypass the key check
        */
        sesConnection.connect(timeOut);
    }

    /**
    * Execution of the command with execute channel on the remote machine
    *
    * @param command
    *            Actual command that needs to get executed on terminal
    * @return String as method result
    * @throws JSchException
    * @throws IOException
    */
    public String runCommand(String command) throws JSchException, IOException {
        channel = sesConnection.openChannel("exec");
        // ((ChannelExec) channel).setCommand("source /etc/bashrc");
        ((ChannelExec) channel).setCommand(command);
        LOG.info("Command:" + command);
        BufferedReader br = new BufferedReader(new InputStreamReader(channel.getInputStream()));

        InputStream error = ((ChannelExec) channel).getErrStream();
        channel.connect(60000);
        outputstream = new StringBuffer();
        String msg = null;
        while ((msg = br.readLine()) != null) {
            outputstream.append(msg).append("\n");
            /**
            * Enters this loop if command has executed successfully and stores
            * result in output String
            */
        }
        LOG.info("The output stream's length is:" + outputstream.length());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            LOG.warn("After sleep 2 second got the error message:" + e.getMessage());
        }
        // channel.disconnect();
        int code = channel.getExitStatus();
        LOG.info("Channel exit status:" + channel.getExitStatus());
        LOG.debug("Output of command successful execution: " + outputstream.toString());

        String errormsg = null;
        BufferedReader errorReader = new BufferedReader(new InputStreamReader(error));
        errorstream = new StringBuffer();
        while ((errormsg = errorReader.readLine()) != null) {
            LOG.error("Terminal error output is: " + errormsg);
            errorstream.append(errormsg).append("\n");
            /**
            * Enters this loop if command has not executed successfully. Used
            * for printing the message displayed on the terminal.
            */
        }
        /*
        * LOG.info("Terminal output is: "+ String.format(
        * "OutputStream: [%s] \n ErrorStream: [%s]", outputstream.toString(),
        * errorstream.toString())); if (channel.getExitStatus() != 0) { throw
        * new IOException("Error code is " + channel.getExitStatus()); }
        */
        /**
        * Throw Channel exitstatus not 0 exception
        */
        channel.disconnect();
        // return String.format("OutputStream: [%s] \n ErrorStream: [%s]",
        // outputstream.toString(), errorstream.toString());
        if (errorstream.length() > 0) {
            return errorstream + outputstream.toString() + "ExitCode" + code;
        } else {
            return outputstream.toString() + "ExitCode" + code;
        }
    }

    /**
    * Please be careful when use this method. This method will execute the
    * command and disconnect immediately.So you can not get the output and the
    * channel exitCode will always be -1
    * 
    * @param command
    * @return
    * @throws JSchException
    */
    public int runCommandWithoutWaitOutput(String command) throws JSchException {
        channel = sesConnection.openChannel("exec");
        ((ChannelExec) channel).setCommand(command);
        LOG.info("Command:" + command);
        channel.connect(60000);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int code = channel.getExitStatus();
        channel.disconnect();
        return code;
    }

    /**
    * Execution of the command with shell channel on the remote machine
    *
    * @param command
    * @return
    * @throws JSchException
    * @throws IOException
    */
    public String runShellCommand(String command) throws JSchException, IOException {

        channel = sesConnection.openChannel("shell");
        OutputStream output = channel.getOutputStream();
        PrintStream pstream = new PrintStream(output, true);

        channel.connect();
        InputStream input = channel.getInputStream();
        LOG.info("SSH Shell Command:" + command);
        // Execute command.
        pstream.println(command);

        // Exit shell manually, or will be fall into endless loop.
        pstream.println("exit");

        pstream.close();

        result = getCommandOutput(input, channel);

        // channel.disconnect();
        LOG.info("Channel Exit status is: " + channel.getExitStatus());
        if (channel.getExitStatus() != 0) {
            LOG.info("Terminal output:\n" + result.toString());
            throw new UnexpectedException("Exit Status not 0. Result:\n" + result);
        }
        channel.disconnect();
        return result.toString();

    }

    /**
    * Method getOutputStream() is used to get OutputStream data after executing
    * the SSH command
    *
    * @return String outputstream if it is not null or will return null
    */
    public String getOutputStream() {
        if (outputstream == null) {
            return null;
        } else
            return outputstream.toString();
    }

    /**
    * Method getErrorStream() is used to get ErrorStream data after executing
    * the SSH command
    *
    * @return String errorstream if it is not null or will return null
    */
    public String getErrorStream() {
        if (errorstream == null) {
            return null;
        } else
            return errorstream.toString();
    }

    /**
    * Method getShellRunOutput() is used to get shell output for data after
    * executing the SSH command
    *
    * @return String result if it is not null or will return null
    */
    public String getShellRunOutput() {
        if (result == null) {
            return null;
        } else
            return result;
    }

    /**
    ** Method returns channel exit status for the SSH connection
    *
    * @return int -2 if channel is null or channel exit status
    */
    public int getChannelExitStatus() {
        LOG.info("Channel exiting...");
        if (channel == null) {
            return -2;
        } else
            /**
            * If channel.getExitStatus() = -2 it means that the channel is
            * still null and there is issue in the execution of SSH. If it is 0
            * it means channel command execution is completed successfully.
            */
            return channel.getExitStatus();
    }

    /**
    ** Close the SSH connection
    */
    public void close() {
        sesConnection.disconnect();
    }

    /**
    * Get Command execute output.
    *
    * @param input
    * @param channel
    * @throws IOException
    */
    private static String getCommandOutput(InputStream input, Channel channel) throws IOException {
        StringBuilder result = new StringBuilder();
        int size = 1024;
        byte[] bte = new byte[size];
        while (true) {
            while (input.available() > 0) {
                int i = input.read(bte, 0, 1024);
                if (i < 0)
                    break;
                result.append(new String(bte, 0, i));
            }
            if (channel.isClosed()) {
                if (input.available() > 0) {
                    int i = input.read(bte, 0, 1024);
                    result.append(new String(bte, 0, i));
                }
                break;
            }
        }

        return result.toString();
    }

    public void setAuthenticationKey(String kEY_FILE_PATH) {
        // TODO Auto-generated method stub

    }

}