in a Java application I need to run an external console application. With the window's ones everything is OK:
try {
System.out.println("Running...");
Runtime.getRuntime().exec("notepad.exe");
System.out.println("End.");
}
catch(Exception e) {
System.out.println(e.getMessage());
}
launches notepad successfully.
But if I put D:\\MyProg.exe or .bat or even cmd.exe (which is it PATH as notepad is) it does not work. Without any exeptions. Just:
Running...
End.
First off, most likely Runtime.exec() is returning asynchronously, so just printing "end" will always work, since the exec call returns immediately, which is what you're seeing.
There's a bunch of other problems that could be showing up here. I think what is happening is that the programs you are calling might be outputting I/O on stdout that you are failing to read, or perhaps you need to wait for it to finish before exiting the java process. There's a great article on the various problems with Runtime.exec() you should probably read, it covers this and other problems.
It is because notepad placed in special folder and this folder exists in Path variable.
Run cmd using following line:
Runtime.getRuntime().exec("cmd.exe /c start");
Run other application:
Runtime.getRuntime().exec("cmd.exe /c start C:\\path\\to\\app.exe");
Related
I am trying to make a console-based Java application that starts some batch scripts that do some other irrelevant things. Presently, I just want to find the proof of concept
I have tried to use the following code:
Runtime.getRuntime().exec("cmd /c start pathtomybatch.bat");
This works fine until I turn it into a .jar file and attempt to execute it. Then it opens the batch file in a new command prompt window, which I don't want it to do. I want to open the batch file in the same window that my Java program is running in. I read about the start command on TechNet and SS64 and found out that apparently adding changing start to start /b would open the program in the same command prompt window. However, when I try to run this:
Runtime.getRuntime().exec("cmd /c start /b pathtomybatch.bat");
NetBeans says BUILD SUCCESSFUL for both lines of code, but when I try the second line of code, no command prompt window opens and my batch file doesn't get started.
I want to know how I can make Java open that batch file within the same command prompt window without stopping the Java application or waiting for it to finish.
Also, as a tiny extra request, could someone tell me if I could do the same for an .exe file?
I'm on Windows 7, but I want this app to work for people using Vista or newer.
The extra window is coming from the start command you initiate. See https://www.windows-commandline.com/cmd-start-command/
A better pattern is to use
Process p = Runtime.getRuntime().exec("cmd /c pathtomybatch.bat");
Then make sure you loop until p.exitValue() no longer throws an exception (which means the process has exited), and while looping copy all available bytes from p.getOutputStream() and p.getErrorStream() to System.out and/or System.err.
How would I make my Java application delete itself and then close out of itself on a Mac/Linux OS? I have tried a couple Runtime commands, but none of them seem to work.
Something like this maybe:
try {
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "rm \"" + getRunningJarPath() + "\""});
} catch (final IOException e) {}
Note: The method: getRunningJarPath IS accurate.
Generally, it's not possible: you program may happen not to have rights to remove itself.
Additionally, there's a problem: while your program is running, JVM holds a read lock on the JAR, so it well may be that you cannot delete it right away.
Usually, you run your program from a script which would check the exit code and remove the files if necessary.
You can create a cron job to delete file, that will start after a delay
You do not state why you want the program to be deleted afterwards.
Anyway, you should not rely on manipulating the file system yourself. I would suggest you look into Java WebStart instead as it provides all the file system caching (including expiration) you need.
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
I'm using Eclipse to develop a Java program, and figured I'd add an option to my program to parse stdin if there are no arguments. (otherwise it parses a file)
I am having problems if I execute "somecommand | java -jar myjar.jar" and went to debug... then realized I don't know how to start a process in Eclipse like that. And if I run it on the command prompt, I can't attach to a running process since the process starts immediately.
Any suggestions on how to debug?
edit: see, the thing is, I wrote my program originally to take a filename argument. Then I figured it would be useful for it to take stdin as well, so I did abstract InputStream out of my program (as Mr. Queue suggests). It works fine operating on a file (java -jar myjar.jar myfile), but not operating when I run type myfile | java -jar myjar.jar. I suspect that there's something different in the two scenarios (eof detection is different?) but I really would like to debug.
// overall program structure follows:
public static void doit(InputStream is)
{
...
}
public static void main(String[] args)
{
if (args.length > 0)
{
// this leaves out the try-catch-finally block,
// but you get the idea.
FileInputStream fis = new FileInputStream(args[0]);
doit(fis);
fis.close();
}
else
{
doit(System.in);
}
}
Run your app, with the pipe, on the command line but add JVM args for remote debugging, like this:
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=1044
suspend=y will tell the JVM to not actually run the program until the debugger is attached.
Next, go into the Eclipse debug launch configurations (Run -> Debug Configurations...) and create a "Remote Java Application" to connect to your app. Run the launch in Eclipse (after setting some breakpoints) and you should be able to debug. Not terribly convenient, but if you can't reproduce your issues without the pipe, this is an option.
If I'm interpreting your question right, I believe you just want to know how to send input across standard in and debug through it in eclipse.
If it's simple input, you can actually manually enter System.in data via the eclipse Console window while the program is running. Just start typing in the console window, and press enter to send the text to Standard in.
If it's something more complicated, I'd suggest abstracting the read you're trying to do to take an InputStream. In your program, you can send System.in as the InputStream. To Debug, you can send any other InputStream. For example, you could put your input in a file, and pass a FileInputStream to the method to test it.
EDIT:
Without seeing some more code, I'm not sure, but you might be on to something with eof detection. A FileInputStream has a defined end of file, but I'd guess System.in has nothing of the sort. Your reader might just be waiting to read the next character and never advancing. You might have to manually stop the read after you know you've read "enough".
Perhaps this solution of creating a named pipe might apply here.
mkfifo foo
somecommand > foo
Next in the debug configuration, add < foo in the args, so that your program is debugged as:
java -jar myjar.jar < foo
I'm late to the party. But you can look for the "common" tab in the debug configuration for your project. There, you should be able to see a section labeled "Standard Input and Output". You can allocate the console with input files and set output files this way.
I have a Java program that I'd like to daemonize on a linux system. In other words, I want to start running it in a shell and have it continue running after I've logged out. I also want to be able to stop the program cleanly.
I found this article which uses a combination of shell scripting and Java code to do the trick. It looks good, but I'd like something simpler, if possible.
What's your preferred method to daemonize a Java program on a Linux system?
Apache Commons Daemon will run your Java program as Linux daemon or WinNT Service.
If you can't rely on Java Service Wrapper cited elsewhere (for instance, if you are running on Ubuntu, which has no packaged version of SW) you probably want to do it the old fashioned way: have your program write its PID in /var/run/$progname.pid, and write a standard SysV init script (use for instance the one for ntpd as an example, it's simple) around it. Preferably, make it LSB-compliant, too.
Essentially, the start function tests if the program is already running (by testing if /var/run/$progname.pid exists, and the contents of that file is the PID of a running process), and if not run
logfile=/var/log/$progname.log
pidfile=/var/run/$progname.pid
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1
The stop function checks on /var/run/$progname.pid, tests if that file is the PID of a running process, verifies that it is a Java VM (so as not to kill a process that simply reused the PID from a dead instance of my Java daemon) and then kills that process.
When called, my main() method will start by writing its PID in the file defined in System.getProperty("pidfile").
One major hurdle, though: in Java, there is no simple and standard way to get the PID of the process the JVM runs in.
Here is what I have come up with:
private static String getPid() {
File proc_self = new File("/proc/self");
if(proc_self.exists()) try {
return proc_self.getCanonicalFile().getName();
}
catch(Exception e) {
/// Continue on fall-back
}
File bash = new File("/bin/bash");
if(bash.exists()) {
ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID");
try {
Process p = pb.start();
BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()));
return rd.readLine();
}
catch(IOException e) {
return String.valueOf(Thread.currentThread().getId());
}
}
// This is a cop-out to return something when we don't have BASH
return String.valueOf(Thread.currentThread().getId());
}
I frequently find myself writing scripts or command lines which essentially look like this, if I want to:
Run a program that is immune to sighups
That is completely disconnected from the shell which spawns it, and
Produces a log file from stderr and stdout the contents of which are displayed as well, but
Allows me to stop viewing the log in progress and do other stuff without disrupting the running process
Enjoy.
nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &
I prefer the nohup command. The blog post says there are better ways, but I don't think they're enough better.
You could try Java Service Wrapper, the community edition is free and meets your needs.
My preferred way on Ubuntu is to use the libslack 'daemon' utility. This is what Jenkins uses on Ubuntu (which is where I got the idea.) I've used it for my Jetty-based server applications and it works well.
When you stop the daemon process it will signal the JVM to shutdown. You can execute shutdown/cleanup code at this point by registering a shutdown hook with Runtime.addShutdownHook().
That depends. If it's just a one-time thing, I want to daemonize it and then go home, but usually I wait for the results, I might do:
nohup java com.me.MyProgram &
at the command line. To kill it cleanly, you have a lot of options. You might have a listener for SIGKILL, or listen on a port and shutdown when a connection is made, periodically check a file. Difference approaches have different weaknesses. If it's for use in production, I'd give it more thought, and probably throw a script into /etc/init.d that nohups it, and have a more sophisticated shutdown, such as what tomcat has.
DaemonTools :- A cleaner way to manage services at UNIX https://cr.yp.to/daemontools.html
Install daemon tools from the url https://cr.yp.to/daemontools/install.html
follow the instruction mentioned there,for any issues please try instructions https://gist.github.com/rizkyabdilah/8516303
Create a file at /etc/init/svscan.conf and add the below lines.(only required for cent-os-6.7)
start on runlevel [12345]
stop on runlevel [^12345]
respawn
exec /command/svscanboot
Create a new script named run inside /service/vm/ folder and add the below lines.
#!/bin/bash
echo starting VM
exec java -jar
/root/learning-/daemon-java/vm.jar
Note:
replace the Jar with your own Jar file. or any java class file.
Reboot the system
svstat /service/vm should be up and running now !.
svc -d /service/vm should bring vm down now !.
svc -u /service/vm should bring vm up now !.
This question is about daemonizing an arbitrary program (not java-specific) so some of the answers may apply to your case:
Take a look here:
http://jnicookbook.owsiak.org/recipe-no-022/
for a sample code that is based on JNI. In this case you daemonize the code that was started as Java and main loop is executed in C. But it is also possible to put main, daemon's, service loop inside Java.
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029
Have fun with JNI!
nohup java -jar {{your-jar.jar}} > /dev/null &
This may do the trick.