I am trying to call a python script from a java/tomcat6 webapp. I am currently using the following code:
Process p = Runtime.getRuntime().exec("python <file.py>");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader b = new BufferedReader(isr);
logger.info("PYTHON OUTPUT");
String line = null;
while ( (line = b.readLine()) != null){
logger.info(line);
}
p.waitFor();
logger.info("COMPLETE PYTHON OUTPUT");
logger.info("EXIT VALUE: "+p.exitValue());
I can't really see any output in the catalinia.out file from the python script and using an adapter library like jython is not possible as the script relies on several machine learning libraries that need python's Numpy module to work.
Help?
The explanation is probably one (or more) of following:
The command is failing and writing error messages to its "stderr" fd ... which you are not looking at.
The command is failing to launch because the command name is incorrect; e.g. it can't be found on $PATH.
The command is trying to read from its stdin fd ... but you haven't provided any input (yet).
It could be a problem with command-line splitting; e.g if you are using pathnames with embedded spaces, or other things that would normally be handled by the shell.
Also, since this is python, this could be a problem with python-specific environment variables, the current directory and/or the effective user that is executing the command.
How to proceed:
Determine if the python command is actually starting. For instance. "hack" the "" to write something to a temporary file on startup.
Change to using ProcessBuilder to create the Process object. This will give you more control over the streams and how they are handled.
Find out what is going to the child processes "stderr". (ProcessBuilder allows you to redirect it to "stdout" ...)
Related
I am having trouble using the > operator to write to file in Process Builder. The actual process will run fine and let me parse using a InputStreamReader etc to parse the output. I want the process to be written to file using command line like >test.json for example.
Here is my code
try {
//process builder used to run a Python script
ProcessBuilder process = new ProcessBuilder("python",
System.getProperty("user.dir")+"\\createJson.py","--structure","cloc.csv",
"--weights","EntityEffort.csv",">","a.json");
process.directory(new File("c:\\users\\chris\\desktop\\test2"));
Process p = process.start();
} catch(Exception e) {
e.printStackTrace();
}
As #JimGarrison points out, > is interpreted by the shell. Here you are directly starting a process for createJson.py, without a shell.
In UNIX you could use ProcessBuilder to start a shell using:
process = new ProcessBuilder("bash", "someCommand", ">", "outputfile");
Something similar will probably work with Windows and cmd.exe.
However, it's not very good practice. It's an opportunity for command injection attacks. Calling external processes is a last-resort approach, and you should try and minimise what you do within those processes.
So you would be better off sticking with what you have, and handle the redirect to file in Java. The ProcessBuilder javadoc gives an example:
File log = new File("log");
processBuilder.redirectOutput(Redirect.appendTo(log));
In the project I am working on, I need to execute a script that I have in a resources folder -- in the class path. I am simply testing the final script functionality, since I am on Windows, I needed a way to output a file to STDIN so I created a simple cat.jar program to clone unixs cat command.
So when I do "java -jar cat.jar someFile.txt" it will output the file to stdout. I'm sure there are different ways of doing what I did.
Anyways,
I want to run that JAR from my main java program.
I am doing
Runtime.getRuntime().exec("java -jar C:/cat.jar C:/test.txt");
I've tried switching the forward slash to a backward slash and escaping it -- didn't work.
Nothing is getting sent to standard out.
Where as, if I run the cat jar on its own, I get the file directed to standard out.
What am I doing wrong here?
Is this enough information?
Use the Process instance returned by exec()
Process cat = Runtime.getRuntime().exec("java -jar C:/cat.jar C:/test.txt");
BufferedInputStream catOutput= new BufferedInputStream(cat.getInputStream());
int read = 0;
byte[] output = new byte[1024];
while ((read = catOutput.read(output)) != -1) {
System.out.println(output[read]);
}
References:
http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html
By default, the created subprocess does not have its own terminal or console. All its standard I/O (stdin, stdout, stderr) operations will be redirected to the parent process, where they can be accessed via the streams obtained using the methods getOutputStream(), getInputStream(), and getErrorStream().
http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#getInputStream()
getInputStream() returns the input stream connected to the normal output of the subprocess.
I have a java servlet running in a server, plus an 'exe file' located in the same server,
i want , in respond to the client passed parameters to the servlet , to run the exe file located on the server and show it to the client , even a screen shot,,
any ideas??!! please help
You can use Process and Runtime classes
Eg :
Runtime r = Runtime.getRuntime();
Process p = r.getRuntime().exec("C:\\newfolder\\run.exe");
For taking screenshot refer to how to take sc in java
This way you can save the image and then send this image to user.
For sending image to client refer to how to send file from sever to client
these are.the pieces , you need to put them together
UPDATE 1 : to kill the exe you can use p.destroy() ( not a good implementation though, as it forcefully kills the process)
UPDATE2 : to check if the process( which is executing your exe) hence to check if the exe is running or not, you can refer to how to check if a process is running
You can run an external command in Java by the following code:
Process p = Runtime.getRuntime().exec("your_external_program_here");
You can pass in parameters as well, simply amend the above line to include what parameters you want to pass into the program.
To retrieve the 'output' of the process you need to get the input stream for the process:
InputStream output = p.getInputStream();
Note the input stream is the piped output of the process. You can then view the contents (advisable to use a buffered reader) like this:
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(output));
while ((line = reader.readLine()) != null) { ... }
Or alternatively you can look at ProcessBuilder which is easier to use :)
I'm trying to integrate with a legacy system. The legacy system uses dialog windows to report errors. It have no return codes at all except for the dialog windows. I start the legacy system with Runtime.exec().
Is there a way to detect if the executed program has spawned dialog windows or any other graphical interface? This solution is done in Windows and the executed program is an exe.
If the legacy system report errors in console, is possible get your erros.
Simply take the inputstream of error and do your reading.
Like this:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
// any error message?
InputStream error = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(error);
BufferedReader br = new BufferedReader(isr);
String line=null;
while ( (line = br.readLine()) != null)
System.out.println(" ERROR >" + line);
I recommend to read: Runtime.exec() quirks
Hope this help.
You can use this JNA snippet to poll for windows started by your process.
AFAIK, you can only get the standard and error output streams from a process using the Java Process API.
So the solution i did, is to use the snippet code that #Gerrett Hall linked to. That snippet code check the active window before i run the command and save the name.
Then after a vile if the command have not returned check if the active window have changed. if it have, kill the process(Alt. send a return key global).
To get the info from the dialog i could use Ctrl + C to copy the content of the dialog and reading the paste buffer to copy the message in to the log. Have not figured out that part yet.
And yes this is a ugly hack but so is the legacy system to.
I'm making an update function for my project, it's working great, until i want it to restart, basically I download the new file and replace it with the old one, and then i want to run it again, now for some reason it doesn't wna run, and i don't get any error...
Here is the complete update class:
http://dl.dropbox.com/u/38414202/Update.txt
Here is the method i'm using to run my .jar file:
String currDir = new File("(CoN).jar").getAbsolutePath();
Process runManager = Runtime.getRuntime().exec("java -jar " + currDir);
It's not clear to me, why do you need to run the jar with a call to exec() . Given that you need to run the code in the .jar file from a Java program, you could simply run the main() method as defined in the jar's manifest, and capture its output - wherever that is.
Using exec() is OK when you need to call a program from the underlying operating system, but there are easier ways to do this if both the caller and the callee are Java programs.
Now, if your jar is gonna change dynamically and you need to update your program according to a new jar, there are mechanisms for reloading its contents, for instance take a look ath this other post.
The JavaDocs for the Process class specifically point out that if you don't capture the output stream of the Process and promptly read it that the process could halt. If this is the case, then you wouldn't see the process that you started run.
I think you have to capture the stream like this :
BufferedReader stdInput = new BufferedReader(new InputStreamReader(runManager.getInputStream()),8*1024);
BufferedReader stdError = new BufferedReader(new InputStreamReader(runManager.getErrorStream()));
// read the output from the command
String s = null;
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The exec function doesn't automatically lookup into the PATH to start a process, so you have to pass the complete path for the java binary.
You can do that by using the java.home system property, see this answer: ProcessBuilder - Start another process / JVM - HowTo?
No one here seemed to help me, so I went to ask my friend and I had it almost right. It abiously required the string to be an array.
solution:
String[] cmd = {"java", "-jar", currDir};
try {
Runtime.getRuntime().exec(cmd);
} catch (IOException e1) {
e1.printStackTrace();
}