Handling interactive prompts in external process java - java

I'm wrapping command line application that I oftenly use with GUI interface. It basically comes down to executing it (as Java process) and then parsing its responses. However one of the usecases requires to take additional action by enduser (application asks if user wants to overwrite a file) and I'm not sure how to handle that. Both InputStream and ErrorStream freezes as soon as this prompt comes up. Here is a (pretty generic) code of executeCommand method:
private void executeCommand(String command) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("bash", "-c", command);
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
while ((line = reader.readLine()) != null) {
//some actions "File already exists. Do you want to overwrite ? [y/N]" line never gets to this point
}
while ((line = errorReader.readLine()) != null) {
//some actions "File already exists. Do you want to overwrite ? [y/N]" line never gets to this point
}
handleExitCode(process.waitFor(),"Success!");
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
I assume that "File already exists. Do you want to overwrite ? [y/N]" prompt is being passed through some other channel. I just don't know how to handle it. The ideal scenario for me would be if I could prompt messageBox with the same question and then pass the response accordingly.

When you are forking a child process, it needs to inherit I/O from parent process to talk stdin and stdout. Use ProcessBuilder.inheritIO to redirect your command streams in your stdin, stdout and stderr.

Related

sshj: how to read InputStream from long-running command while command is executing

Currently I am executing command over ssh using:
val sshCmd = session.exec(command)
println(IOUtils.readFully(sshCmd.inputStream).toString())
sshCmd.join()
However, to see the output I need to wait until the command is finished.
How can I get "live" response?
I guess I can read the input stream until end of the line occurs and then print the line; however, is there already some method in the library that can help me with this?
It blocks and waits for the whole thing because that's what IOUtils.readFully is meant to do, it reads fully.
Instead, to read line-by-line, you can do something as simple as:
try (BufferedReader reader = new BufferedReader(new InputStreamReader(sshCmd.inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e);
}

Running a script in terminal from java

I am running a script in a java program using:
Runtime.getRuntime().exec()
I am able to open the terminal application using this.
If I give command to run the script. It's happening but I am not able to get the logs in the terminal. I am using MAC. I want to get the logs in the terminal.
You can use a Process variable to get what return from that command, and use method such as: getInputStream(), getOutputStream(), getErrorStream(). Example:
Process p = null;
try {
p = Runtime.getRuntime().exec(....your stuff here)
p.getOutputStream().close(); // close stdin of child
InputStream processStdOutput = p.getInputStream();
Reader r = new InputStreamReader(processStdOutput);
BufferedReader br = new BufferedReader(r);
String line;
while ((line = br.readLine()) != null) {
//System.out.println(line); // the output is here
}
p.waitFor();
}
catch (InterruptedException e) {
...
}
catch (IOException e){
...
}
finally{
if (p != null)
p.destroy();
}
The Process object returned by the method call above has an getInputStream() method (as well as ones for the error and output streams). You have to read from those if you want to grap the inputs and outputs of your script.
For reference: http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html
in terminal, using > to output the log to file. For example: ls / > rootfolder.txt
Using that way, you can output the log to file and then read the log from the file.

Error handling in java

Am running .exe file from java code using ProcessBulider, the code I have written is given below. The .exe file takes Input.txt(placed in same directory) as input and provide 3 output file in same directory.
public void ExeternalFileProcessing() throws IOException, InterruptedException {
String executableFileName = "I:/Rod/test.exe;
ProcessBuilder processBuilderObject=new ProcessBuilder(executableFileName,"Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
Process process = processBuilderObject.start();
process.waitFor();
}
this process is working fine by call ExeternalFileProcessing(). Now am doing validation process, If there is any crash/.exe file doesn't run, I should get the error message how can I get error message?
Note: It would be better that error message be simple like run successful/doesn't run successful or simply true/false, so that I can put this in If condition to continue the remaining process.
You can add exception handlers to get the error message.
public void externalFileProcessing() {
String executableFileName = "I:/Rod/test.exe";
ProcessBuilder processBuilderObject = new ProcessBuilder(
executableFileName, "Input.txt");
File absoluteDirectory = new File("I:/Rod");
processBuilderObject.directory(absoluteDirectory);
try {
Process process = processBuilderObject.start();
process.waitFor();
// this code will be executed if the process works
System.out.println("works");
} catch (IOException e) {
// this code will be executed if a IOException happens "e.getMessage()" will have an error
e.printStackTrace();
} catch (InterruptedException e) {
// this code will be executed if the thread is interrupted
e.printStackTrace();
}
}
But it would be better to handle it in the calling function by put a try catch handler in the calling function and handling it there.
Is it a third party .exe or do you have access to its sources? If so, you could work with basic System outputs (for example couts to the console).
Those outputs can be redirected to your java app using something like this:
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null) {
if(line.equals("something")) {
// do something
}
}
br.close();
This is how i do things like that and it works very well in general. But i must admit, that i can not say/garuantee, that this is THE way to do it. A more advanced approach might be the use of StreamGobbler (see Listing 4.5) to handle the outputs of the .exe.
Let me know if it helped you or not.

Redirect I/O of subprocess in Java (why doesn't ProcessBuilder.inheritIO() work?)

I'm launching a process in the following way.
try {
final Process mvnProcess = new ProcessBuilder("cmd", "/c", "mvn", "--version")
.directory(new File(System.getProperty("user.dir")))
.inheritIO()
.start();
System.exit(mvnProcess.waitFor());
} catch (final IOException ex) {
System.err.format(IO_EXCEPTION);
System.exit(1);
} catch (final InterruptedException ex) {
System.err.format(INTERRUPTED_EXCEPTION);
System.exit(1);
}
Since I invoke inheritIO() I was expecting the sub-process's output on the console, but nothing appears. What am I missing here?
Edit: I know that I can use mvnProcess.getInputStream() and read the process's output explicitly, writing it to the console (or where-ever) in a loop. I don't like this solution however, since the loop will block my thread. inheritIO() looked promising, but apparently I don't understand how it works. I was hoping someone here could shed some light on this.
Maybe it is an option the read it from the subprocess:
Add this code after start() and you will have it printed to stdout:
InputStream is = mvnProcess.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
You can use the .redirectError(Redirect.INHERIT).
It sets the source and destination for sub process standard I/O to be the same as those of the current Java process.

Output the result of a bash script

If for example I chose to run a bash script that would output (echo) the time e.g. CheckDate.sh. How could I run this from Java and then print the result of the bash script (the date) in my Java program?
Try this code.
String result = null;
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec("example.bat");
BufferedReader in =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
result += inputLine;
}
in.close();
} catch (IOException e) {
System.out.println(e);
}
One way would be to assign your script execution in a Process object and retrieve the script ouput from its inputstream.
try {
// Execute command
String command = "ls";
Process process = Runtime.getRuntime().exec(command);
// Get the input stream and read from it
InputStream in = process.getInputStream();
int c;
while ((c = in.read()) != -1) {
process((char)c);
}
in.close();
} catch (IOException e) {
LOGGER.error("Exception encountered", e);
}
Another way would be to make your bash scripts write its output in a file and then read this file back from Java.
Good luck.
The java.lang.Process class is intended for such purposes. You run an external process in Java either using the (simpler) java.lang.Runtime.exec function, or the (more complex) java.lang.ProcessBuilder class. Both give you, in the end, an instance of said java.lang.Process, whose getInputStream method you can call to get a stream from which you can read its output.
See the Javadoc for more information.

Categories