1

I'm trying to give to my app self update ability. It download an JAR from my website and save it as myapp.jar.new.

After that, I want to launch a command to delete the current version and rename the new one.

This is my code (see the notes):

public void applyUpdateAndRestart() {
    Runtime rt = Runtime.getRuntime();
    rt.addShutdownHook(new Thread(() -> {
        try {
            String updateCmd = "restart.cmd";
            try (PrintStream ps = new PrintStream(new FileOutputStream(updateCmd))) {
                ps.println("@echo off");
                // wait for a while to the main process closes and the "myapp.jar" to be writable
                ps.println("ping 127.0.0.1 -n 2 > nul"); 
                ps.println("del /q myapp.jar.old");
                ps.println("move myapp.jar myapp.jar.old");
                ps.println("move myapp.jar.new myapp.jar");
                ps.println("java -jar myapp.jar");
            }

            ProcessBuilder p = new ProcessBuilder();
            p.command("cmd", "/c", updateCmd);

            System.out.println("Before apply update");

            p.start(); // this does not launch

            System.out.println("After apply update"); // this prints!
        } catch (Throwable e) {
            e.printStackTrace(); // this does not occurs!
        }
    }));
    System.exit(0);
}

Why my update.cmd does not start?

Beto Neto
  • 3,962
  • 7
  • 47
  • 81
  • 1
    Any exception thrown by the shutdown thread will be suppressed and will not create output. I would catch all exceptions, not just IOExceptions, and print the result - likely something goes wrong when invoking cmd. – Markus Fischer Sep 15 '17 at 11:30
  • @MarkusFischer I tried too catch the Throwable, but it does not occurs, and sorry, the second sysout prints! – Beto Neto Sep 15 '17 at 11:39
  • 1
    You don't see the output of the created child process because its output is bound to the `InputStream` of the `Process` object returned by `p.start()`. Try using `ProcessBuilder.inheritIO()`. – Klitos Kyriacou Sep 15 '17 at 12:26

3 Answers3

2

Solved with this approach:

  • After download my jar to new-myapp.jar, I launch it with an special argument like this: java -jar new-myapp.jar --do-update (running the new jar will unlock the current to be overwritten)
  • My main mehtod intercept the argument --do-update who applies the new jar to current (copy new-myapp.jar myapp.jar).
  • After the new jar was copied, It launches itself again using the overwritten jar (java -jar myapp.jar)

I think that Klitos comment can solve my problem too, but I solved implementing my previous approach.

On the approach of the question the problem was that the cmd /c haven't a console window allocated. Changing the command to cmd /c start solve the problem too because the start command allocate a new console window.

Beto Neto
  • 3,962
  • 7
  • 47
  • 81
0

My idea - since you just call start() for process and finish the shutdown hook - the process dies with your main java process. Try to call Process.waitFor() to have you shutdown hook thread waiting until external process finished.

0

I think that you can't do it like you want. You want to remove the jar of the application but the app is running and therefore could not be removed.

My suggestion is use a launcher.cmd that look for a new.jar if it finds it remove old.jar and rename new.jar and THEN launch java -jar old.jar.