1

I have a spring-boot web application to be distributed as jar file. The code to start the application is as follows:

private static ConfigurableApplicationContext ctx;

    public static void main(String[] args){

        if(ctx == null) {
            ctx = SpringApplication.run(MyApplication.class, args);
        }       
        try {
            openHomePage("http://localhost:8090/");
        }catch(Exception e) {
            logger.error("Error occured starting the application: ", e);
            ctx.close();
        }

    }


private static void openHomePage(String url) throws IOException, URISyntaxException {
        if(Desktop.isDesktopSupported()) {
            URI homePage = new URI(url);
            Desktop.getDesktop().browse(homePage);
        }else {
            Runtime runtime = Runtime.getRuntime();
            runtime.exec(new String[]{"cmd", "/c","start chrome " + url});
        }       

    }

which opens the home page in Chrome, both when I run it from Eclipse and by double clicking on the jar file.

The problem is when I start the application from the jar file and close the browser tab, the application continues to run in JVM and I have to kill it from the task manager manually which is annoying. If I don't kill the JVM and double click on the jar file again, then the application doesn't start automatically as it does the first time, and I have to manually open a new browser tab and type http://localhost:8090/ in order to use the application.

Is it possible to kill every process after user closes the browser tab so that when they click on the jar file next time they need to use the application, a fresh browser tab opens automatically?

Thanks in advance..

sticky_elbows
  • 1,344
  • 1
  • 16
  • 30
  • 2
    It is somewhat strange to start a web application and a browser at the same time. These are two quite different components with different life cycle. – Henry Dec 11 '18 at 09:23
  • 2
    There's a **stop** button in Eclipse. And if you must do this.. You can send something from javascript to your server continiously and when server haven't recieved it for 1 sec, which means the web page was closed, stop itself. – Meow Cat 2012 Dec 11 '18 at 09:36
  • @MeowCat2012 thank you for the comment. I can manage sending the heartbeats with javascript, but how do I handle closing the JVM in the server side upon failing to receive the heartbeats? – sticky_elbows Dec 11 '18 at 10:40
  • I'll move it to an **answer** for better readability. – Meow Cat 2012 Dec 12 '18 at 00:56

2 Answers2

4

SOLUTION

This might not be the best solution but it works a treat.

*Step 1 - Send heartbeats from the browser

var heartBeatIntervals = null;

$( document ).ready(function() {

//this ajax call will be fired every 2 seconds as long as the browser tab stays open.
// the time intervals can of course be modified
heartBeatIntervals = setInterval(() => {
        $.ajax({
            type:'POST',
            url: 'http://localhost:8090/MyController/checkHeartbeats'
        })
    }, 2*1000);

});

*Step 2 - Handle the heartbeats in the server

@Controller
@RequestMapping("/MyController")
public class MyController {

    //declare an instance variable to store the number of missed heartbeats
    private int missedHeartbeats = 0;

    //reset the counter to 0 upon receiving the heartbeats
    @PostMapping("/checkHeartbeats")
    public void checkHeartbeats() {
        missedHeartbeats = 0;
    }

    //increase the missedHeartbeats by one every 3 seconds - or whatever
    @Scheduled(fixedRate = 3000)
    public void schedule() {
        missedHeartbeats++;
        //check how many heartbeats are missed and if it reaches to a certain value
        if(missedHeartbeats > 5) {
            //terminate the JVM (also terminates the servlet context in Eclipse)
            System.exit(0);
        }
    }

}

*Step - 3 Enable scheduling

In order to use any scheduling in spring-boot application you need to add @EnableScheduling annotation in your class where your main method resides.

And that's it.

sticky_elbows
  • 1,344
  • 1
  • 16
  • 30
  • 1
    AFAIK this is in fact the only reliable solution (it can take different forms of course). Any solution depending on the browser detecting it's shutting down and then firing something at the server is unreliable, depends heavily on not just the browser but the exact version and how exactly it's closed (close button, menu option, kill signal, crash, etc.). – jwenting Dec 12 '18 at 08:43
0

There's a stop button in Eclipse. And in case it can't be used:
You can send something from javascript to your server continiously and when server haven't recieved it for 1 sec, which means the web page was closed, stop itself.

Solution 1

  1. Use a method in any @Controller to handle heartbeat requests.
  2. Store the most recent heartbeat time in a static field of any class, the initial value could be 0 or -1 indicating the web page has not been opened yet.
  3. Use a @Scheduled task to retrive last heartbeat time and compare with current time. schedule the task once per 2 second or whatever. https://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html#scheduling-annotation-support
  4. Stop JVM if needed, maybe by System.exit(0).

Solution 2

It would be easier if you can add a Close button on webpage. being clicked, it signals the server to stop, and afterwards it closes the web page itself. https://stackoverflow.com/a/18776480/9399618

Meow Cat 2012
  • 928
  • 1
  • 9
  • 21