I have a simple server application, which I would like to run in the background. The following line works for me:
Runtime.getRuntime().exec("cmd /c start java -jar ..\\server\\server.jar -Dlog4j.configuration=file:src\\test\\resources\\log4j.properties -filename src\\test\\resources\\server.properties");
But it displays the cmd window and I am unable to destroy it. So I would like to use
Runtime.getRuntime().exec("java -jar ..\\server\\server.jar -Dlog4j.configuration=file:src\\test\\resources\\log4j.properties -filename src\\test\\resources\\scIntegration.properties");
But it simply doesn't connect to the server. So why is that?
A related question. How do I end the process? It is a server that "doesn't end". So I have to kill it and I would assume, that running the java only command would be capable to be destroyed, but with the cmd I have no luck there.
You should split your command into an array in which first argument is the actual command to run and all the rest are command like arguments:
Runtime.getRuntime().exec(new String[] {"/usr/bin/java", "-jar", "..\\server\\server.jar" ...});
Try using an absolute path to the java programm.
For destroying: exec() returns a java.lang.Process, which you should be able to destroy. If not, you have to implement some type of callback to shut your server down, e.g. listening on a specific prot for a shutdown command.
The server is outputing something to stdout and in the shortened command version it didn't have a place to output, so it got stuck while trying to output some data. The solution is to pipe the stdout to eg some file.
Related
I am trying to start a new process using Runtime.exec(), but my problem lies within using ssh to remote in and then run a java program there. Code:
test = "ssh -t username#host java packageName.ClassName portNumber (Other command line args for this class)"
Process proc = Runtime.getRuntime().exec(new String[] {"/bin/bash", "-c", test});
this doesn't fail or catch, but I need to be able to see the stdout for the newly running process and I don't.
Note: if I run ssh -t username#host java packageName.ClassName portNumber (Other command line args for this class) from the command line it works fine. I have the host setup to not require a password by using ssh keys.
Any ideas?
You need to use Process.getInputStream to obtain the output from the sub-process being created.
See this article for a good discussion on Runtime.exec.
I think you can ask for an input stream that corresponds to the stdout of the process and then print it on your standard output. If you need to see it after it executes, just call waitFor() method on the process so it finishes before you start printing.
Use getInputStream() to access returned process's stdout. You can also use facilities provided by ProcessBuilder.Redirect.
This is an extremely strange situation, but I just cannot point out what I'm doing wrong.
I'm executing a big bunch of SQL scripts (table creation scripts, mostly). They are executed through Java, using sqlcmd. Here's the sqlcmd command I use.
sqlcmd -m 11 -S SERVER -d DB -U USER -P PASS -r0 -i "SCRIPT.sql" 2> "ERRORS.log" 1> NULL
Note: I use the -r0 and redirects to make sure only errors go into the log file. I chuck out all STDOUTs.
Now I execute this command in Java, using getRuntime.exec(), like this.
Runtime.getRuntime().gc();
strCmd = "cmd /c sqlcmd -m 11 -S SERVER -d DB -U USER -P PASS -r0 -i \"SCRIPT.sql\" 2> \"ERRORS.log\" 1> NULL"
Process proc = Runtime.getRuntime().exec(strCmd);
proc.waitFor();
Note: I use cmd /c, so that the command runs in its own shell and exits gracefully. Also, this helps in immediately reading the error log to look for errors.
The Problem!
This command works perfectly when run by hand on the command prompt (i.e. the tables are getting created as intended). However, when executed through Java as shown, the scripts are run, and and there are no errors, no exceptions, nothing in the logs. But, when checking in SSMS, the tables aren't there!
Where do I even begin debugging this issue?
UPDATE: I'M A MORON
The return value from the getRuntime().exec method is 1. It should be 0, which denotes normal execution.
Any pointers on how to fix this?
UPDATE 2
I've looked at the process' ErrorStream, and this is what it has.
Sqlcmd: Error: Error occurred while opening or operating on file 2>
(Reason: The filename, directory name, or volume label syntax is
incorrect).
Looks like the path I'm passing is wrong. The error log goes into my profile directory, which is C:\Documents and Settings\my_username. Do the spaces in the path matter? I'm anyways double-quoting them!
Have a look at the exec method with an string array as parameter:
java.lang.Runtime.exec(String[] cmdArray)
The JavaDoc for this method says:
Executes the specified command and arguments in a separate process.
So, the first item in the array is the command and all of your arguments are appended to the array, e. g.,
Runtime.getRuntime().exec(new String[] {"cmd", "/c", "sqlcmd ... "});
After looking at your comment and the implementation of exec(String) it seems to be, that the exec method recognizes the pipe operator > as an argument to cmd, because exec(String) splits the command string to an array using whitespaces as seperators.
I don't have privs to post comments - which is what this is - but what if you try putting in a bogus user id for the DB? Does that cause a different execution path? Will that give you a Java error? Or an Auth error in your DB? Also, def tweak the user, not the password and learn from my experience that if you tweak the password that's a great way to get an account locked out!
The other thing - and this may be a shot in the dark - but what are the JRE and driver you're using? I believe there's a known issue with JRE 1.6.0.29 and the sqljdbc4 JAR. I have more details on this, but I'll have to post the link once I get to work.
Edit:
I know it's been established that the JRE/sqljdbc combo isn't your issue, but if folks search and find this, here is the link I spoke of above:
Driver.getConnection hangs using SQLServer driver and Java 1.6.0_29
First enable log/view commands output (since exec() returns 1), which would point out possible cause of the issue.
Use proc.getInputStream() and print the contents to a file or console.
The following doesn't work in Java (an exception is thrown):
Runtime.getRuntime().exec("cd mydir; myprog");
The same works fine in PHP:
exec("cd mydir; myprog");
What exactly is different in Java's implementation and why (it seems more limited at first glance)?
the java exec command does not use the system command interpreter. something like "cd mydir; myprog" depends on the system command line interpreter (e.g. on windows cmd, on linux sh) to split that into 2 separate commands and execute each of them. java does not invoke the system command interpreter, so that does not work. you either need to call each command separately, or invoke the desired interpreter yourself as part of the command line.
I've seen people have problems like this, and I'm sure there are several ways, however the one I've seen most people reply is this. add cmd before it.
Runtime.getRuntime().exec("cmd cd mydir; myprog");
Assuming you're running an applet, not Java in a CLI environment on the server? If so, then your Java runtime is running on the client computer, not the server.
Java also has a better way to handle multiple commands than your semicolon. Instead of using the signature:
Runtime.exec(String)
try using this for each of your commands:
Runtime.exec(String[])
and make each argument of your command an element in the String array.
I am trying to write a simple application that takes in a command line arguement (which will be a Powershell ps1 file) and then run it. So I have experemented with a number of different approaches and seem to be running into a problem. If I attempt to invoke powershell from within java, the windows process is started and is visible via process explorer, however powershell never returns, it hangs in some sort of loop by the looks of it. The command I am using is:
String command = "powershell -noprofile -noninteractive \"&C:\\new\\tst.ps1\"";
The command is then executed using:
Runtime systemRuntime = Runtime.getRuntime();
Process proc = systemRuntime.exec(command);
At the moment I am hard coding the location to the ps1 file as I was trying to rule this out as an issue. Using a process explorer I can see the hanging powershell process and the command that was passed to it was :
powershell -noprofile -noninteractive "&C:\new\tst.ps1"
which when copied into a cmd window, works to launch the tst.ps1 file. The file itself is incredibly simple in this example and I think I can rule it out being the cause of the freeze as I have tried to launch other ps1 files the same behaviour can be seen.
To further add to the confusion, if I use the java code posted above and pass in powershell commands instead of a file name then it successfully runs.
I've scoured the web and see lots of people experiencing the same issue but no one seems to have posted there solution, I hope its a simple oversight on my part and can be easily fixed.
Any hints/tips are appreciated :D
Alan
You have to close OutputStream in order for Powershell to exit.
Runtime systemRuntime = Runtime.getRuntime();
Process proc = systemRuntime.exec(command);
proc.getOutputStream().close();
Is your external program writing to the standard outputs (err and out)?
If yes, it can hang waiting for you to consume them from the java parent process.
You can get those as InputStreams by calling
Process.getInputStream()
and
Process.getErrorStream()
There's more details here:
Javadoc for Process
Each time I use Runtime.exec("cmd /c start....") I am opening a cmd window. I would like to create a more seamless application by closing each previous cmd window. How can I do this?
If anyone knows of a better way to run a series of commands in the same cmd window rather than opening new ones each time I execute a command, please let me know.
Don't use start, that opens another window
Replace:
Runtime.exec("cmd /c start....")
with:
Runtime.exec("cmd /c ....")
Why do you need cmd windows?
I'd run the command directly in Java and capture the output and display it in a local window (if it's needed at all).
Just make sure you consume all the output from the program or it might stall. Also remember to close the stdout, stderr, and stdin streams or some file handles might leak (well, that's true on some JDKs on some Unix OSes... Windows, who knows).
You cannot control the opened windows from Java. But I suggest two solutions for you:
First:
Runtime.exec("cmd /c start /MIN ...")
The /MIN parameter will prevent windows from appearing.
Second: put all the applications you must call inside the same batch file and call it once. :-)