How to run java.lang.Process one by one? - java

I need help in running maven command one by one through Java.
In my code I am trying to run maven build command and print the log to Swing TextArea window.
But the problem is Process.waitFor() is not working properly. As a result multiple processes
are running simultaneously and logs are not getting printed properly.
In Internet I found that waitFor() sometimes doesnt work. Instead I can use
Process.isAlive(). But I am not sure in my code how would I use that method.
Please help
Timer timer = new Timer(300, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String line;
for (int i = 0; i < process.length; i++) {
BufferedReader buffer=new BufferedReader(new InputStreamReader(process[i].getInputStream()));
try {
if ((line = buffer.readLine()) != null) {
logTextArea[i].append(line + "\n");
} else {
((Timer) e.getSource()).stop();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
});
try {
for ( int count = 0 ; count < destList.getModel().getSize(); count++){
String projectPath = findDir(new File(codebasePath), destList.getModel().getElementAt(count).toString());
process[count] = Runtime.getRuntime().exec(System.getenv("M2_HOME")+"//bin//mvn.bat clean install -DskipTests -f "+projectPath + "\\pom.xml");
logTextArea[count] = new JTextArea(25, 60);
logFrame[count] = new JFrame("Show Log");
logFrame[count].add(new JScrollPane(logTextArea[count]), BorderLayout.CENTER);
logFrame[count].setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
logFrame[count].pack();
logFrame[count].setLocationByPlatform(true);
logFrame[count].setVisible(true);
timer.start();
process[count].waitFor()
}
} catch (IOException e) {
e.printStackTrace();
}

I am a bit puzzled where exactly you struggle, so maybe I am overlooking something, but you'd generally use it like so:
process[count].waitFor();
while (process[count].isAlive()) {
Thread.sleep(100);
}
You might want to get rid of waitFor completely and add some additional checks to the loop, e.g. a timeout or a signal to cancel the process, in case the process hangs, so your application can terminate properly:
while (process[count].isAlive()) {
if (someTimeoutCondition || someCancelCondition) {
// throw exception or do whatever else you want to do in this situation to gracefully exit
}
Thread.sleep(100);
}

Related

Is there a better way to implement multi-threading REPL?

I'm trying to implement a REPL application.
There are two threads, which are REPL and a loop function. The function will print messages from time to time, and I need the REPL to get the command of input then dispatch it.
This is my implement method (I use JLine):
Thread replThread = new Thread(() -> {
try {
Terminal terminal = TerminalBuilder.builder().system(true).build();
LineReader reader = LineReaderBuilder.builder().terminal(terminal).build();
for (;;) {
String line;
line = reader.readLine("> ");
System.out.println("input command: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
});
Thread loopThread = new Thread(() -> {
for (;;) {
try {
System.out.println("running");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
replThread.start();
loopThread.start();
This is the running screenshot
It shows that the prompt is overlapped with the prompt, and two threads' output conflicts with each other. I need the prompt (such as > ) to be always in the last line on the console.
So is there a better way or library can implement this requirement?

ProcessBuilder in Java on Raspberry Pi 3 not showing error/input stream for omxplayer

I am doing a little program in Java on a Raspberry pi 3 Jessie, and I am trying to use omxplayer to play a sound from inside the java program.
I have the following code:
ProcessBuilder p = new ProcessBuilder("omxplayer", "/path/to/wav");
p.redirectErrorStream(true);
Process pr = p.start();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
Executors.newSingleThreadExecutor().execute(new Runnable() {
#Override
public void run() {
try {
String line = "";
while((line = bufferedReader.readLine()) != null) {
System.out.println("Reading " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
The program will play the sound correctly, but will not output anything until it reaches the end of the wav and then prints all.
However, when I launch the same command directly in a terminal, I can see text showing during the wav.
For example, when I press "+" or "-" in a terminal with omxplayer running, it changes the volume and prints "Current volume : blabla mB", but when I send through the ProcessBuilder "+" or "-", I can hear the sound of my wav changes, but still no outputs.
It is weird because I have used ProcessBuilder for many other uses, and have never encountered a problem as such.
Do you think the problem is with omxplayer's implementation? Or am I doing something wrong here?
EDIT:
I have tried reading the stream without the BufferedReader as such:
InputStream inputStream = pr.getInputStream();
Executors.newSingleThreadExecutor().execute(new Runnable() {
#Override
public void run() {
try {
int read;
while((read = inputStream.read()) >= 0) {
System.out.println("Reading " + (char)read);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
in case the omxplayer did not send any line returns, but the problem remains.
I had exactly the same problem and could fix it with the parameter -s (statistics). In this case, the player continuously puts status information and also all the start infos.

Java- Runtime.getRuntime().exec() will not execute python.exe

For a project I need to start python.exe via Runtime.getRuntime.exec(). However, when I try to run it it won't execute, but it doesn't throw up an IOException. Here's the code:
try
{
Process process=Runtime.getRuntime().exec("C:\\Program Files (x86)\\PythonTest\\python.exe");
}
catch (IOException e)
{
System.out.println("Cannot find python.exe");
e.printStackTrace();
}
You need to get the output from the process and (waitFor() it to finish). Something like,
final String cmd = "C:/Program Files (x86)/PythonTest/python.exe";
Process p = Runtime.getRuntime().exec(cmd);
final InputStream is = p.getInputStream();
Thread t = new Thread(new Runnable() {
public void run() {
InputStreamReader isr = new InputStreamReader(is);
int ch;
try {
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
p.waitFor();
t.join();
To actually do something with python you'll want to get the OutputStream.
I think that the problem is due to eval incorrectly splitting the command string. My understanding is that exec("C:\\Program Files (x86)\\PythonTest\\python.exe") will attempt to run an application called "C:\\Program", passing it 2 command line arguments.
Try this instead:
exec(new String[]{"C:\\Program Files (x86)\\PythonTest\\python.exe"});
The exec(String, ...) command line parsing is primitive, and often has the incorrect behaviour from the programmer's perspective. The best bet is often to split the command and arguments yourself.

Java PID from cmd not changing

I have a swing timer that runs every 30 seconds, it calls a method where I do a search for a few specific application's PIDs that I get from a list.
This is the code in the method that is called.
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec("tasklist");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine = "";
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
for (int i = 0; i < runningAppList.size(); i++) {
if (inputLine.contains(runningAppList.get(i).getExecutableName())) {
appPIDNumber = inputLine.substring(28, 35).trim();
break;
} else {
appPIDNumber = "";
}
}
}
in.close();
} catch (IOException e) {
LoggingUtils.LogExceptions(LoggingConstants.ERROR, e.toString());
}
So if my app is running and I start the application I get the PID, but when I close the application it still shows the PID and does not clear it back to ""; I know I'm missing something small.
Thanks.
I think it is because of the runningAppList. If the application is closed, then that list might be empty, so the "while" loop will not be executed and the variable appPIDNumber will not be set to empty.
Second option is, that r.exec("tasklist") does not contain any line, after your application closed.
Anyway, seems you will have to set appPIDNumber to empty just before the "while" loop.

How do I handle multiple streams in Java?

I'm trying to run a process and do stuff with its input, output and error streams. The obvious way to do this is to use something like select(), but the only thing I can find in Java that does that is Selector.select(), which takes a Channel. It doesn't appear to be possible to get a Channel from an InputStream or OutputStream (FileStream has a getChannel() method but that doesn't help here)
So, instead I wrote some code to poll all the streams:
while( !out_eof || !err_eof )
{
while( out_str.available() )
{
if( (bytes = out_str.read(buf)) != -1 )
{
// Do something with output stream
}
else
out_eof = true;
}
while( err_str.available() )
{
if( (bytes = err_str.read(buf)) != -1 )
{
// Do something with error stream
}
else
err_eof = true;
}
sleep(100);
}
which works, except that it never terminates. When one of the streams reaches end of file, available() returns zero so read() isn't called and we never get the -1 return that would indicate EOF.
One solution would be a non-blocking way to detect EOF. I can't see one in the docs anywhere. Alternatively is there a better way of doing what I want to do?
I see this question here:
link text
and although it doesn't exactly do what I want, I can probably use that idea, of spawning separate threads for each stream, for the particular problem I have now. But surely that isn't the only way to do it? Surely there must be a way to read from multiple streams without using a thread for each?
As you said, the solution outlined in this Answer is the traditional way of reading both stdout and stderr from a Process. A thread-per-stream is the way to go, even though it is slightly annoying.
You will indeed have to go the route of spawning a Thread for each stream you want to monitor. If your use case allows for combining both stdout and stderr of the process in question you need only one thread, otherwise two are needed.
It took me quite some time to get it right in one of our projects where I have to launch an external process, take its output and do something with it while at the same time looking for errors and process termination and also being able to terminate it when the java app's user cancels the operation.
I created a rather simple class to encapsulate the watching part whose run() method looks something like this:
public void run() {
BufferedReader tStreamReader = null;
try {
while (externalCommand == null && !shouldHalt) {
logger.warning("ExtProcMonitor("
+ (watchStdErr ? "err" : "out")
+ ") Sleeping until external command is found");
Thread.sleep(500);
}
if (externalCommand == null) {
return;
}
tStreamReader =
new BufferedReader(new InputStreamReader(watchStdErr ? externalCommand.getErrorStream()
: externalCommand.getInputStream()));
String tLine;
while ((tLine = tStreamReader.readLine()) != null) {
logger.severe(tLine);
if (filter != null) {
if (filter.matches(tLine)) {
informFilterListeners(tLine);
return;
}
}
}
} catch (IOException e) {
logger.logExceptionMessage(e, "IOException stderr");
} catch (InterruptedException e) {
logger.logExceptionMessage(e, "InterruptedException waiting for external process");
} finally {
if (tStreamReader != null) {
try {
tStreamReader.close();
} catch (IOException e) {
// ignore
}
}
}
}
On the calling side it looks like this:
Thread tExtMonitorThread = new Thread(new Runnable() {
public void run() {
try {
while (externalCommand == null) {
getLogger().warning("Monitor: Sleeping until external command is found");
Thread.sleep(500);
if (isStopRequested()) {
getLogger()
.warning("Terminating external process on user request");
if (externalCommand != null) {
externalCommand.destroy();
}
return;
}
}
int tReturnCode = externalCommand.waitFor();
getLogger().warning("External command exited with code " + tReturnCode);
} catch (InterruptedException e) {
getLogger().logExceptionMessage(e, "Interrupted while waiting for external command to exit");
}
}
}, "ExtCommandWaiter");
ExternalProcessOutputHandlerThread tExtErrThread =
new ExternalProcessOutputHandlerThread("ExtCommandStdErr", getLogger(), true);
ExternalProcessOutputHandlerThread tExtOutThread =
new ExternalProcessOutputHandlerThread("ExtCommandStdOut", getLogger(), true);
tExtMonitorThread.start();
tExtOutThread.start();
tExtErrThread.start();
tExtErrThread.setFilter(new FilterFunctor() {
public boolean matches(Object o) {
String tLine = (String)o;
return tLine.indexOf("Error") > -1;
}
});
FilterListener tListener = new FilterListener() {
private boolean abortFlag = false;
public boolean shouldAbort() {
return abortFlag;
}
public void matched(String aLine) {
abortFlag = abortFlag || (aLine.indexOf("Error") > -1);
}
};
tExtErrThread.addFilterListener(tListener);
externalCommand = new ProcessBuilder(aCommand).start();
tExtErrThread.setProcess(externalCommand);
try {
tExtMonitorThread.join();
tExtErrThread.join();
tExtOutThread.join();
} catch (InterruptedException e) {
// when this happens try to bring the external process down
getLogger().severe("Aborted because auf InterruptedException.");
getLogger().severe("Killing external command...");
externalCommand.destroy();
getLogger().severe("External command killed.");
externalCommand = null;
return -42;
}
int tRetVal = tListener.shouldAbort() ? -44 : externalCommand.exitValue();
externalCommand = null;
try {
getLogger().warning("command exit code: " + tRetVal);
} catch (IllegalThreadStateException ex) {
getLogger().warning("command exit code: unknown");
}
return tRetVal;
Unfortunately I don't have to for a self-contained runnable example, but maybe this helps.
If I had to do it again I would have another look at using the Thread.interrupt() method instead of a self-made stop flag (mind to declare it volatile!), but I leave that for another time. :)

Categories