Search code examples
javasshstreamjschstderr

JSch doesn't provide output when called a 2nd time


I'm using JSch to connect via SSH to a server and use a scan command there which transfers a file.

The code is tested and worked nicely. I got all the output from to command line. Yet - when I use the same method again everything still "works" but I don't see any output. I need the output to see if everything has worked.

In the main app when a button is pressed this happens:

Scan s = new Scan(getHost(),getUser(),getPassword());
s.scan("scanscript \"" + getScancommand() + "\" \"" + getFilename() + "\"");

scanscript requires two parameters: One is the whole command scanimage blah blah - the other one is the desired filename. Scanscript also returns an exit-code which is required - but it's not obtained always.

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import java.io.InputStream;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSchException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;


public class Scan {

    private final String scan_host;
    private final String scan_user;
    private final String password;

    public Scan(String host, String user, String password) {
        this.scan_host = host;
        this.scan_user = user;
        this.password = password;
    }




    public void scan(String command) {
        boolean b_success = true;

        try {

            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            JSch jsch = new JSch();
            Session session = jsch.getSession(scan_user, scan_host, 22);
            session.setPassword(password);
            session.setConfig(config);
            session.connect();
            Logger.getLogger(Scan.class.getName()).log(Level.INFO, "Command: {0}", command);
            System.out.println("Connected"); //This here is displayed always

            Channel channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();
            channel.connect();
            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) {
                        break;
                    }
                    System.out.print(new String(tmp, 0, i));
                }
                if (channel.isClosed()) {
                    if (channel.getExitStatus() != 0) {
                        b_success = false;
                        javafx.scene.control.Alert alert = new Alert(Alert.AlertType.ERROR, "Scan failed\n - Exit-Status: " + channel.getExitStatus(), ButtonType.OK);
                        alert.showAndWait();
                    }

                    System.out.println("exit-status: " + channel.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ee) {
                    Logger.getLogger(Scan.class.getName()).log(Level.SEVERE, null, ee);
                }
            }
            channel.disconnect();
            session.disconnect();
            if (b_success) {
                javafx.scene.control.Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Scan successful", ButtonType.OK);
                alert.showAndWait();
            }
        } catch (JSchException | IOException e) {
            Logger.getLogger(Scan.class.getName()).log(Level.SEVERE, null, e);
            javafx.scene.control.Alert alert = new Alert(Alert.AlertType.ERROR, "Scan failed: " + e.getLocalizedMessage(), ButtonType.OK);
            alert.showAndWait();
        }
    }

}

Here's my console output:

Jun 15, 2017 9:12:03 PM com.schwaiger.kanva.scan.Scan scan
INFORMATION: Befehl: scanscript "scanimage --device='brother4:net1;dev0' --format tiff --resolution=150 --source 'Automatic Document Feeder(left aligned,Duplex)' -l 0mm -t 0mm -x210mm -y297mm --batch=$(date +%Y%m%d_%H%M%S)_p%04d.tiff" "testscan1.pdf"
Connected
scanimage: rounded value of br-x from 210 to 209.981
scanimage: rounded value of br-y from 297 to 296.973
Scanning -1 pages, incrementing by 1, numbering from 1
Scanning page 1
Scanned page 1. (scanner status = 5)
Scanning page 2
Scanned page 2. (scanner status = 5)
Scanning page 3
Scanned page 3. (scanner status = 5)
Scanning page 4
Scanned page 4. (scanner status = 5)
Scanning page 5
scanimage: sane_start: Document feeder out of documents
exit-status: 0
Connected
exit-status: 0

As you can see after the first time I called the command I got the whole information about what's going on. The second time I just got the Connected and an exit-status. But I can't be sure whether that status refers to my script or to the whole operation.


Solution

  • Your command provides all output on an error stream.

    You pipe the channel error stream to an error output of your Java console application:

    ((ChannelExec) channel).setErrStream(System.err);
    

    When the channel of the first command execution closes, it takes down the console error output with it.

    So the next time around, the error output is closed already, and any attempts to write it are silently ignored.

    You have to read the error stream the same way, you are reading the normal output (the while (true) loop).