Site Sponsors:
Java Processes - Java Jive? 

NOTE:


Our quest to find an elegant solution to the random Platform / Process hang-up (zombie) read-problem lead to the creation of an Open-Source Project.


Cross-platform and easy to re-use, you will recognize some of the following code as par for the Microsoft Windows & POSIX / Linux Test Cases of the IpcReader Project!

--- ORIGINAL OBSERVATION ---


Common Problem


It should have been noticed well before now - but since it is a problem, it should be documented. That way someone can fix it.

The Story


Because 3rd party code tends to break over time, I have been contemplating putting together a few Java 'wrappers' around some strategic external commands. Shelling out to do things like FTP, TAR (etc.) could come in very handy!

Though implementations can differ wildly, wrapping external commands would be far more stable over the eons. -Certainly across the desktops I like to write software for (i.e. Linux, Mac, & Windows.)

The Code


So after trying the 'old' way of starting a command from Java:

Process proc1 = Runtime.getRuntime().exec("ps ax");


-We noticed that trying to do such for a genuine external command, simply did not work on Ubuntu (at least, nut under my current 1.6 version of the Sun/Oracle JVM). While everything seems to run just-fine, trying to read a stream from an executed external command winds up hanging any read-operation in a forever-loop:

Process proc2 = Runtime.getRuntime().exec("/bin/tar");


So what's a good geek to do? -Why, ask other enthusiasts, of course.

Thanks, Stack Overflow!


After scanning over a decade's worth of 'solutions' to the 'we cannot read the process stream' problem, I decided to create the definitive example. An all-in-one class. A single demonstration that incorporated every approach proposed by every-one I could 'google-to.

Here is the best thread:

[ Community Observations ]

Of course I posted the approach at a few places. But I was pleased to get so many interesting responses in so short a time from StackOverflow.

Bottom Line


To save you some reading-time, lets summarize by noting that sometimes using

Process proc3 = new ProcessBuilder("/bin/tar").start();


-is better. Curiously however, sometimes using

Runtime.getRuntime().exec("/bin/tar");


works just as well.

Of the two approaches, we have noted on our platform that while ProcessBuilder fails to recognize 'internal' shell commands, on my machine using ProcessBuilder gives the best results. For me & for now, only ProcessBuilder will properly invoke those external commands.

Conversely, when wanting to run those exact same internal commands, at the time of this writing that classic toolkit is by far the easiest way-to-go. (i.e. No need for scripting, invoking sub-shells, writing daemons, channeling druids, etc.)

'Der Code


Until our various JDK 'gurus catch up with this observation, allow me to share the following code. -Something everyone might quickly try for themselves:


package Problems;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class RunningProblem {

public static class RunningReader implements Runnable {

private Process proc;
private String sName;

private RunningReader(Process proc1, String sName) {
this.proc = proc1;
this.sName = sName;
}

public void run() {
try {
InputStreamReader in = new InputStreamReader(proc.getInputStream());
BufferedReader reader = new BufferedReader(in);

String line = reader.readLine();
while (line != null) {
System.out.println(sName + ": " + line);
line = reader.readLine();
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
try {
Runtime rt = Runtime.getRuntime();

Process proc1 = rt.exec("ps ax");
RunningReader reader1 = new RunningReader(proc1, "reader1");

Process proc2 = rt.exec("ls -l /");
RunningReader reader2 = new RunningReader(proc2, "reader2");

Process proc3 = rt.exec("/bin/tar");
RunningReader reader3 = new RunningReader(proc3, "reader3");

pool.execute(reader3);
pool.execute(reader2);
pool.execute(reader1);

} catch (Exception ex) {
System.err.println(ex.getMessage());
} finally {
pool.shutdown();
}
System.out.println("Launcher.main() Exited.");
}
}


Conversely, here is the latest way to do the same thing using ProcessBuilder:


Process proc1 = new ProcessBuilder("ps ax").start();
RunningReader reader1 = new RunningReader(proc1, "reader1");

Process proc2 = new ProcessBuilder("ls -l /").start();
RunningReader reader2 = new RunningReader(proc2, "reader2");

Process proc3 = new ProcessBuilder("/bin/tar").start();
RunningReader reader3 = new RunningReader(proc3, "reader3");


-Just paste those six lines over their classic equivalent, after trying it.

RFC


If you can take a moment to comment on this thread after trying the above, then we can all learn what-works on which-platform someday.

May the source be with you... Always!


--Rn


[ view entry ] ( 1936 views )   |  permalink  |  related link

<<First <Back | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Next> Last>>