Java scp util

Java scp util implemented with JSch lib.

import java.io.*;
import com.jcraft.jsch.*;
import org.apache.log4j.Logger;

/**
 * @author yuanjiang
 *
 */
public class SCPUtil
{

    private static final Logger LOG = Logger.getLogger(SCPUtil.class);

    private String host = null;
    private String username = null;
    private String password = null;
    private String privateKey = null;
    private String privateKeyPass = null;

    private FileOutputStream fos = null;
    private FileInputStream fis = null;

    /**
     * SCPUtil with password-based auth
     * @param host the host to scp file from or to
     * @param username the ssh auth based username
     * @param password the ssh auth based password
     */
    public SCPUtil(String host, String username, String password)
    {
        this.host = host;
        this.username = username;
        this.password = password;
    }

    /**
     * SCPUtil with private-key-based auth
     * @param host the host to scp file from or to
     * @param username the ssh auth based username
     * @param privateKey the ssh auth based private key
     * @param privateKeyPass the ssh auth based private key passphrase
     */
    public SCPUtil(String host, String username, String privateKey, String privateKeyPass)
    {
        this.host = host;
        this.username = username;
        this.privateKey = privateKey;
        this.privateKeyPass = privateKeyPass;
    }

    /**
     * Get authenticated session
     * @return authenticated Session instance
     */
    private Session getAuthSession() throws Exception
    {
        Session session;
        JSch jsch = new JSch();
        if (this.password == null)
        {
            if (this.privateKeyPass != null)
            {
                jsch.addIdentity(this.privateKey, this.privateKeyPass);
            }
            else
            {
                jsch.addIdentity(this.privateKey);
            }
            session = jsch.getSession(this.username, this.host);
            LOG.info("Starting private key auth scp session to host: " + this.host);
        }
        else
        {
            session = jsch.getSession(this.username, this.host);
            session.setPassword(this.password);
            LOG.info("Starting password auth scp session to host: " + this.host);
        }

        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);

        return session;
    }

    /**
     * Scp from remote file to local file
     * @param remoteFile Remote file name to retrieve, including path
     * @param localFile Local file name to save, including path
     * @throws Exception
     */
    public void get(String remoteFile, String localFile)
    {

        try {
            Session session = this.getAuthSession();
            session.connect();

            LOG.info("Getting remote file: " + remoteFile + " and saving as: " + localFile);

            String command = "scp -f " + remoteFile;
            Channel channel = session.openChannel("exec");
            ((ChannelExec)channel).setCommand(command);

            OutputStream out = channel.getOutputStream();
            InputStream in = channel.getInputStream();

            channel.connect();

            byte[] buf = new byte[1024];

            buf[0] = 0;
            out.write(buf, 0, 1);
            out.flush();

            while(true)
            {
                int c = checkAck(in);
                if(c != 'C')
                {
                    break;
                }

                // read '0644 '
                in.read(buf, 0, 5);

                long filesize = 0L;
                while(true)
                {
                    if(in.read(buf, 0, 1) < 0)
                    {
                        // error
                        break;
                    }
                    if(buf[0] == ' ') break;
                    filesize = filesize * 10L + (buf[0] - '0');
                }

                String file = null;
                for(int i=0; ; i++)
                {
                    in.read(buf, i, 1);
                    if(buf[i] == (byte)0x0a)
                    {
                        file = new String(buf, 0, i);
                        break;
                    }
                }

                LOG.info("filesize=" + filesize + ", file=" + file);

                // send '\0'
                buf[0] = 0;
                out.write(buf, 0, 1);
                out.flush();

                // read a content of local file
                fos = new FileOutputStream(localFile);
                int foo;
                while(true)
                {
                    if(buf.length < filesize) foo = buf.length;
                    else foo = (int)filesize;
                    foo = in.read(buf, 0, foo);
                    if(foo < 0)
                    {
                        // error
                        break;
                    }
                    fos.write(buf, 0, foo);
                    filesize -= foo;
                    if(filesize == 0L) break;
                }
                fos.close();
                fos = null;

                if(checkAck(in) != 0)
                {
                    System.exit(0);
                }

                // send '\0'
                buf[0] = 0;
                out.write(buf, 0, 1);
                out.flush();
            }

            LOG.info("File downloaded successfully!");

            channel.disconnect();
            session.disconnect();

        }
        catch (Exception e)
        {
            LOG.error(e.getMessage(), e);
            try
            {
                if(fos != null) fos.close();
            }
            catch(Exception ee)
            {
                LOG.error(e.getMessage(), ee);
            }
        }
    }


    /**
     * Scp from local file to remote file
     * @param remoteFile Remote file name to save, including path
     * @param localFile Local file name to scp, including path
     * @throws Exception
     */
    public void put(String localFile, String remoteFile)
    {
        try {
            Session session = this.getAuthSession();
            session.connect();

            LOG.info("Putting local file: " + localFile + " to remote and saving as: " + remoteFile);

            boolean ptimestamp = true;

            // exec 'scp -t rfile' remotely
            String command = "scp " + (ptimestamp ? "-p" :"") + " -t " + remoteFile;
            Channel channel = session.openChannel("exec");
            ((ChannelExec)channel).setCommand(command);

            // get I/O streams for remote scp
            OutputStream out = channel.getOutputStream();
            InputStream in = channel.getInputStream();

            channel.connect();

            if(checkAck(in) != 0)
            {
                System.exit(0);
            }

            File lfile = new File(localFile);

            if(ptimestamp)
            {
                command = "T " + (lfile.lastModified() / 1000) + " 0";
                // The access time should be sent here,
                // but it is not accessible with JavaAPI ;-<
                command += (" " + (lfile.lastModified() / 1000) + " 0\n");
                out.write(command.getBytes());
                out.flush();
                if(checkAck(in) != 0)
                {
                    System.exit(0);
                }
            }

            // send "C0644 filesize filename", where filename should not include '/'
            long filesize = lfile.length();
            command = "C0644 " + filesize + " ";
            if(localFile.lastIndexOf('/') > 0)
            {
                command += localFile.substring(localFile.lastIndexOf('/') + 1);
            }
            else
            {
                command += localFile;
            }

            command += "\n";
            out.write(command.getBytes());
            out.flush();

            if(checkAck(in) != 0)
            {
                System.exit(0);
            }

            // send a content of lfile
            fis = new FileInputStream(localFile);
            byte[] buf = new byte[1024];
            while(true)
            {
                int len = fis.read(buf, 0, buf.length);
                if(len <= 0) break;
                out.write(buf, 0, len); //out.flush();
            }
            fis.close();
            fis = null;
            // send '\0'
            buf[0] = 0;
            out.write(buf, 0, 1);
            out.flush();
            if(checkAck(in) != 0)
            {
                System.exit(0);
            }
            out.close();


            LOG.info("filesize=" + filesize + ", file=" + remoteFile);
            LOG.info("File uploaded successfully!");

            channel.disconnect();
            session.disconnect();


        }
        catch (Exception e)
        {
            LOG.error(e.getMessage(), e);
            try
            {
                if(fis != null) fis.close();
            }
            catch(Exception ee)
            {
                LOG.error(e.getMessage(), ee);
            }
        }
    }

    static int checkAck(InputStream in) throws IOException
    {
        int b = in.read();
        // b may be 0 for success,
        //          1 for error,
        //          2 for fatal error,
        //          -1
        if(b == 0) return b;
        if(b == -1) return b;

        if(b == 1 || b == 2)
        {
            StringBuffer sb = new StringBuffer();
            int c;
            do
            {
                c = in.read();
                sb.append((char)c);
            }
            while(c != '\n');
            if(b == 1)
            { // error
                LOG.error(sb.toString());
            }
            if(b == 2)
            { // fatal error
                LOG.error(sb.toString());
            }
        }
        return b;
    }

Reference:

java