I have JVM and all dependencies for my Java program ready. With Java I would run like:
javac HelloWorld.java
java HelloWorld
Now I want to, in Linux environment, control this Java program processes using Go's cmd package. In Go, when you run command you are given the PID. With this PID, I want to terminate the Java program whenever j want and restart using the same cmd package. Would this work correctly as long as I have JVM installed? I want to do:
cmd := exec.Command("bash", "-c", " "java HelloWorld")
cmd.Start()
syscall.Kill(cmd.Process.Pid)
Thanks!
In short, yes.
As a test, with added interrupt handling so your own Go process doesn't terminate this will work:
package main
import (
"os/exec"
"syscall"
"os"
"os/signal"
"fmt"
)
func main() {
cmd := exec.Command("bash", "-c", "java HelloWorld")
err := cmd.Start()
fmt.Printf("Starting java proccess with pid %d\n", cmd.Process.Pid)
if err != nil {
// do something about it
}
c := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
go func() {
<-c
fmt.Printf("Sending interrupt to pid: %d\n", cmd.Process.Pid)
syscall.Kill(cmd.Process.Pid, syscall.SIGHUP)
done <- true
}()
<-done
}
Companion Java class:
public class HelloWorld {
public static void main(String[] args) throws Exception {
System.out.println("Hello World from Go! But you cant see me :)");
while (true) {
System.out.println("you cant see this because I am outing to the STDOUT of a subshell!");
Thread.sleep(5000);
}
}
}
But it is full of gotchas. As long as your Go process exits normally, it will send the signal you specify (sighup would be natural choice, if I'd venture a guess) to the java pid. But you need to ensure that you wont let a zombie in case your own Go process crash or in case your java application hangs on after failing to shut down cleanly when you tell it to. Saving that pid to a /tmp/ file and doing all sorts of things with it in case of a restart could be interesting, but you know your needs.
Edit: controlling a JVM process from another program might get finicky quick. You should evaluate if you really want to do that. If you are in Linux, I'd take a look at the SysV init/systemd/upstart/start-stop-daemon system your distro uses if your companion java program acts as a daemon.
Related
I am trying to create a console application which hangs up in a way that pressing CTRL + BREAK or sending a SIGTERM signal to the process doesn't terminate it [i.e. it keeps on hanging, without closing]. I want to test that it keeps on going with the following Java code:
public static void main(String[] args) throws IOException {
//Replace APPLICATION PATH HERE with path towards the executable file
Process process = Runtime.getRuntime().exec("APPLICATION PATH HERE");
// this should kill the process
process.destroy();
// if the process is alive, exitValue() will throw exception
try {
process.exitValue();
// the process is dead - hasn't survived kill
System.out.println("WRONG: process died");
} catch (IllegalThreadStateException e) {
// the process is still running
// the process is not dead and survived destroy()
System.out.println("OK: process hanged");
}
}
So far, I have managed to find the following information:
How Can I Make A Command Prompt Hang? , though it doesn't stop SIGTERM, just SIGINT.
I have also tried using Shutdown Hooks in a java -jar executable file, which also give me control over SIGINT,but not over SIGTERM. I want the program to keep running when given SIGTERM,so that I test the destroy function.
I have also written a program in Go which does a similar thing,with the exception that it registers CTRL+ BREAK as an interrupt,for some reason[I am not sure why, but it still doesn't handle SIGTERM signals from the java code]:
package main
import "fmt"
import "os"
import "os/signal"
import "syscall"
func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)
go func() {
sig := <-sigs
fmt.Println("TEST!!")
fmt.Println(sig)
done <- true
}()
fmt.Println("awaiting signal")
<-done
sigs2 := make(chan os.Signal, 1)
done2 := make(chan bool, 1)
signal.Notify(sigs2, syscall.SIGTERM, syscall.SIGINT)
go func() {
sig2 := <-sigs2
fmt.Println("TEST!!")
fmt.Println(sig2)
done2 <- true
}()
fmt.Println("awaiting signal 2")
<-done2
}
NOTE: I still want to be able to close the application with a SIGKILL signal, or the red X in the window :)
Thank you for any ideas :)
From the Java API documentation (emphasis mine):
public abstract void destroy()
Kills the subprocess. The subprocess represented by this Process object is forcibly terminated.
In Windows terms, that means it terminates the process - the equivalent of SIGKILL. There is no way for a process to detect, prevent, or postpone termination.
Note that Windows does not have anything equivalent to SIGTERM. For GUI applications, the recommended procedure is documented in KB178893.
I am working on a program written in Java which, for some actions, launches external programs using user-configured command lines. Currently it uses Runtime.exec() and does not retain the Process reference (the launched programs are either a text editor or archive utility, so no need for the system in/out/err streams).
There is a minor problem with this though, in that when the Java program exits, it doesn't really quit until all the launched programs are exited.
I would greatly prefer it if the launched programs were completely independent of the JVM which launched them.
The target operating system is multiple, with Windows, Linux and Mac being the minimum, but any GUI system with a JVM is really what is desired (hence the user configurability of the actual command lines).
Does anyone know how to make the launched program execute completely independently of the JVM?
Edit in response to a comment
The launch code is as follows. The code may launch an editor positioned at a specific line and column, or it may launch an archive viewer. Quoted values in the configured command line are treated as ECMA-262 encoded, and are decoded and the quotes stripped to form the desired exec parameter.
The launch occurs on the EDT.
static Throwable launch(String cmd, File fil, int lin, int col) throws Throwable {
String frs[][]={
{ "$FILE$" ,fil.getAbsolutePath().replace('\\','/') },
{ "$LINE$" ,(lin>0 ? Integer.toString(lin) : "") },
{ "$COLUMN$",(col>0 ? Integer.toString(col) : "") },
};
String[] arr; // array of parsed tokens (exec(cmd) does not handle quoted values)
cmd=TextUtil.replace(cmd,frs,true,"$$","$");
arr=(String[])ArrayUtil.removeNulls(TextUtil.stringComponents(cmd,' ',-1,true,true,true));
for(int xa=0; xa<arr.length; xa++) {
if(TextUtil.isQuoted(arr[xa],true)) {
arr[xa]=TextDecode.ecma262(TextUtil.stripQuotes(arr[xa]));
}
}
log.println("Launching: "+cmd);
Runtime.getRuntime().exec(arr);
return null;
}
This appears to be happening only when the program is launched from my IDE. I am closing this question since the problem exists only in my development environment; it is not a problem in production. From the test program in one of the answers, and further testing I have conducted I am satisfied that it is not a problem that will be seen by any user of the program on any platform.
There is a parent child relation between your processes and you have to break that.
For Windows you can try:
Runtime.getRuntime().exec("cmd /c start editor.exe");
For Linux the process seem to run detached anyway, no nohup necessary.
I tried it with gvim, midori and acroread.
import java.io.IOException;
public class Exec {
public static void main(String[] args) {
try {
Runtime.getRuntime().exec("/usr/bin/acroread");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Finished");
}
}
I think it is not possible to to it with Runtime.exec in a platform independent way.
for POSIX-Compatible system:
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "your command"}).waitFor();
I have some observations that may help other people facing similar issue.
When you use Runtime.getRuntime().exec() and then you ignore the java.lang.Process handle you get back (like in the code from original poster), there is a chance that the launched process may hang.
I have faced this issue in Windows environment and traced the problem to the stdout and stderr streams. If the launched application is writing to these streams, and the buffer for these stream fills up then the launched application may appear to hang when it tries to write to the streams. The solutions are:
Capture the Process handle and empty out the streams continually - but if you want to terminate the java application right after launching the process then this is not a feasible solution
Execute the process call as cmd /c <<process>> (this is only for Windows environment).
Suffix the process command and redirect the stdout and stderr streams to nul using 'command > nul 2>&1'
It may help if you post a test section of minimal code needed to reproduce the problem. I tested the following code on Windows and a Linux system.
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec(args[0]);
}
}
And tested with the following on Linux:
java -jar JustForTesting.jar /home/monceaux/Desktop/__TMP/test.sh
where test.sh looks like:
#!/bin/bash
ping -i 20 localhost
as well as this on Linux:
java -jar JustForTesting.jar gedit
And tested this on Windows:
java -jar JustForTesting.jar notepad.exe
All of these launched their intended programs, but the Java application had no problems exiting. I have the following versions of Sun's JVM as reported by java -version :
Windows: 1.6.0_13-b03
Linux: 1.6.0_10-b33
I have not had a chance to test on my Mac yet. Perhaps there is some interaction occuring with other code in your project that may not be clear. You may want to try this test app and see what the results are.
You want to launch the program in the background, and separate it from the parent. I'd consider nohup(1).
I suspect this would require a actual process fork. Basically, the C equivalent of what you want is:
pid_t id = fork();
if(id == 0)
system(command_line);
The problem is you can't do a fork() in pure Java. What I would do is:
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
Runtime.getRuntime().exec(command);
}
catch(IOException e)
{
// Handle error.
e.printStackTrace();
}
}
});
t.start();
That way the JVM still won't exit, but no GUI and only a limited memory footprint will remain.
I tried everything mentioned here but without success. Main parent Java process can't quit until the quit of subthread even with cmd /c start and redirecting streams tu nul.
Only one reliable solution for me is this:
try {
Runtime.getRuntime().exec("psexec -i cmd /c start cmd.cmd");
}
catch (Exception e) {
// handle it
}
I know that this is not clear, but this small utility from SysInternals is very helpful and proven. Here is the link.
One way I can think of is to use Runtime.addShutdownHook to register a thread that kills off all the processes (you'd need to retain the process objects somewhere of course).
The shutdown hook is only called when the JVM exits so it should work fine.
A little bit of a hack but effective.
I have a bat script which runs a java application. If I press ctrl+c on it, it the application terminates gracefully, invoking all the shutdown hooks. However, if I just close the cmd window of the bat script, the shutdown hooks are never invoked.
Is there a way to solve this? Perhaps there's a way to tell the bat script how to terminate the invoked applications when its window is closed?
From addShutdownHook documentation:
In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows.
So i think nothing to do here, unfortunately.
CTRL-CLOSE signal in Windows Console. Seems non-tweakable.
Quoting above link:
The system generates a CTRL+CLOSE signal when the user closes a console. All processes attached to the console receive the signal, giving each process an opportunity to clean up before termination. When a process receives this signal, the handler function can take one of the following actions after performing any cleanup operations:
Call ExitProcess to terminate the process.
Return FALSE. If none of the registered handler functions returns TRUE, the default handler terminates the process.
Return TRUE. In this case, no other handler functions are called, and a pop-up dialog box asks the user whether to terminate the process. If the user chooses not to terminate the process, the system does not close the console until the process finally terminates.
UPD. If native tweaks are acceptable for you, WinAPI SetConsoleCtrlHandler function opens way for suppressing of default behavior.
UPD2. Revelations on Java signal handling and termination relatively old article, but section Writing Java signal handlers really may contain what you need.
UPD3.
I've tried Java signal handlers from article above. It works with SIGINT nicely, but it not what we need, and i decided to carry it with SetConsoleCtrlHandler. The result is a bit complicated and may be not worth to implement in your project. Anyway, it could help someone else.
So, the idea was:
Keep reference to shutdown handler thread.
Set custom native console handler routine with JNI.
Call custom Java method on CTRL+CLOSE signal.
Call shutdown handler from that method.
Java code:
public class TestConsoleHandler {
private static Thread hook;
public static void main(String[] args) {
System.out.println("Start");
hook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(hook);
replaceConsoleHandler(); // actually not "replace" but "add"
try {
Thread.sleep(10000); // You have 10 seconds to close console
} catch (InterruptedException e) {}
}
public static void shutdown() {
hook.run();
}
private static native void replaceConsoleHandler();
static {
System.loadLibrary("TestConsoleHandler");
}
}
class ShutdownHook extends Thread {
public void run() {
try {
// do some visible work
new File("d:/shutdown.mark").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Shutdown");
}
}
Native replaceConsoleHandler:
JNIEXPORT void JNICALL Java_TestConsoleHandler_replaceConsoleHandler(JNIEnv *env, jclass clazz) {
env->GetJavaVM(&jvm);
SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
}
And handler itself:
BOOL WINAPI HandlerRoutine(__in DWORD dwCtrlType) {
if (dwCtrlType == CTRL_CLOSE_EVENT) {
JNIEnv *env;
jint res = jvm->AttachCurrentThread((void **)(&env), &env);
jclass cls = env->FindClass("TestConsoleHandler");
jmethodID mid = env->GetStaticMethodID(cls, "shutdown", "()V");
env->CallStaticVoidMethod(cls, mid);
jvm->DetachCurrentThread();
return TRUE;
}
return FALSE;
}
And it works. In JNI code all error checks are omitted for clearance. Shutdown handler creates empty file "d:\shutdown.mark" to indicate correct shutdown.
Complete sources with compiled test binaries here.
Further to the above answer of using SetConsoleCtrlHandler, you can also do this using JNA rather than writing your own native code.
You could create your own interface on kernel32 if you wanted, or use the one provided in this excellent framework: https://gitlab.com/axet/desktop
Some example code:
import com.github.axet.desktop.os.win.GetLastErrorException;
import com.github.axet.desktop.os.win.handle.HANDLER_ROUTINE;
import com.github.axet.desktop.os.win.libs.Kernel32Ex;
...
private static HANDLER_ROUTINE handler =
new HANDLER_ROUTINE()
{
#Override
public long callback(long dwCtrlType) {
if ((int)dwCtrlType == CTRL_CLOSE_EVENT) {
// *** do your shutdown code here ***
return 1;
}
return 0;
}
};
public static void assignShutdownHook() {
if (!Kernel32Ex.INSTANCE.SetConsoleCtrlHandler(handler, true))
throw new GetLastErrorException();
}
Note that I assigned the anonymous class to a field. I originally defined it in the call to SetConsoleCtrlHandler, but I think it was getting collected by the JVM.
Edit 4/9/17: Updated link from github to gitlab.
Though the batch file may be terminated, the console (window) the batch file has been running in may be left open, depending on the operating system, the command processor, and how batch file execution was started (from a command prompt or through a shortcut).
taskkill is a good command for ending a program which is distributed with Windows (I'm assuming you want to stop a DIFFERENT program, not the batch file itself).
It is possible to end programs by process id, executable name, window title, status (i.e. not responding), DLL name, or service name.
Here are some examples based on how you might use this in your batch file:
Force "program.exe" to stop (often the /f "force" flag is needed to force the program to stop, just check whether it is needed for your application by trial and error):
taskkill /f /im program.exe
Stop any non-responsive programs:
taskkill /fi "Status eq NOT RESPONDING"
Stop a program based on its window title (* wildcard is allowed here to match anything):
taskkill /fi "WindowTitle eq Please Login"
taskkill /fi "WindowTitle eq Microsoft*"
You can even use it to stop a program on another computer on your network (although writing the password of an account in a batch file is just not a good idea).
taskkill /s JimsPC /u Jim /p James_007 /im firefox.exe
Another alternative also distributed with Windows is tskill. Although it doesn't have nearly as many options, the commands are a bit simpler.
EDIT:
I am not sure there is. I would think that closing the cmd window is akin to force-closing the app i.e. immediate termination with no further notice. This has the behavior of many applications that, when they are asked to force-close, they actually take a long time to finally terminate. This is because in the OS's efforts to release all resources, some resources (especially certain I/O and/or file resources) don't let go immediately.
IMO, there's nothing Java could even do about it if it wanted to. A force-close happens at the OS level, at which point it releases the memory, file and I/O handles in use, etc. Java does not (nor does any other program) have control over a force-close. At this point, the OS is taking charge.
Someone please correct me if I'm wrong.
I have a jar say test.jar having TestJar as its main class, a shell script jar_executor.sh,and a java file. My test.jar will return 1 if we pass 1 as an argument and 2 if we pass any other value.
My shell script is executing test.jar as follow
#!/usr/bin/ksh
java TestJar 1 -cp test.jar
return_code=$?
exit $return_code
In java file I am creating a process and executing shell script and taking its exitvalue with following code
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(sh jar_executor.sh);
int exitVal = process.waitFor();
System.out.println(exitVal);
This exitVal variable should print 1 or 2 as per argument we are passing but it is printing 255 everytime.
If I use echo $return_code in shell script then I am getting correct value.
Please help me why I am getting value 255 with exit. Thanks in advance!!!
255 or -1 is an application defined exit code, you would have to read the code to know what it means.
A Java application which exits normally, returns 0 and if it throws an Exception, returns 1.
Go to your workspace library, workspace.metadata.plugins\org.eclipse.e4.workbench
and remove the workbench file :) . after that you can restart eclipse
It looks like it might be a Java bug. Others have reported issues similar to what you've seen; see this Java bug report. The Java devs don't think there's a bug but I'm suspicious. The code JRE uses to get the return value from a spawned process is hairy, and I wouldn't be surprised if there's a race condition or other concurrency bug.
I'm guessing that the JRE fails to capture the return code if the spawned process exits very quickly. If my suspicion is correct, adding sleep 1 to your shell script will cause it to work.
Your shell script does not call java correctly:
java TestJar 1 -cp test.jar
You need to set the options for the java command before you mention your main class name. All arguments after your main class name are arguments for your main class and are no longer options for the java VM. So in your case there is no classpath specified for java. I get the following error message when I execute your script: Error: Could not find or load main class TestJar. To fix, you have just to re-order the arguments in your jar_executor.sh script:
java -cp test.jar TestJar 1
I cannot reproduce the 255 on my PC, so I can only guess where that comes from: Either your java command returns an error code of 255 instead of 1 when it fails to load the main class or your korn shell (/usr/bin/ksh) sets this return value when the script is aborted.
Here are all sources I used:
jar_executor.sh
#!/bin/sh -e
java -cp test.jar TestJar 2
return_code=$?
exit $return_code
TestJar.java
public class TestJar {
public static void main(final String[] args) {
System.exit(Integer.parseInt(args[0]));
}
}
JarRunner.java
import java.io.IOException;
public class JarRunner {
public static void main(final String[] args) throws IOException, InterruptedException {
final Runtime runtime = Runtime.getRuntime();
final Process process = runtime.exec("sh jar_executor.sh");
final int exitVal = process.waitFor();
System.out.println(exitVal);
}
}
When I now run java -cp bin JarRunner, I get the output 2 as expected.
You're probably wrong in invoking the script. Try:
Process process = runtime.exec("sh -c jar_executor.sh");
Note the "-c" flag that means you're calling the shell to execute the command.
What is the simplest way to call a program from with a piece of Java code? (The program I want to run is aiSee and it can be run from command line or from Windows GUI; and I am on Vista but the code will also be run on Linux systems).
Take a look at Process and Runtime classes. Keep in mind that what you are trying to accomplish is probably not platform independent.
Here is a little piece of code that might be helpful:
public class YourClass
{
public static void main(String args[])
throws Exception
{
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("name_of_your_application.exe");
int exitVal = proc.exitValue();
System.out.println("Process exitValue: " + exitVal);
}
}
One question in S.O. discussing similiar issues. Another one. And another one.
You can get a runtime instance using Runtime.getRuntime() and call the runtime's exec method, with the command to execute the program as an argument.
For example:
Runtime runTime = Runtime.getRuntime ();
Process proc = rt.exec("iSee.exe");
You can also capture the output of the program by using getting the InputStream from the process.
The difficulty you will run into is how to get the application to know the path. You may want to use an xml or config file, but if you use this link, it should explain how to run a file:
http://www.javacoffeebreak.com/faq/faq0030.html
You may also want to consider passing in some kind of argument to your program to facilitate finding the specific program you want to run.
This could be with command line arguments, properties files or system properties.