Restarting Application using Applescript from Java?

Joined
Aug 3, 2011
Messages
6
Reaction score
0
Points
1
The Problem
-----------------------------------------------
Basically I've created a class in java to restart my application by writing a applescript to file called aScriptRestart.scpt, running the applescript, and deleting the applescript upon restart or open if the file exists.

The problem I am having is that the code that runs the applescript is only working 50%, meaning that it quits the application but does not reopen (or reactivate) the application.

The Code:
-----------------------------------------------
Code:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author iwebdevelop
 */
public class RestartMacApp {

    private String script = "tell application \"myApp\"\n"
            + "quit\n"
            + "delay 2 -- Wait for myApp to close\n"
            + "tell application \"myApp\" to activate\n"
            + "end tell";
    private File file = new File("aScriptRestart.scpt");
    private String pathToFile;

    public void runScript() { //works 50%, closes but does not restart because script closes before it
        ScriptToFile();
        try {
            pathToFile = file.getCanonicalPath();
        } catch (IOException ex) {
            Logger.getLogger(RestartMacApp.class.getName()).log(Level.SEVERE, null, ex);
        }
        String[] commandStrings = null;
        Process results = null;
        try {
            commandStrings = new String[]{"/usr/bin/osascript", pathToFile};
            results = Runtime.getRuntime().exec(commandStrings);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deleteScript() { //works
        if (file.exists() && file.isFile()) {
            file.delete();
        } else {
            System.out.println("File not found");
        }
    }

    private void ScriptToFile() { //works
        script.replaceAll("\n", System.getProperty("line.separator"));
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(file));
            writer.write(script);
            writer.close();
        } catch (IOException ioe) {
            System.err.format("IOException: %s%n", ioe);
        }
    }
}

Any Solutions??
-----------------------------------------------
However, if I simply run the script from Script Editor it works perfectly, but within the application it appears to close the script as soon as the application closes.

Is there anyway to do this? Keep in mind, I cannot use the com.apple.cocoa.foundation or similar imports due to this being developed as part of an open-source cross-platform application and is mostly being developed on Windows. I could but the .jar files for com.apple.cocoa.* do not exist, therefore unable to use them.

The goal is to make the open-source application more Mac friendly, as we use the osxappbundle-maven-plugin for our releases.

Any help would be greatly appreciated.

Thanks in advanced!;D
 

vansmith

Senior Member
Joined
Oct 19, 2008
Messages
19,924
Reaction score
559
Points
113
Location
Queensland
Your Mac's Specs
Mini (2014, 2018, 2020), MBA (2020), iPad Pro (2018), iPhone 13 Pro Max, Watch (S6)
I'm going to guess (but I don't know for sure) that when the application quits, the script that you've executed also quits. My hunch, in other words, is that by closing the Java application, you also close any processes that are still executing that were launched from your app. Like I said, I don't know this for sure but it sounds as if this is the case.

Take a look here - it looks as if someone has written a method to do what you're looking to do.
 
OP
I
Joined
Aug 3, 2011
Messages
6
Reaction score
0
Points
1
Reply to vansmith

I'm going to guess (but I don't know for sure) that when the application quits, the script that you've executed also quits. My hunch, in other words, is that by closing the Java application, you also close any processes that are still executing that were launched from your app. Like I said, I don't know this for sure but it sounds as if this is the case.

Take a look here - it looks as if someone has written a method to do what you're looking to do.

I agree, I believe that is exactly what it is doing... I'll take a look there and see.

If not, there's got to be a solution to this problem, b/c I've used many cross-platform applications with restart functions on mac.

Thanks again.
 
OP
I
Joined
Aug 3, 2011
Messages
6
Reaction score
0
Points
1
Re: vansmith

I'm going to guess (but I don't know for sure) that when the application quits, the script that you've executed also quits. My hunch, in other words, is that by closing the Java application, you also close any processes that are still executing that were launched from your app. Like I said, I don't know this for sure but it sounds as if this is the case.

Take a look here - it looks as if someone has written a method to do what you're looking to do.

OK, that link with the code (as seen below) works, but only with .jar files.
Code:
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.myApp.Main;

/**
 * @author [URL="http://stackoverflow.com/questions/4159802/how-can-i-restart-a-java-application"]http://stackoverflow.com/questions/4159802/how-can-i-restart-a-java-application
 */[/URL]
public class RestartMacApp {

    public void restartApplication() {
        final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
        final File currentJar;
        try {
            currentJar = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI());
            /* is it a jar file? */
            if (!currentJar.getName().endsWith(".jar")) {
                return;
            }

            /* Build command: java -jar application.jar */
            final ArrayList<String> command = new ArrayList<String>();
            command.add(javaBin);
            command.add("-jar");
            command.add(currentJar.getPath());

            final ProcessBuilder builder = new ProcessBuilder(command);
            builder.start();
        } catch (IOException ex) {
            Logger.getLogger(RestartMacApp.class.getName()).log(Level.SEVERE, null, ex);
        } catch (URISyntaxException ex) {
            Logger.getLogger(RestartMacApp.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        System.exit(0);
    }

Granted I could just release a .jar version for mac users, but I am releasing a .app version, which is built using Jar Bundler or the osxappbundle-maven-plugin. The issue is, as soon as you wrap the .jar application to a .app, the code above no longer works on .app version and the application just closes and doesn't restart.

I guess the question is, how to do this for an wrapped .app version (Mac OS X Native Executable Version)?
 

vansmith

Senior Member
Joined
Oct 19, 2008
Messages
19,924
Reaction score
559
Points
113
Location
Queensland
Your Mac's Specs
Mini (2014, 2018, 2020), MBA (2020), iPad Pro (2018), iPhone 13 Pro Max, Watch (S6)
I can't give you the Java code for this (I last touched Java in any real capacity about 6 years ago) but instead of having the app execute java with the -jar switch, simply have it execute something like the following:
Code:
open /path/to/application
It looks like instead of building up the command variable by adding bits related to executing a jar file, code in something so that you can execute the above (obviously replacing /path/to/application with the actual path to the app bundle).
 
OP
I
Joined
Aug 3, 2011
Messages
6
Reaction score
0
Points
1
I can't give you the Java code for this (I last touched Java in any real capacity about 6 years ago) but instead of having the app execute java with the -jar switch, simply have it execute something like the following:
Code:
open /path/to/application
It looks like instead of building up the command variable by adding bits related to executing a jar file, code in something so that you can execute the above (obviously replacing /path/to/application with the actual path to the app bundle).

Given it a shot, probably use something like "/usr/bin/open", pathToFile similar to the first code posted. Will post the results when done.

Thanks again.;D
 

vansmith

Senior Member
Joined
Oct 19, 2008
Messages
19,924
Reaction score
559
Points
113
Location
Queensland
Your Mac's Specs
Mini (2014, 2018, 2020), MBA (2020), iPad Pro (2018), iPhone 13 Pro Max, Watch (S6)
You shouldn't need to use the full path to open as /usr/bin/ will be in the user's path. Its not wrong to add it but it shouldn't be needed.
 
OP
I
Joined
Aug 3, 2011
Messages
6
Reaction score
0
Points
1
The Solution

I would just like to say thanks to everyone that responded. I have found the solution.

The Code && Solution:
---------------------------------
Code:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class Restarts Java Bundled Native Mac Applications with the .app extension
 * To use put the following where you want to call a restart, such as in a JMenuItem:
 * <pre>
 *      RestartMac restart = new RestartMac(0);
 * </pre>
 * Then put the following in your main() method to delete the files created:
 * <pre>
 *      RestartMac restart = new RestartMac(1);
 * </pre>
 * @author Paul Barton
 */
public class RestartMac {

    /* AppleScript */
    private String restartScript = "tell application \"yourApplication\" to quit\n"
            + "tell application \"System Events\"\n"
            + "repeat until not (exists process \"yourApplication\")\n"
            + "delay 0.2\n"
            + "end repeat\n"
            + "end tell\n"
            + "tell application \"yourApplication\" to activate";
    /* AppleScript FileName */
    private final File restartFile = new File("yourApplicationRestart.scpt");
    /* Created Application FileName
     * Is created when the AppleScript is Compiled
     */
    private final String restartApp = "yourApplicationRestart.app";
    /* String[] used to Compile AppleScript to Application */
    private final String[] osacompileString = new String[]{"/usr/bin/osacompile", "-o", restartApp, restartFile.toString()};
    /* String[] used to Open created Application */
    private final String[] openString = new String[]{"/usr/bin/open", restartApp};
    /*
     * String used to Delete created Application
     * VERY DANGEROUS IF THIS STRING IS CHANGED
     */
    private final String deleteString = "rm -rf " + restartApp;
    /* Compiles AppleScript to Application */
    private Process osacompile = null;
    /* Opens created Application */
    private Process open = null;
    /* Deletes created Application */
    private Process delete = null;
    /* Arguments for Constructor */
    private int argv;

    /**
     * Restarts YourApplication.app on Mac OS X
     * @param argc 
     */
    public RestartMac(int argc) {
        this.argv = argc;
        if (argc == 0) { //Use 0 when you call a restart, such as in FileMenuItem
            compileAppleScript();
            openApp();
        } else { //Use 1 in main, so on restart it removes the files created
            deleteScript();
            deleteApp();
        }
    }

    /*
     * Write AppleScript to a File
     */
    private void scriptToFile() {
        restartScript.replaceAll("\n", System.getProperty("line.separator"));
        try {
            BufferedWriter restartWriter = new BufferedWriter(new FileWriter(restartFile));
            restartWriter.write(restartScript);
            restartWriter.close();
        } catch (IOException ioe) {
            System.err.format("IOException: %s%n", ioe);
        }
    }

    /*
     * Compiles AppleScript to Application
     */
    private void compileAppleScript() {
        scriptToFile();
        try {
            osacompile = Runtime.getRuntime().exec(osacompileString);
            osacompile.waitFor(); //everything must wait until this process is completed
        } catch (InterruptedException ex) {
            Logger.getLogger(RestartMac.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RestartMac.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /*
     * Opens created Application
     */
    private void openApp() {
        try {
            open = Runtime.getRuntime().exec(openString);
        } catch (IOException ex) {
            Logger.getLogger(RestartMac.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /*
     * Deletes AppleScript if found
     */
    private void deleteScript() {
        if (restartFile.exists() && restartFile.isFile()) {
            restartFile.delete();
        }
    }

    /*
     * Deletes Created Application if found
     */
    private void deleteApp() {
        try {
            delete = Runtime.getRuntime().exec(deleteString);
        } catch (IOException ex) {
            Logger.getLogger(RestartMac.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

I'm sure this code needs to be refactored but it works. If any one can refactor this code, please post the refactored code here as a reply.:D
 

Shop Amazon


Shop for your Apple, Mac, iPhone and other computer products on Amazon.
We are a participant in the Amazon Services LLC Associates Program, an affiliate program designed to provide a means for us to earn fees by linking to Amazon and affiliated sites.
Top