Using Runtime.exec to Safely Compile and Execute a .java File - java

After having read a lot of similar questions about Runtime.exec and Java, I've not encountered a safe and clean idiom for compiling and running a .java file. I have just finished reading the "When Runtime.exec() won't" article, which helped me understand the general do's and don't's, but does not provide this idiom I'm looking for.
Overall I'm trying to create separate processes that will compile and run in series (multiple servers), without hanging or leaving any orphan processes. I'm not well-versed with these topics, so I am looking for more pointers.
So far I am able to compile the file by doing this:
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("javac Server.java");
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
} catch (Throwable t) {
t.printStackTrace();
}

Related

java Runtime.exec() crashes Netbeans

I have been searching the web for quite some time now and I did find a lot about Runtime.exec(), but I didn't find a satisfying answer to my problem yet, so I decided to open a new question.
I am running asymptote (http://asymptote.sourceforge.net/) from java. After reading some articles and tinkering around a bit I found this (working) solution:
public static voidcompileAsy(File name)
{
try
{
Runtime rt = Runtime.getRuntime();
String[] cmdarray = {"/usr/texbin/asy", name.getName()};
//String[] envp = {"PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/texbin:/usr/local/bin"};
String[] envp = null;
File fd = new File("/xxxxxx/xxxxx");
Process proc = rt.exec(cmdarray, envp, fd);
// any errors?
StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), "error");
// any output?
StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "output");
// kick them off
errorGobbler.start();
outputGobbler.start();
int exitVal = proc.waitFor();
System.out.println("Process exitValue: " + exitVal);
}
catch(Throwable t)
{
t.printStackTrace();
}
So far so good. It turns out that without the correct path variables set asymptote crashes, which would be no problem if I could catch this event from the java side. Unfortunately when asymptote crashes it takes down java entirely including Netbeans so I have no chance for any diagnosis. Here are my questions:
How does this happen? Isn't asymptote a process on its own and should die without touching the jvm?
How can I prevent this from happening?
The system is MacOSX 10.10.3
Happy to hear any opinion/suggestions on this!
There is one thing I can see that is wrong with your code above and that is that you read the error stream and then read the input stream.
This can cause execution to block and stream buffers fill up.
You should create a separate thread for each stream and once your waitfor call has completed join the threads. I do not know if this is contributing to the crash in some way. Perhaps you are getting an input stream buffer overflow.
Consider changing to use ProcessBuilder, which has simpler options for handling process outputs like inheritIO()

destroy not working in java

I have created a simple java program to open an excel file and write data to it, once the data is written I then proceed to open the file to view the spreadsheet:
String[] cmdarray=new String[]{"cmd.exe","/c","C:\\Users\\Jason\\Documents\\*******\\********\\******.xls"};
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(cmdarray);
as part of the learning curve I then try to close the file 10 secs later with:
process.destroy();
but this isn't closing the window.
Can anyone point out where I am going wrong? Thank you.
private static void OpenExcel() throws IOException {
//Find the File and open it
String[] cmdarray=new String[]{"cmd.exe","/c","C:\\Users\\Jason\\Documents\\*********\\*********\\********.xls"};
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(cmdarray);
try{
//Delay
TimeUnit.SECONDS.sleep(10);
}catch (InterruptedException e) {
e.printStackTrace();
//Handle exception
}
//Close Excel
System.out.println("Closing Excel");
process.destroy();
}
}
One of the reason could be well-known JDK bug:
The fundamental problem here is that, unlike Unix, Windows does that
maintain parent-child relationships between processes. A process can
kill its own immediate children, but unless you make other
arrangements to obtain the information, can't kill any
'grand-children' because it has no way of finding them.
You can try with direct execution of Excel, not via cmd:
Runtime.getRuntime().exec("C:\\full\\path\\to\\excel.exe C:\\file.xls");

Invoking python from Java

I'm building a front-end for my company's internal tool kit. Half the tools are written in python and then the other half are written in several other scripting languages. So I'm building a front-end in java using swing. So far I can invoke python scripts through the following code:
public class Foo
{
public static void main(String[] args)
{
try
{
Runtime r = Runtime.getRuntime();
Process p = r.exec("python foo.py");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
p.waitFor();
String line = "";
while (br.ready())
System.out.println(br.readLine());
}
catch (Exception e)
{
String cause = e.getMessage();
if (cause.equals("python: not found"))
System.out.println("No python interpreter found.");
}
}
}
Which works beautifully but if the python script encounters any errors it doesn't print them out. How can I ensure that it also prints out any errors that it has?
The simple answer is to also read Process.getErrorStream.
The more complicated answer is that what you call Python likely refers to CPython which is just one implementation of the language. There is another implementation, Jython, which basically compiles Python into Java bytecode to be run on a JVM. This would allow tighter integration than simply invoking CPython via Java's Runtime.exec
P.S. Runtime.exec is sort of the old way of doing things. ProcessBuilder is often a much cleaner and more intuitive way of starting a sub-process in Java.
The prevois answer is Ok,here is a suggestion that you shoud release any resources of Process,like:
Process process = null;
try{
//xxxx
}catch(xxx){
}finally{
if(process!=null){
process.destroy();
}
}
The reason is that if you forgot to destroy process,the file handler involved would leak,
you will got an IOException show too many open files finally.

How do I find the process ID (pid) of a process started in java? [duplicate]

This question already has answers here:
How to get PID of process I've just started within java program?
(18 answers)
Closed 9 years ago.
If I get a process object in Java through Runtime.getRuntime().exec(...), or ProcessBuilder.start(), I can wait for it through Process.waitFor(), which is like Thread.join(), or I could kill it with Process.destroy(), which is like the deprecated Thread.stop().
BUT: How do I find the pid of the Process Object? I don't see a method for doing that in The Official Documentation. Can I do this in Java? If so, how?
This guy calls out to bash to get the PID. I'm not sure if there is an java solution to the problem.
/**
* Gets a string representing the pid of this program - Java VM
*/
public static String getPid() throws IOException,InterruptedException {
Vector<String> commands=new Vector<String>();
commands.add("/bin/bash");
commands.add("-c");
commands.add("echo $PPID");
ProcessBuilder pb=new ProcessBuilder(commands);
Process pr=pb.start();
pr.waitFor();
if (pr.exitValue()==0) {
BufferedReader outReader=new BufferedReader(new InputStreamReader(pr.getInputStream()));
return outReader.readLine().trim();
} else {
System.out.println("Error while getting PID");
return "";
}
}
Source:
http://www.coderanch.com/t/109334/Linux-UNIX/UNIX-process-ID-java-program
Similar to the other tools mentioned, there is the jps command line tool that comes with the Java runtime. It spits out the PIDs of all running JVMs. The benefit is the output one needs to parse is confined to only the JVM processes.
Leo, after looking into this issue for about a week myself I think Jhurtado's approach is likely the "best" approach we can manage in Java right now. "best" is in quotes because it has the very nasty side effect of basically being a "guess" at what your child PID is.
If your Java app is spawning native processes quickly in a high-load system, there is NO guarantee that the PID you pickup in your diff calculation is the PID of the Process started by the current Thread or that the PID of the process you pick was even spawned by our app (maybe the host system was already running that process anyway).
That being said, if you are not spawning dozens of processes or the native Process you are spawning is really unique (some custom util you ship with your app) then this approach works fine in which case the PID of the native process you are looking for is the one you want.
On windows you can use 'tasklist' as Jhurtado pointed out to get the full list of PIDs and filter for the one you want (using the /FI filter switch didn't work for me in testing).
On any *nix system you can use "ps ax | grep " where NAME is some process name like 'nginx' or 'httpd' that you want to filter for to get your list.
Additionally, if you need to kill stray processes (for example, on VM exit) on *nix you can of course use "kill -9 " and on Windows, interestingly enough, you can use 'taskkill '.
Hardly optimal unfortunately.
I ran into the same issue as you. I found a pretty decent solution, I recommend a slight sleep before it thought to ensure the process has officially started up.
Process p = Runtime.getRuntime().exec("cmd /c tasklist");
StringWriter writer = new StringWriter();
IOUtils.copy(p.getInputStream(), writer);
String theString = writer.toString();
//System.out.println(theString);
id = findLastString("javaw.exe .{1,} Console 1", theString);
System.out.println(id);
where findLastString is defined as
public static String findLastString(String pattern, String in) {
Pattern p = Pattern.compile(pattern);
Matcher matcher = p.matcher(in);
String it= "";
while(matcher.find()) {
it = matcher.group();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int firstIndex=pattern.indexOf(".{1,}");
int lastIndex=it.substring(firstIndex).indexOf(pattern.substring(pattern.indexOf(".{1,}")+5))+firstIndex;
String dotOn = it.substring(pattern.indexOf(".{1,}"));
it=it.substring(firstIndex, lastIndex);
return it;
}
Basically this will get the list of running processes, and find the most recently ran one with, in this instance, the name javaw.exe (My program was starting a separate java process). You can replace javaw.exe with the name of the process, which you can find by using Task Manager. You will need to get the Apache common IO jar too.
I think in Java your best shot is to get the tasklist before and after spawning your child process. Make a diff and get your PID.
you can get the Tasklist by issuing a Runtime.getRuntime.exec("tasklist");
Notice that tasklist.exe is not included with Windows XP Home edition, but still you can download it.

Help running Java runtime.exec() on multiple threads

In my program, I need to run a external command in a Ubuntu environment (ntpdate) using java. Currently my code looks like this:
Runtime rt = Runtime.getRuntime();
byte[] readBuffer = new byte[131072];
// Exec a process to do the query
Process p = null;
try {
p = rt.exec("ntpdate -q " + ip);
} catch (Exception ex) {
ex.printStackTrace();
}
if(p!= null){
try {
Thread.sleep(1000);
} catch (Exception e) {
}
// Read the input stream, copy it to the file
InputStream in = p.getInputStream();
try {
int count = 0, rc;
while ((rc = in.read(readBuffer, count, readBuffer.length - count)) != -1) {
count += rc;
if (count >= readBuffer.length) {
p.destroy();
break;
}
}
p.destroy();
result = processOutput(readBuffer, count);
} catch (IOException ex) {
ex.printStackTrace();
}
p.destroy();
This code need to be ran simultaneously on multiple threads in order to maximize performance (I need to test a list of 1.000.000 addresses using ntpdate). However, it runs very slowly, barely consuming machine processing. What am I doing wrong? How could I make this more efficient?
The same problem arises when trying to execute "dig" using .exec(), so I doubt it is because of the specific program being called. Is there some restriction in using Runtime.exec() in a multi Threaded environment?
Is Java the most appropriate approach here? Perhaps this would be better in a shell script, which calls ntpdate in the background multiple times? I'm not sure what benefit you're getting from this code snippet by doing this in Java.
What are you doing with the InputStream from the process?
A bash script could do this like:
for ip in #...IP list
do
ntpdate -q $ip > $ip.txt &
done
Why are you waiting for 1 second at each time ?
try {
Thread.sleep(1000);
} catch (Exception e) {
}
This will do nothing but slowing the execution of your application.
Not sure why it's slow but you need to do a lot more to close your resources. Runtime.exec() needs quite a bit of care and attention to avoid hang-ups and leaking of file descriptors.
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
Are you sure the issue isn't ntpdate? If ntpdate is just sitting there waiting for a server response and has a large timeout value, then your application is going to sit there too.
Try calling ntpdate with a timeout of 0.2 and see if it makes a difference.
Also, as you're opening streams in your code, you definitely want to explicitly .close() them when you're done. Otherwise it might not happen until a GC which could be a very long time away.
I think I found the solution, and that is that there is no solution using java's Runtime.exec(). The problem seems to be that all calls to start a process are synchronized. Indeed, if you start each process alone (via synchronization) you get the exact same result of starting all processes together.
Are there any alternatives to exec? Otherwise, I will need to get some solution without linux's ntpdate...
I notice that both of the commands you tried involve network round-trips. How is the speed if you call something like echo or cat instead?

Categories

Resources