
Sometimes you need to use some CLI-Tools before you want to create or search for a native JNI Binding.
So there is a common way, using the Java Process-Class. But then you might meet two problems i had to face in the past during several problems:
- There are (a really small) number of CLI-Tools, that giving no constant output over the STD-OUT (the standard output the Process-Class uses for output)
- There is no “elegant” way to implement a process call into your project.
To solve this Problem I created a basic HelperClass, that calls the System over SSH (with the Convenience to work remote and the side-effect to always get STD-compatible output).
I am primarely using it for a fun project SAM i started some months ago to try to create a Management-Tool for Unices and Windows with a very low client-side footprint.
The first Class is used to capsulate the basic SSH Calls:
// some imports...
public class SystemHelper {
private Runtime r;
private String sshPrefix = "";
// call with $user and 127.0.0.1 to run local command.
public SystemHelper(String user, String ip) {
r = Runtime.getRuntime();
sshPrefix = " ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no " + user + "@" + ip;
}
public void runCommand(String command, ProcessParser pp) {
try {
Logger.info("running: " + this.sshPrefix + " " + command);
Process p = r.exec(this.sshPrefix + " " + command);
InputStream in = p.getInputStream();
BufferedInputStream buf = new BufferedInputStream(in);
InputStreamReader inread = new InputStreamReader(buf);
BufferedReader bufferedreader = new BufferedReader(inread);
pp.parse(bufferedreader);
try {
if (p.waitFor() != 0) {
Logger.info("exit value = " + p.exitValue());
}
} catch (InterruptedException e) {
System.err.println(e);
} finally {
// Close the InputStream
bufferedreader.close();
inread.close();
buf.close();
in.close();
}
} catch (IOException ex) {
Logger.error(ex.getLocalizedMessage());
}
}
}
ProcessParser is an interface that defines the methode parse, accepting a BufferedReader for parsing the output of the Process. Unfortunately there is no timeout ATM to kill a hanging SSH-Call.
public interface ProcessParser {
public void parse(BufferedReader bufferedreader);
}
The most basic (Output-)Parser looks like this:
public String getPublicSSHKey() {
SimpeOutputPP so = new SimpeOutputPP();
String command = "cat ~/.ssh/id_rsa.pub";
runCommand(command, so);
if (!so.getOutput().isEmpty()) {
return so.getOutput().get(0);
}
return "";
}
This returns just the public SSH-Key of the current user. I implemented some more parsers for the output of apt (dpkg), rpm and pacman. You can find them in the github project here.