I have a java process running as windows server using prcorun (http://commons.apache.org/proper/commons-daemon/); unfortunatly I have to launch an external legacy command written in C/C++.
both
Process myProcess = Runtime.getRuntime().exec(command);
and
Process myProcess = new ProcessBuilder(command, arg).start();
work well when java is launched as a stand-alone application, but when I start java as service it replies
command not found
also with
Process myProcess = Runtime.getRuntime().exec("dir");
command not found
I think is a problem due to windows services.
Any suggestion?
I would try to do a quick test and print the PATH environment variable in your service. What I usually found when you run some command as a service, the PATH might not be totally available (which can also explain why DIR is not working for you). If that the case, when starting the service, you have to make sure the PATH include both the normal bin and your legacy bin.
As the error says, the command is not found in the path. You'll need to set the environment variable PATH to the child process's environment. Look at exec(cmd, String[] env) method. You can create an array of environment variables (key value pairs) and pass it to exec().
In my case I used
cmd /c <<YOUR COMMAND>>
eg.
Process myProcess = Runtime.getRuntime().exec("cmd /c dir");
also I added the envinronments. as suggested by smurf
private static String[] getEnv() {
Map<String, String> env = System.getenv();
String[] envp = new String[env.size()];
int i = 0;
for (Map.Entry<String, String> e : env.entrySet()) {
envp[i++] = e.getKey() + "=" + e.getValue();
}
return envp;
}
...
Process myProcess = Runtime.getRuntime().exec("cmd /c dir",getEnv());
Alternative to java.lang.Runtime.exec() that can execute command lines as a single string?
Related
I am able to invoke a java class using below command line:
java -jar <my jar name>.jar -option1 <option> "<a string value>"
However, I want to invoke it from a another Java program.
The name of the main class is XYZ
I have imported the jar as a dependency in my project.
That heavily depends on whether you want to launch it as a separate process or simply execute within the same one.
To kick it off in the same process, you could just call the main method:
String[] arguments = new String[]{"-option1", "<option>", "<a string value>"};
MyOtherMainClass.main(arguments);
To start it as a different process:
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "<my jar name>.jar", "-option1", "<option>", "<a string value>");
Process process = pb.start();
int errCode = process.waitFor();
The second example was inspired by http://examples.javacodegeeks.com/core-java/lang/processbuilder/java-lang-processbuilder-example/
First let me say that this question is not a duplicate of Use Process.Start with parameters AND spaces in path. I am using the System.Diagnostics.Process to start a cmd.exe window and then running java in that window. Except I want the java command to be run based on their installed Java path, as the PATH environment variable is unreliable and doesn't seem to get set very often when Java is installed. So I replaced the "java" in my arguments for the Process with the actual Java path, but now I'm getting this error:
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
Clearly this is because there are spaces in the name, but I am properly quoting the path and using escape characters to create those quotes. Here is the code used to run the cmd.exe:
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
//startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
startInfo.FileName = "cmd.exe";
if (chbPath.Checked) startInfo.Arguments = "/C \"" + javaPath + "\\bin\\java.exe\" -Djava.library.path=\"lib\\natives-win\" -jar SecondDimension.jar " + chbWindowed.Checked.ToString();
else startInfo.Arguments = "/C java -Djava.library.path=\"lib\\natives-win\" -jar SecondDimension.jar " + chbWindowed.Checked.ToString();
process.StartInfo = startInfo;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.Start();
this.Visible = false;
process.WaitForExit();
Console.WriteLine(process.StandardError.ReadToEnd());
Application.Exit();
If chbPath.Checked = false, it runs the command with the java command set with PATH. Which works fine for me, but doesn't for people who haven't ever tried to run java from the command line. But when I check chbPath, then I get the error listed above. Can anyone help with this? This is really annoying and I should have been done with this hours ago, but of course a SPACE....a SINGLE SPACE is stopping me from progressing....ARGHHH!!!
Edit:
Also here is the code for my path finder, which I pulled off another post here:
String javaKey = "SOFTWARE\\JavaSoft\\Java Runtime Environment";
using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(javaKey))
{
String currentVersion = baseKey.GetValue("CurrentVersion").ToString();
using (var homeKey = baseKey.OpenSubKey(currentVersion))
return homeKey.GetValue("JavaHome").ToString();
}
First you could use the property ProcessStartInfo.WorkingDirectory to set the working folder for the Java process, then, because your program is in a different directory you need to change the path to this program.
You could set an Environment variable and use that variable to complete the path to the program or directly include the name of the program in the environment variable
Environment.SetEnvironmentVariable("JAVA_PRG", #"d:\temp"); // Whatever
Process process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = Path.Combine(javaPath, "bin");
startInfo.FileName = "cmd.exe";
if (chbPath.Checked)
startInfo.Arguments = "/C java.exe .... -jar %JAVA_PRG%\SecondDimension.jar ";
Ok, so I was able to fix it. Apparently I don't need to run a cmd window to run the java command, because using diagnostics.process to start a progarm this way always creates a console window. So I just changed the GetJavaInstallationPath() code to return the path to the actual java executable, and then just set StartInfo.FileName = GetJavaInstallationPath(); which pretty much solved all my problems. This way the working directory stays in the game's directory and I still get the console window I wanted. So I guess I was trying too hard. :) Here's the fixed code:
private void btnLaunch_Click(object sender, EventArgs e)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = GetJavaInstallationPath();
startInfo.Arguments = "-Djava.library.path=\"lib\\natives-win\" -jar SecondDimension.jar " + chbWindowed.Checked.ToString();
process.StartInfo = startInfo;
process.Start();
this.Visible = false;
process.WaitForExit();
Application.Exit();
}
This question already has answers here:
How do I execute Windows commands in Java?
(5 answers)
Closed 9 years ago.
If I go to the folder using dos prompt and run:
python.exe DocumentConverter.py a.odt b.pdf
it successfully converts odt to pdf... but if I do this in Java:
p = Runtime.getRuntime().exec(new String[]{
"cmd",
"C:/OpenOffice 4/program/python.exe",
"C:/OpenOffice 4/program/DocumentConverter.py",
"C:/OpenOffice 4/program/a.odt C:/OpenOffice 4/program/b.pdf"});
then nothing happens, why?
Instead of passing a String[] as parameter, try passing just a String.
Runtime.getRuntime().exec("cmd /c C:/OpenOffice 4/program/python.exe C:/OpenOffice 4/program/DocumentConverter.py C:/OpenOffice 4/program/a.odt C:/OpenOffice 4/program/b.pdf");
I believe the thread How do I execute Windows commands in Java? and this page can help you with what you need if you have any questions or wants to know alternative approaches.
I would suggest you try the ProcessBuilder
Process p = new ProcessBuilder("myCommand", "myArg").start();
ProcessBuilder pb =
new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
File log = new File("log");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = pb.start();
assert pb.redirectInput() == Redirect.PIPE;
assert pb.redirectOutput().file() == log;
assert p.getInputStream().read() == -1;
I would add a sleep command at the beginning of DocumentConverter.py, then from cmd, use the command 'tasklist' to see the list of currently running tasks. That should tell you if the way Java is kicking off your program looks the same as how it gets run manually from the cmd window. This is probably the most important thing you can do because it's difficult to get Java to run external programs and pass parameters the same way that you do from the command prompt.
I don't think you should need the 'cmd' to start with.
You are most likely going to have to escape the space in "C:/OpenOffice 4/program/python.exe", so it should be "C:/OpenOffice\\ 4/program/python.exe", otherwise that will probably be viewed as two separate parameters, which is not what you're going for. Better yet, avoid specifying the full path, at least initially. Once you get it working with a relative path, then you can tackle the absolute path. One step at a time.
Also, I would start here: http://commons.apache.org/proper/commons-exec/
The apache commons-exec makes calling external programs from Java better, but it's still painful.
You should do three things differently compared to working code that I have, this may or may not solve your actual problem:
1) You should not pass cmd, with Runtime.getRuntime().exec() you are essentially in the commandline interface already.
2) You should enclose every argument with spaces within quotes, so in Java it looks like the following: "\"argument with spaces\"".
3) There may only be one argument in each element, in this case in String[].
In your code you may do it like this:
p = Runtime.getRuntime().exec(new String[]{
"\"C:/OpenOffice 4/program/python.exe\"",
"\"C:/OpenOffice 4/program/DocumentConverter.py\"",
"\"C:/OpenOffice 4/program/a.odt\"",
"\"C:/OpenOffice 4/program/b.pdf\""});
Then at a later point you can call p.waitFor() if you want your thread (program) to waiit until the execution has finished.
I want to run different commands which can be executed on my command prompt or terminal through Java.
I did search few place but did not get appropriate reply.
I want to run a compiler which is set in the environment as VISAGE_HOME as well as run GRADLE so as to do all my build tasks.
I want to invoke all these commands from within Java Program.
Since it is a swing application I would like to invoke these commands on click of button or some other events.
My Problem is that I am not able to program this :( .
Neither do I know an API which would do this. I went through some sample codes but most of them have same kind of example codes of executing the shell commands or command prompt commands. None showed me to do the above stuff.
Have a look at ProcessBuilder. The Process object it returns has a waitFor method so you can wait for the process to finish. Then you can start your next process.
For example
Process p = new ProcessBuilder("runYourCommand").start();
InputStream in = process.getInputStream();
InputStreamReader inr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(inr);
String inputLine;
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
}
p.waitFor();
Another interesting method on ProcessBuilder is environment(). This will return the environment variables that you can access. From the API docs
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
Something like this:
String cmd = "gedit";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
Firstly, ProcessBuilder is your friend...
You could have a look at;
Getting started with Java’s ProcessBuilder (Linux focus)
Using ProcessBuilder to Make System Calls
Run processbuilder and get in and output
ProcessBuilder and how redirecting input and output from operating system's processes
Executing Operating System Commands from Java
Secondly, You will need to use System.getenv to find the value of the specified environment variable and substitute it yourself.
nb: Thanks to Guillaume Polet for pointing out that the Process will automatically include the path environment variable to find commands.
Also, remember, DO NOT EXECUTE ANY BLOCKING PROCESS ON THE EDT.
Executing external commands are inherently blocking actions, while not explicitly, taking into account needing to consume the output of the process or wanting to know about the processes termination, these would require you to perform some kind of blocking action. Don't do this on the EDT. It will cause you program to appear as if it's hung.
You can use the Runtime.exec methods to run commands from within Java. The system enviroment variables are normally not visible from within the jvm. You could use a launcher, that submits these system enviroment properties as jvm properties to your java application.
According to http://javarevisited.blogspot.de/2011/02/how-to-execute-native-shell-commands.html implementing the following into your code after including "java.lang.Runtime" should perfectly work:
try {
Process process = Runtime.getRuntime().exec("Command to be executed");
} catch (Exception e) {
e.printStackTrace(System.err);
}
I have written a java program named Automate.java, in which the another java program named newsmail will be executed.
The problem i face here is, Automate.java is in Desktop location(should be in desktop only always due to some requirements) and newsmail is in /home/Admin/GATE521/LN_RB this location.
What must be done before the below code, such that the command prompt automatically goes to the required folder and executes the program.
String command = "java newsmail";
Process child = Runtime.getRuntime().exec(command);
You can use this exec() :
Process child = Runtime.getRuntime().exec(command, null, new File("/home/Admin/GATE521/LN_RB"));
Resources :
javadoc - Runtime.exec()
Use the new ProcessBuilder class, instead of Runtime.exec().
ProcessBuilder pb = new ProcessBuilder("java", "newsmail");
pb.directory("/home/Admin/GATE521/LN_RB");
pb.start();
You can even look at pb.environment() to change environment variables if necessary.