Search code examples
javabatch-fileprocessbuildershutdown-hook

Why does my restarted Java program lose keyboard focus?


I attempted to create a simplified failsafe Java application that would restart itself, whenever it was forcibly shutdown (in Windows, using CMD command of CTRL+C ).

The batch code looks like this :

@echo off
setlocal

start /wait java BatchWakeMeUpSomehow

if errorlevel 1 goto retry
echo Finished successfully
exit

:retry
echo retrying...
start /wait java BatchWakeMeUpSomehow

And the java code is this one :

public class WakeMeUpSomehow {
    static class Message extends Thread {

        public void run() {
            try {

                while(true)
                {
                    System.out.println("Hello World from run");

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            Runtime.getRuntime().addShutdownHook(new Message());
            while(true)
            {
                System.out.println("Hello World");
                Thread.sleep(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

I wanted to clarify my understanding . I think that because Java runs within a JVM environment, then it has some limitations in regards to restarting a JVM which was forcibly closed down (if we restart a forcibly-shutdown JVM via a batch file, then it loses the cursor-focus and it just runs in a new CMD window that cannot have keyboard focus.

My goal was to have this app keep running in a loop (a la "digital wackamole" ), but I can only ever re-run it once (where it's running in a non-responsive CMD window )

Someone had suggested that I look at Apache Daemon tool, but I'm not sure how this helps.


Solution

  • To make an endless loop in case of errorlevel 1 and above add a label before the start line:

    :run
    start /wait java BatchWakeMeUpSomehow
    if errorlevel 1 echo retrying... & goto run
    echo Finished successfully
    

    However this will also open a new window, so if you want to restart the java process in the already started window you may use typeperf to check its CPU usage (so that you can forcibly close the process and restart it) or simply start java anew once the execution is returned into the batch file.

    • In case the java process exits (doesn't hang) we can detect it with tasklist:

      :run
          start java BatchWakeMeUpSomehow
      :check
          timeout 1 >nul
          tasklist /fi "imagename eq java.exe" | find "java.exe" >nul
          if errorlevel 1 echo retrying... & goto run
          goto check
      
    • In case the java process hangs and the CPU usage is 0% for 1 minute:

      if not "%~1"=="childprocess" goto main
      :loop
          java BatchWakeMeUpSomehow
          goto loop
      
      :main
          start "" "%~dpnx0" childprocess
      :check
          for /f "skip=2 delims=, tokens=2" %%a in ('
              typeperf "\process(java)\%% processor time" -sc 1 -si 60
          ') do if %%a=="0.000000" taskkill /f /im java.exe
          goto check