I know more or less how to do this, but I think I'm getting burned by the complexity of this command due to inexperience.
I'm trying to feed some raw html into wkhtmltopdf. I can do this from the command line like this:
echo "<p>Hello</p>" | wkhtmltopdf - ~/somePdf.pdf
That works fine, but how do I do this from a Java app? Here's a couple things I've tried:
String[] cmd = { "echo", html.body(), "|", "wkhtmltopdf", "-", "/home/sam/yourPdf.pdf" };
Runtime.getRuntime().exec(cmd);
OR
Runtime.getRuntime().exec("echo " + html.body() + " | wkhtmltopdf - /home/sam/yourPdf.pdf");
Neither one of these produces a file in my home folder.
I've read that wkhtmltopdf will output to STDERR, but I'm not sure how to view that from Eclipse. I was told it should be available in my Console view, but I don't see anything there.
Any help is appreciated, thanks!
Edit
The accepted answer will work for wkhtmltopdf, but for anyone else using the Play! framework who finds this post, there is a Play! module that generates a PDF based on a scala template. It works really well, but don't forget to set media="print" in your stylesheet :)
You cannot do this directly, because you are running two commands and you create a pipe. Neither the Runtime.exec() nor the ProcessBuilder.command() methods are made for this. The easiest way to still achieve something akin to this from Java is to put all that stuff into a shell script and call that script with Runtime.exec() .
EDIT:
You can also skip the shell script and call
Runtime.getRuntime().exec( new String[] { "bash", "-c", "\"echo \"<p>Hello</p>\ | wkhtmltopdf - ~/somePdf.pdf\""} );
That save you writing the shell script, but you may have to fiddle with the quotes a little to get it right.
You can try something like this to output your error stream to your console:
try{
Runtime runTime= Runtime.getRuntime();
Process process= runTime.exec("echo " + html.body() + " | wkhtmltopdf - /home/sam/yourPdf.pdf");
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
while ( (line = reader.readLine()) != null){
System.err.println(line);
}
}catch(Exception exe){
exe.printStackTrace();
}
Note that this is specific to getting what is printed to your error stream. I hope this helps to get you started
Related
I've been trying to run a compiled C program from Java using following commnand. Then I want to get results from process' input stream.
Process p = Runtime.getRuntime().exec(commandLine);
Now, my command is this (first string is path to program, second and third are paths to files, which program takes as params):
trec_eval.8.1\trec_eval.exe trec_eval.8.1\czech TREC\results_2016-04-26_20_52_175.txt
When I run it normally from command line (I'm on Windows 10), it works as expected (C program finishes without errors and prints expected output into the command line), but alas, when I run it from Java, it doesn't work. Both stdout and stderr streams of the process are empty and process' exit status is some error code.
Here is minimal "working" example (I omitted stderr stream, since it made this code snippet too long):
String commandLine = "trec_eval.8.1\\trec_eval.exe" +
" trec_eval.8.1\\czech + " " + file;
System.out.println("Command: " + commandLine);
Process process = Runtime.getRuntime().exec(commandLine);
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder("Output:\n");
for (String line; (line = stdout.readLine()) != null; ) {
output.append(line).append("\n");
}
System.out.println(output.toString());
int exitStatus = 0;
try {
exitStatus = process.waitFor();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("Exit status: " + exitStatus);
stdout.close();
Output from this code are following lines:
Command: trec_eval.8.1\trec_eval.exe trec_eval.8.1\czech TREC\results_2016-04-27_18_27_585.txt
Output:
Exit status: -1073741515
Obviously, I have read several other answers here on Stackoverflow and elsewhere. Unfortunately, code in said answers was pretty much the same as mine (and did not work for me in the same way as my code does not work).
Can someone please tell me, what am I doing wrong? Why is stdout stream empty instead of containing C program's output? Why does not the process exit with status 0 (as it should), but with before-mentioned monstrosity? Finally, if you know, why my Java code does not work as expected, can you explain, why the exact same command works from the the command line?
Thanks in advance.
It seems like the program is not getting something it needs in it's environment. You said the program exited with an error code--so that sounds like your Java code is doing exactly what it should be doing (Starting the program and reading the exit code).
Your paths look relative--perhaps Java isn't starting in the directory you think it is? Try doing a full path to your argument and see if that helps.
Is there a way you can interpret the error code from the app?
If all else fails, try running it through a shell (either cmd /c or sh depending on your OS) using full paths. You can test that without java, then pass the whole thing to java and see if you get the same results.
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();
}
I´m using Mac OS Lion, with java version 1.6.0_26
I'm making a small app for Mac in Java with a main menu for the user, so he can choose several options.
One of them is install an app using a .pkg
Everything was working fine with these commands:
File instFolder = new File(System.getProperty("user.dir") + "/foldername/appInstaller.pkg");
String s = "open "+ instFolder.toString();
Process p = Runtime.getRuntime().exec(s);
Then I realized that there is a problem when foldername has spaces or if I copy this java file with the needed subfolders to a USB pen drive with "NO NAME" as name (or some name with spaces).
Because s will become something like:
open /Volumes/NO NAME/foldername/appInstaller.pkg
or
open /Users/user1/Desktop/folder name/appInstaller.pkg
So when you run the p process, the command will finish where the first space appears on the path
open /Volumes/NO
or
open /Users/user1/Desktop/folder
To try to fix this I changed the s definition for something like this:
String s = "open "+ "\"" + instFolder.toString() + "\"";
It stopped working fine. The strange thing is that if i copy the s value (after creating the s variable) and paste it in the terminal it works:
open "/Users/user1/Desktop/folder name/appInstaller.pkg"
but running it from Java it does't work.
Could you help me, please?
Thanks.
In order to properly escape arguments, you can use the following:
Runtime.getRuntime().exec(new String[] { "open", instFolder.toString() });
Though I would probably to use the more modern ProcessBuilder:
ProcessBuilder pb = new ProcessBuilder("open", instFolder.toString());
Process p = pb.start();
int exitCode = p.waitFor();
Though this may be worth a read depending on what you want to do with the processes output.
Note: edited to reflect question in comment
it seems your path does not have quotes when turned into the shell.
You should probably add "'" on both sides of your path, so the final shell command will look like:
open 'your path'
instead of
open your path
Here's a little trick that came out from the answers mentioned above:
ProcessBuilder pb = new ProcessBuilder(commandString.split(" "));
Say commandString = "killall Mail" then the split will separate the words making it a String[] parameter to the ProcessBuilder.
I am running the following code, and it stops at waitfor() function. What could be the reason and how can I solve it?
String line;
Process albumProcess;
try {
albumProcess = Runtime.getRuntime().exec(
"iconv -f UTF-16 -t UTF-8 /home/gozenem/"+ xmlFileName +
".xml | grep albumID");
albumProcess.waitFor();
BufferedReader in = new BufferedReader(
new InputStreamReader(albumProcess.getInputStream()));
ArrayList<String> lineList = new ArrayList<String>();
while ((line = in.readLine()) != null) {
lineList.add(line);
}
result[0] = lineList.size();
albumProcess.destroy();
} catch (Exception e) {}
The | grep ... is not consuming the output from the command as you expect because getRuntime().exec does not understand piping symbols. The process gets bogged down waiting for something to consume its output and its getting passed bogus command line arguments "|", "grep", and "albumId".
A shell will understand | but execv will not, so you need to use bash -c instead to get a shell to do the piping (see java shell for executing/coordinating processes? do the piping yourself (see Pipe between java processes on command shell not reliable working). Java 7 has a new ProcessBuilder class that makes it easy to set up pipes so you can use those if you're only running on a bleeding edge JVM.
Once you've got grep running, if there's a bunch of lines that match, it may still fill up the buffer, so you need something sitting on the buffer consuming the process's output stream. Moving
albumProcess.waitFor();
after the while loop should do it.
I think you should try to read the output from the process before waiting on it. Otherwise, if the command outputs to much then the buffer may get filled.
Have a look at this article which explains how to read from the process: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
Im developing a simple console Application using java. The code is given below
` try {
File file = new File("writer.txt");
writer = new BufferedWriter(new FileWriter(file));
Process myProcess = Runtime.getRuntime().exec("jps -l");
BufferedReader stdout = new BufferedReader(new InputStreamReader(
myProcess.getInputStream()));
String line = stdout.readLine();
while (line != null) {
if (line.contains(".jar")) {
writer.write(line);
System.out.println(line);
}
line = stdout.readLine();
}
writer.close();
}
`
The code will display the currently running the jar in my windows. The output format is displayed 2356 Timeout.jar I want to display it only Timeout.jar How to remove that integer values. Thanks in advance.
Assuming you have "2356 Timeout.jar" in line, this will return just the jar name:
line.substring(line.indexOf(" ") + 1);
I think there must be an easier way to get the running jar though. I did a quick search and you may want to look at these questions:
How to get the path of a running JAR file?
http://arstechnica.com/civis/viewtopic.php?f=20&t=261563
You could:
Apply a regular expression to line before writing it out. (Think start-of-line, then integers, ending at the first whitespace)
Use ls (or dir) as your exec process instead of jps
Just grab the directory listing directly instead of via the external process as per below:
File dir = new File("directoryName");
String[] children = dir.list();
Doing what you have via JPS is probably not a good idea if this isn't a quick one-off app or a learning exercise because of the following note from the jps man page:
NOTE- You are advised not to write scripts to parse jps output since
the format may change in future releases. If you choose to write
scripts that parse jps output, expect to modify them for future
releases of this tool.
Tokenizing the result is one way.
if you are in unix, use awk to get the second field.
If you are using a Linux based OS,
Instead of
Process myProcess = Runtime.getRuntime().exec("jps -l");
try this one
Process myProcess = Runtime.getRuntime().exec("jps -l | cut -d \" \" -f2");