[java] Run a command over SSH with JSch

The example provided by Mykhaylo Adamovych is very thorough and exposes most of the major features of JSch. I packaged this code (with attribution, of course) into an open-source library called Remote Session. I added JavaDoc and custom exceptions, and I also provided a facility to specify custom session parameters (RemoteConfig).

One feature that Mykhaylo's code doesn't demonstrate is how to provide an "identity" for remote system interactions. This is critical if you're going to execute commands that require super-user access (i.e. - sudo). Remote Session adds this capability in its SessionHolder.newSession() implementation:

RemoteConfig remoteConfig = RemoteConfig.getConfig();
Path keyPath = remoteConfig.getKeyPath();

if (keyPath == null) {
    throw new RemoteCredentialsUnspecifiedException();
}

String keyPass = remoteConfig.getString(RemoteSettings.SSH_KEY_PASS.key());
if (keyPass != null) {
    Path pubPath = keyPath.resolveSibling(keyPath.getFileName() + ".pub");
    jsch.addIdentity(keyPath.toString(), pubPath.toString(), keyPass.getBytes());
} else {
    jsch.addIdentity(keyPath.toString());
}

Note that this behavior is bypassed if the remote system URL includes credentials.

Another feature that Remote Session demonstrates is how to provide a known-hosts file:

if ( ! remoteConfig.getBoolean(RemoteSettings.IGNORE_KNOWN_HOSTS.key())) {
    Path knownHosts = keyPath.resolveSibling("known_hosts");
    if (knownHosts.toFile().exists()) {
        jsch.setKnownHosts(knownHosts.toString());
    }
}

Remote Session also adds a ChannelStream class that encapsulates input/output operation for the channel attached to this session. This provides the ability to accumulate the output from the remote session until a specified prompt is received:

private boolean appendAndCheckFor(String prompt, StringBuilder input, Logger logger) throws InterruptedException, IOException {
    String recv = readChannel(false);
    if ( ! ((recv == null) || recv.isEmpty())) {
        input.append(recv);
        if (logger != null) {
            logger.debug(recv);
        }
        if (input.toString().contains(prompt)) {
            return false;
        }
    }
    return !channel.isClosed();
}

Nothing too complicated, but this can greatly simplify the implementation of interactive remote operations.