Determine if a java execution from another java application was done successfully - java

I have an application that calls a java test class in a specified location of my PC. The path is hard-coded for now, and I checked that it worked by executing it from the command line (in case you want to see it: java -cp C:\Users\user\Documents\workspace\test\build\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest), so I know that the command works fine.
The thing is, when I do Runtime.getRuntime().exec(command), if I try to log the resulting InputStream and ErrorStream of its resulting process, the program stucks. I tried with exitValue() and waitFor(), but the first throws an incompletition error and the second also gets stuck. The weird thing is that if I don't touch anything of this (the streams, or using the functions), the program has no problem ending.
So my question is: Why could this be? The next step is to build the command with given parameters, but if I can't see the resulting inputs I can't be completely sure if the tests are running or not.
The code, in case you want to see it:
Runtime runtime=Runtime.getRuntime();
logger.debug("Attempting to execute the test {} at path {}",classpath,applicationLocation);
String command="java -cp C:\\Users\\user\\Documents\\workspace\\test\\build\\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest";
Process process=runtime.exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}

You absolutely must read both streams in separate threads. (Read the Javadoc of the Process class). If you wait for the end, or read first one stream before the other it can happen that the output buffer of the command fills up and it will block (on stdout or stderr, depending on what you read first). Normally you use waitFor() in the current thread and have background thread draining the outputs (this also allows detecting end of child process without polling).
If you want to use only one (additional) thread you can redirect stderr to stdout. If you want to avoid to read the streams at all, you can set the
ProcessBuilder features inheritIO(). This allows the stream to be written to the existing output and so you do not need a thread to read independently.
There are BTW various libararies which offer exec tools (for example Apache Commons Exec has some streams) which offer active stream draining, logging or pumping for Process.
In addition to that it might also be a good idea to first close stdin, in case the command waits for input: p.getOutputStream().close();

Make sure you close the 2 streams:
String command="java -cp C:\\Users\\user\\Documents\\workspace\\test\\build\\test.jar org.junit.runner.JUnitCore us.test.DynamicWebserviceInvocationTest";
Process process=runtime.exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
stdInput.close();
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
stdError.close();

Related

Start and get output of a .jar (E.g. Minecraft Bukkit .jar)

I'm trying to start some .jar inside an .jar using this code: (I'm trying with craftbukkit server right know)
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("java -jar craft.jar");
BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedWriter in = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
this.running = true;
while(this.running){
String line;
if((line = out.readLine()) != null){
System.out.println(line);
}
}
The problem is, it work for a moment, but after a while it stops outputting or just print '>' as show in the image below. How can I fix this? **Plus, Which is the correct way to send commands to the bukkit server?
Thanks!
When using a Process in Java, it is crucial to read stdout and stderr in two independend threads (your while loop). Otherwise the child process can lock up waiting for the filled buffer to be drained.
With Java 7 you can actually redirect stderr to stdout, and possibly redirect the resulting stream to the parents stdout. With older versions you need to attach the seperate threads.
Besides: you should not use the "single string" variant of exec, but specify the args as arrays. This is safer (less vulnerable to parsing problems).
(But I am not sure if this is your actual problem. Maybe you should dump the error stream and see if it helps)
I do it like that:
#Override
public void run(){
// ...
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream())); //of course proc is an instance of Process, and it's set up
while(true){
String line = stdInput.readLine();
if(line == null) break; //this is essential, when process terminates, line gets null
System.out.println(">"+line);
}
// ...
}
Give it a try.
(Technically it's similiar how you did, but it works for me so i share it)

Java run Process unable to get standard out

I have my code below. I am trying to run my ruby script and get the standard out, I don't really need standard error in this case. For some reason, I could not get any output at all in my production host, and I only get empty string. The same code works fine in my desktop. If I run my ruby script myself, I could get output from it. My ruby script only has a puts statement for now. Any one know the reason? Is it that I need to some kind of block to wait for the ruby script to finish?
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("ruby", "tests.rb");
Process process = processBuilder.start();
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = bufferReader.readLine()) != null) {
System.out.println("Line is: " + line);
output.append(line + "\n");
}
bufferReader.close();
return output.toString();
I have redhat machine running zsh.
You need to close the process's output stream (its standard input), and you should probably merge the output and error streams. You might think you don't want them both but you might be wrong, and if the process produces enough unread error output it will stall.

how to integrate Bash with Java

Can any body help me with how to compile a bash script as part of a java program. I am writing a simple java program that i want to use to invoke bash script commands.
my java code looks like the following:
try{
Process p = Runtime.getRuntime().exec("myscript.sh");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null){
System.out.println(line);
}
}
catch(IOException e){
System.out.println(e.getMessage());
}
and the "mysrcipt.sh" file is a simple script that contains the following lines
!/bin/bash
echo "enter your input followed by [ENTER]:"
read -e choice
echo $choice
My problem is, the program waits for an input at the read command in the script even if i enter multiple lines and press enter several times.
You can use:
Process p = Runtime.getRuntime().exec("bash_script.sh");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
// use bash script line output
}
It would be helpful to see some code showing what you're trying to accomplish.
Executing bash script in Java can be done using something like the following...
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("YOUR COMMAND STRING");
List<String> lines = IOUtils.readLines(process.getInputStream());
Runtime.exec() is what you need to execute your bash script, but be aware there are a few pitfalls. I found this to be a good article when starting to call external scripts.
It is written for a windows platform, but a lot of what is discussed is relevant to *nix as well.
See also this question.

Java read Oracle EXP command output

I need to run the Oracle EXP command through a Java program and print somewhere the command output.
The EXP command is correct, the dump file is created correctly when I execute my Java code, but I'm experiencing some issues to get the output.
This is an snippet very similar to the one I'm using to read the output:
String line;
String output = "";
try {
Process p = Runtime.getRuntime().exec(myCommand);
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
output += (line + '\n');
}
input.close();
}
catch (Exception ex) {
ex.printStackTrace();
}
System.out.println(output);
As I said, the command is correctly executed (verified through the generated dump file), but nothing appears on my console and my Java programs doesn't terminate either.
The same code works perfectly if I use another command, as "ls -l" instead of "exp ...".
Maybe exp is writing to standard error output rather than standard output.
Try to use p.getErrorStream() instead of getInputStream()
As a_horse_with_no_name said, it might be that the error stream buffer is full and thus is blocking the programm execution.
Either try to start a Thread to also read the error stream or use the ProcessBuilder class to redirect the error stream to stdout (which you already read).

Running other programs from Java

I need to run a couple of other programs from my own Java program, basically I need to run these command line statements.
svn log --xml -v > svn.log
and
java -jar example.jar arg1 arg2
and I need to use the text outputs written to the console from these programs in my own program. I've tried Runtime.getRuntime().exec() with the svn, but it doesn't seem to be doing anything because it doesn't make a svn.log file. Also both programs need to be called in different places, the svn line needs to be called from inside one folder and the java line needs to be called from another.
Any ideas on how to go about this? If this is not possible in Java, is there a way to do it in C#?
Thanks
Here:
ProcessBuilder processbuilder
try
{
processbuilder.directory(file);
processbuilder.redirectErrorStream(true);
process = processbuilder.start();
String readLine;
BufferedReader output = new BufferedReader(new InputStreamReader(process.getInputStream()));
// include this too:
// BufferedReader output = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while((readLine = output.readLine()) != null)
{
m_Logger.info(readLine);
}
process.waitFor();
}
I've used something similar. You'll actually want to do something with the readLine. I just copied and pasted from code where I didn't care what it said.
The redirection > (like the pipe |) is a shell construct and only works when you execute stuff via /bin/sh (or equivalent). So the above isn't really going to work. You could execute
/bin/sh -c "svn log --xml -v > svn.log"
and read svn.log.
Alternatively, you can read the output from the process execution and dump that to a file (if you need to dump it to a file, or just consume it directly as you read it). If you choose this route and consume stdout/stderr separately, note that when you consume the output (stdout), you need to consume stderr as well, and concurrently, otherwise buffers will block (and your spawned process) waiting for your process to consume this. See this answer for more details.
instead of piping in your command, just let it print to standard output and error output. You can access those streams from your process object that is returned from exec.
For the svn stuff use java SVNKit API.
Seeing your two commands, why don't you do it directly from Java, without executing ? You could use SVNKit for the svn part, and include directly the jars in your classpath.
Try this
public static void main(String[] args) {
try {
// Execute a command with an argument that contains a space
System.out.println(args[0]);
String[]commands = new String[]{"svn", "info", args[0]};
Process process = Runtime.getRuntime().exec(commands);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
String result = builder.toString();
System.out.println(result);
}catch(Exception e){
System.out.print(e);
}
}

Categories