Launch a process with java and then terminate it - java

Normally I use this code to run a bash script and get it's output
ProcessBuilder pb = new ProcessBuilder("/home/myscript");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputRead;
p.waitFor();
while((inputRead=stdInput.readLine()) != null){
Helper.log(inputRead);
}
This works fine but this time the bash script I am using didn't terminate. It's always active and when it detect something it print it. I want to start the script, wait for some time and than check if it detected something.
I tried this code
Thread.sleep(5000);
p.destroy();
String inputRead;
while((inputRead=stdInput.readLine()) != null){
Helper.log(inputRead);
}
But I get as result
java.io.IOException: Stream closed
I also tried
p.waitFor(5, TimeUnit.SECONDS);
while((inputRead=stdInput.readLine()) != null){
Helper.log(inputRead);
}
But the process never ended and I still get the input in the log for ever.
I just want to run the script for a short period of time, in this example 5 seconds and than stop it and get the output generated by the script in this period.

Process.destroy might (and probably will, but this is implementation dependent) kill your process and this is why you're getting your java.io.IOException.
If you're using Java 8, I'd suggest using Process.waitFor with the timeout constructor. You'll be able to check whether your process has hanged or not. If it returns true, you will have captured the process output using normal means. If it returns false, your process might have hanged, so you can either terminate it, or wait some more and try to see if anything has changed.
An alternative would be to control your bash script using the timeout command, so you can be sure that your script will eventually terminate in a finite amount of time.

Related

How to execute a linux terminal command from LUAJ?

I want to simply execute a linux terminal command like ls from LuaJ and the result that it will return or anything that returns i want to receive it and will show the names in the Java Gui. I searched but found this but not one with LuaJ.
Is there any function to execute the terminal command from LuaJ ??
There are multiple ways to do this, for one, you can implement it yourself in Java then link it to LuaJ.
LuaFunction command = new OneArgFunction()
{
public LuaValue call(LuaValue cmd)
{
Process p = Runtime.getRuntime().exec("/bin/sh", "-c", cmd.checkstring());
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
int returnCode = p.waitFor();
return LuaValue.valueOf(returnCode);
}
}
globals.set("command", command);
Then in Lua:
local code = command("ls");
The problem with actually getting the output of a command is that you can't just have a fixall solution. For all the system knows you could be calling a program which runs for 2 hours generating constant output, which could be an issue, not to mention if the program requires input. If you know you're only going to use certain functions you can make a dirty version of above function to capture the output from the stream and return it all instead of the exit code, just don't use it on other processes that don't return quickly. The other alternative is to create a class that wraps the input and output streams from the process and return a coerced version of that class, and manage the input and output from lua.
Lua does have a function that's part of the OsLib called execute(), if execute doesn't exist in your current environment then in Java call:
globals.load(new OsLib());
Before loading the lua code. the os.execute() function returns the status code, and doesn't return the streams, so no way to get the output there. To get around this you can modify the command to pipe the output to a temp file and open it with the io library (new IoLib() if doesn't exist in current environment).
The other option is to use io.openProcess, which also executes the command and returns a file to read the output from.
Resources:
http://luaj.org/luaj/3.0/api/org/luaj/vm2/lib/OsLib.html
http://luaj.org/luaj/3.0/api/org/luaj/vm2/lib/IoLib.html

Java: wait for all child process to finish

Environment: Windows 7
I'm launching an external process with ProcessBuilder. This external program can be called with an argument defining how many CPU cores to use. It then launches as many processes to perform the calculation.
The issue seems to be that the initial called process then immediately terminates. So process.waitFor() does not actually wait for the calculation to complete.
How can I make it wait for the child-process it spwaned? Or how can i wait til all process of a specific name have been terminated?
EDIT due to comments:
ProcessBuilder pb = new ProcessBuilder("myExe", "-i", inputFile, "-o", outputFile, "-np", "4");
pb.directory(new File(tempPath));
Process myProcess = pb.start();
myProcess.waitFor();
Process is a 3-rd party exe file (no GUI).
EDIT 2 Possible workaround (which has another issue):
As a workaround I tried a solution found with google:
while(wait) {
Process p = Runtime.getRuntime().exec(System.getenv("windir") +"\\system32\\"+"tasklist.exe /fi \"imagename eq myExe.exe\"");
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream(), "US-ASCII"));
while ((line = input.readLine()) != null) {
if (line.startsWith("INFO: No tasks are running")) {
wait = false;
}
}
if (wait) {
Thread.sleep(2000);
}
input.close();
}
This should return a list of all processes with the given name. Problem is the list is always empty when called from Java but works correctly when called from the cli manually. Any ideas why?
Java-like dirty solution
Currently java.lang.Process is rather poor and is getting enriched.
For example, here you can find the feature requests. In java 8,
you already have methods like isAlive and destroyForcibly So
you can try something like the following dirty solution:
Get the id of the main process by reflection.
Get the child processes - specific for Windows
Wait for the found child processes
Steps 2 and 3 can be implemented as one script and executed as
java.lang.Process.waitFor
Work with the executable
I suppose, that the executable is some kind of MPI program. If you have access to the sources, i'd better change it to work correctly and waiting for all threads.

Java Processbuilder - Catching the exitvalue of another Script?

I try to run a python script in my java programm. What I want to do is to catch the exitValue of the python programm and write it via System.out.println out.
Here is the Python code:
import sys
import subprocess
print "hallo"
i = sys.argv[0]
path = "R:\\xxx\\xxx\\xxx\\read"
resultlist = []
if i == 0:
result = True
else:
result = False
resultlist.append(result)
resultlist.append(path)
sys.exit(resultlist)
The Processbuilder methods .waitFor() and .exitValue() just gives a 0 or a 1 out. So I cant use it.
Is there any possible way to catch the value/string of sys.exit(resultlist) from the python script in my java programm?
man 2 exit:
The function _exit() terminates the calling process "immediately". Any open file descriptors belonging to the process are closed; any children of the process
are inherited by process 1, init, and the process's parent is sent a SIGCHLD signal.
**The value status is returned to the parent process as the process's exit status, and can be collected using one of the wait(2) family of calls.**
You cannot return "complex values" with exit(2) (the syscall) to begin with. If python does that then fine, but it's a "trick". Don't rely on it.
What you want to do is print the output of your program to stdout and capture stdout. For this, use the Process's .getInputStream() and swallow it in, for instance, a ByteArrayOutputStream.
Since you use a ProcessBuilder, you can also use its .redirectOutput() method before executing the process. Since Java 7, it has quite a few options available.

Handling delayed execution of a program in java

I am running an .exe file from my program and it is taking certain time for the same.The output from this command is used in the following statements for further processing. The output is a boolean variable. But the program is returning false immediately, but in fact the command is still in execution and is taking certain time. Because of the false value the subsequent statements is throwing an error. How do i handle this situation.
The return_var = exec(pagecmd) is the executing statement.
boolean return_var = false;
if("true".equals(getConfig("splitmode", ""))){
System.out.println("Inside splitmode if**********************");
String pagecmd = command.replace("%", page);
pagecmd = pagecmd + " -p " + page;
File f = new File(swfFilePath);
System.out.println("The swffile inside splitmode block exists is -----"+f.exists());
System.out.println("The pagecmd is -----"+pagecmd);
if(!f.exists()){
return_var = exec(pagecmd);
System.out.println("The return_var inside splitmode is----"+return_var);
if(return_var) {
strResult=doc;
}else{
strResult = "Error converting document, make sure the conversion tool is installed and that correct user permissions are applied to the SWF Path directory" +
getDocUrl();
}
In conjuction with waitFor() suggested by Andreas, you may also need to use getInputStream of Process object returned by exec() to retrieve the data written by the program you are executing.
Assumed that you are finally using Runtime.exec() inside your exec() method, you can use the waitFor() method of the Process object which is returned from Runtime.exec() to wait until the execution has finished:
...
Process p = Runtime.getRuntime().exec(pagecmd);
int result = p.waitFor();
...
The return value from waitFor() is the exit code of the sub process.
If you actually need to read output from the sub process which the sub process is writing to its stderr or stdout channel, you need to use Process.getInputStream() (Note: not getOutputStream()) and Process.getErrorStream() and read the sub processes output from these streams. Then, check the return values from the stream's read() methods to check if the sub process has terminated (or at least closed its output streams) instead of using waitFor().
Also, for these kind of problems, you should consider using the Apache commons exec library.
Alternatively, you might want to check the ProcessBuilder class.

Waiting for a single Shell script in a series of scripts to run to completion before continuing (Java, MySQL, JUnit)

I'm working on a Java program that incorporates Process and Runtime to run several shell scripts for automated testing. All but one of these scripts runs fine, which causes an issue with script calls following it. Ex:
process = runtime.exec("A.sh");
process = runtime.exec("B.sh");
process = runtime.exec("C.sh");
A.sh runs fine and only takes a few seconds to run. B.sh, however, takes a couple minutes to run, and I think this is causing a problem with running C.sh, since they both interact with the same MySQL table and the overlap causes a Communications Link Failure.
Without overloading you with unnecessary information, my question is, how can I wait to ensure a run shell script has been run to completion/termination before moving on to the next exec() call?
What I've tried:
process.waitFor()
This doesn't work, I don't think it waits until the script is completely done
process.wait(long time_period)
This doesn't work since it causes the current thread to wait which results in the remaining shell script calls to get skipped and the next test case to begin prematurely.
The shell script I call that causes the problem is not a simple script, but I didn't write it myself and have little understanding of what it does behind the scenes. The only relevant information I have about it is that it directly connects to the MySQL database in question whereas my program uses java.sql.* to (I believe) remotely connect (although it is a local database on a remote machine).
Edit:
After following a suggestion, I've looked into the Apache Commons Exec and tried a new strategy, unsuccessfully.
ExecuteWatchdog watchdog = new ExecuteWatchdog(300000); //For five minutes
CommandLine cmdline = CommandLine.parse("./directory/shell.sh");
DefaultExecutor executor = setExitValue(0);
executor.setWatchdog(watchdog);
int exitVal = executor.execute(cmdLine);
//A line to log the exit val in another file
My log gives no implication that the shell script was actually run, as the time between a logged statement saying "shell.sh begins" and "test 2 starts" are essentially the same instant, which means the ~2 minute process that shell.sh runs never happens. Where did I go wrong?
I use Apache Commons Exec. Have synchronous and asynchronous execution support. Execution timeout can be set.
First paragraph from their tutorial page:
At this point we can safely assume that you would like to start some
subprocesses from within your Java application and you spent some time
here to do it properly. You look at Commons Exec and think "Wow -
calling Runtime.exec() is easy and the Apache folks are wasting their
and my time with tons of code". Well, we learned it the hard way (in
my case more than once) that using plain Runtime.exec() can be a
painful experience. Therefore you are invited to delve into
commons-exec and have a look at the hard lessons the easy way ...
Advanced usage example (some code is missing like BusinessException and "StreamUtil.closeQuietly", but it could be easily replaced):
ExecuteWatchdog watchdog = new ExecuteWatchdog(EXECUTION_TIMEOUT_IN_MS);
DefaultExecutor executor = new DefaultExecutor();
executor.setWatchdog(watchdog);
executor.setExitValue(0);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
executor.setStreamHandler(new PumpStreamHandler(outputStream, errorStream));
try {
log.info(commandLine.toString());
int exitCode = executor.execute(commandLine, (Map<?, ?>) null);
if (exitCode != 0)
throw new BusinessException("Process exited with non-zero exit code.");
return outputStream.toString();
} catch (ExecuteException e) {
String errorStreamStr = null;
if (errorStream.size() != 0)
errorStreamStr = errorStream.toString();
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append("main.error").append(":\n").append(
e.getMessage()).append("\n\n");
if (errorStreamStr != null) {
errorMessageBuilder.append("additional.error").append(":\n").append(errorStreamStr).append("\n\n");
}
errorMessageBuilder.append("command.line").append(":\n").append(commandLine.toString());
if (log.isDebugEnabled())
log.debug(errorMessageBuilder.toString());
throw new BusinessException(errorMessageBuilder.toString());
} catch (IOException e) {
throw new IllegalStateException(e);
} finally {
StreamUtil.closeQuietly(outputStream, errorStream);
}

Categories