source: josm/trunk/src/org/openstreetmap/josm/actions/RestartAction.java@ 15938

Last change on this file since 15938 was 14397, checked in by Don-vip, 6 years ago

fix #16935 - simplify/cleanup help topics of ToggleDialog/ToggleDialogAction

  • Property svn:eol-style set to native
File size: 9.5 KB
RevLine 
[5857]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
[13647]6import static org.openstreetmap.josm.tools.Utils.getSystemProperty;
[5857]7
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.io.File;
11import java.io.IOException;
12import java.lang.management.ManagementFactory;
[5904]13import java.util.ArrayList;
[8666]14import java.util.Arrays;
15import java.util.Collection;
[5857]16import java.util.List;
17
18import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
[11650]19import org.openstreetmap.josm.gui.MainApplication;
[11093]20import org.openstreetmap.josm.gui.io.SaveLayersDialog;
[12846]21import org.openstreetmap.josm.spi.preferences.Config;
[5857]22import org.openstreetmap.josm.tools.ImageProvider;
[13842]23import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
[12620]24import org.openstreetmap.josm.tools.Logging;
[14138]25import org.openstreetmap.josm.tools.PlatformManager;
[5857]26import org.openstreetmap.josm.tools.Shortcut;
27
28/**
29 * Restarts JOSM as it was launched. Comes from "restart" plugin, originally written by Upliner.
[6830]30 * <br><br>
[8471]31 * Mechanisms have been improved based on #8561 discussions and
32 * <a href="http://lewisleo.blogspot.jp/2012/08/programmatically-restart-java.html">this article</a>.
[5857]33 * @since 5857
34 */
35public class RestartAction extends JosmAction {
36
[7487]37 // AppleScript to restart OS X package
38 private static final String RESTART_APPLE_SCRIPT =
39 "tell application \"System Events\"\n"
40 + "repeat until not (exists process \"JOSM\")\n"
41 + "delay 0.2\n"
42 + "end repeat\n"
43 + "end tell\n"
44 + "tell application \"JOSM\" to activate";
45
[5857]46 /**
47 * Constructs a new {@code RestartAction}.
48 */
49 public RestartAction() {
50 super(tr("Restart"), "restart", tr("Restart the application."),
51 Shortcut.registerShortcut("file:restart", tr("File: {0}", tr("Restart")), KeyEvent.VK_J, Shortcut.ALT_CTRL_SHIFT), false);
[14397]52 setHelpId(ht("/Action/Restart"));
[5857]53 putValue("toolbar", "action/restart");
[12637]54 if (MainApplication.getToolbar() != null) {
55 MainApplication.getToolbar().register(this);
[9238]56 }
[5951]57 setEnabled(isRestartSupported());
[5857]58 }
59
[6084]60 @Override
[5857]61 public void actionPerformed(ActionEvent e) {
62 try {
63 restartJOSM();
64 } catch (IOException ex) {
[12620]65 Logging.error(ex);
[5857]66 }
67 }
[6069]68
[5857]69 /**
[5967]70 * Determines if restarting the application should be possible on this platform.
[5951]71 * @return {@code true} if the mandatory system property {@code sun.java.command} is defined, {@code false} otherwise.
72 * @since 5951
73 */
74 public static boolean isRestartSupported() {
[13647]75 return getSystemProperty("sun.java.command") != null;
[5951]76 }
[6069]77
[5951]78 /**
[10212]79 * Restarts the current Java application.
80 * @throws IOException in case of any I/O error
[5857]81 */
82 public static void restartJOSM() throws IOException {
[12273]83 // If JOSM has been started with property 'josm.restart=true' this means
84 // it is executed by a start script that can handle restart.
85 // Request for restart is indicated by exit code 9.
[13647]86 String scriptRestart = getSystemProperty("josm.restart");
[12273]87 if ("true".equals(scriptRestart)) {
[12636]88 MainApplication.exitJosm(true, 9, SaveLayersDialog.Reason.RESTART);
[12273]89 }
90
[12636]91 if (isRestartSupported() && !MainApplication.exitJosm(false, 0, SaveLayersDialog.Reason.RESTART)) return;
[8666]92 final List<String> cmd;
[10212]93 // special handling for OSX .app package
[14138]94 if (PlatformManager.isPlatformOsx() && getSystemProperty("java.library.path").contains("/JOSM.app/Contents/MacOS")) {
[10212]95 cmd = getAppleCommands();
96 } else {
97 cmd = getCommands();
98 }
[12620]99 Logging.info("Restart "+cmd);
[12846]100 if (Logging.isDebugEnabled() && Config.getPref().getBoolean("restart.debug.simulation")) {
[12620]101 Logging.debug("Restart cancelled to get debug info");
[10212]102 return;
103 }
104 // execute the command in a shutdown hook, to be sure that all the
105 // resources have been disposed before restarting the application
106 Runtime.getRuntime().addShutdownHook(new Thread("josm-restarter") {
107 @Override
108 public void run() {
109 try {
[13206]110 Runtime.getRuntime().exec(cmd.toArray(new String[0]));
[10212]111 } catch (IOException e) {
[12620]112 Logging.error(e);
[10212]113 }
[5857]114 }
[10212]115 });
116 // exit
117 System.exit(0);
[5857]118 }
[6069]119
[8666]120 private static List<String> getAppleCommands() {
121 final List<String> cmd = new ArrayList<>();
122 cmd.add("/usr/bin/osascript");
123 for (String line : RESTART_APPLE_SCRIPT.split("\n")) {
124 cmd.add("-e");
125 cmd.add(line);
126 }
127 return cmd;
128 }
129
130 private static List<String> getCommands() throws IOException {
131 final List<String> cmd = new ArrayList<>();
132 // java binary
133 cmd.add(getJavaRuntime());
134 // vm arguments
135 addVMArguments(cmd);
136 // Determine webstart JNLP file. Use jnlpx.origFilenameArg instead of jnlp.application.href,
137 // because only this one is present when run from j2plauncher.exe (see #10795)
[13647]138 final String jnlp = getSystemProperty("jnlpx.origFilenameArg");
[8666]139 // program main and program arguments (be careful a sun property. might not be supported by all JVM)
[13647]140 final String javaCommand = getSystemProperty("sun.java.command");
[13393]141 if (javaCommand == null) {
142 throw new IOException("Unable to retrieve sun.java.command property");
143 }
[8666]144 String[] mainCommand = javaCommand.split(" ");
145 if (javaCommand.endsWith(".jnlp") && jnlp == null) {
146 // see #11751 - jnlp on Linux
[12620]147 Logging.debug("Detected jnlp without jnlpx.origFilenameArg property set");
[8666]148 cmd.addAll(Arrays.asList(mainCommand));
149 } else {
150 // look for a .jar in all chunks to support paths with spaces (fix #9077)
151 StringBuilder sb = new StringBuilder(mainCommand[0]);
152 for (int i = 1; i < mainCommand.length && !mainCommand[i-1].endsWith(".jar"); i++) {
153 sb.append(' ').append(mainCommand[i]);
154 }
155 String jarPath = sb.toString();
156 // program main is a jar
157 if (jarPath.endsWith(".jar")) {
158 // if it's a jar, add -jar mainJar
159 cmd.add("-jar");
160 cmd.add(new File(jarPath).getPath());
161 } else {
162 // else it's a .class, add the classpath and mainClass
163 cmd.add("-cp");
[13647]164 cmd.add('"' + getSystemProperty("java.class.path") + '"');
[13233]165 cmd.add(mainCommand[0].replace("jdk.plugin/", "")); // Main class appears to be invalid on Java WebStart 9
[8666]166 }
167 // add JNLP file.
168 if (jnlp != null) {
169 cmd.add(jnlp);
170 }
171 }
172 // finally add program arguments
[11650]173 cmd.addAll(MainApplication.getCommandLineArgs());
[8666]174 return cmd;
175 }
176
177 private static String getJavaRuntime() throws IOException {
[13647]178 final String java = getSystemProperty("java.home") + File.separator + "bin" + File.separator +
[14138]179 (PlatformManager.isPlatformWindows() ? "java.exe" : "java");
[8666]180 if (!new File(java).isFile()) {
181 throw new IOException("Unable to find suitable java runtime at "+java);
182 }
183 return java;
184 }
185
186 private static void addVMArguments(Collection<String> cmd) {
187 List<String> arguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
[12620]188 Logging.debug("VM arguments: {0}", arguments);
[8666]189 for (String arg : arguments) {
190 // When run from jp2launcher.exe, jnlpx.remove is true, while it is not when run from javaws
191 // Always set it to false to avoid error caused by a missing jnlp file on the second restart
192 arg = arg.replace("-Djnlpx.remove=true", "-Djnlpx.remove=false");
193 // if it's the agent argument : we ignore it otherwise the
194 // address of the old application and the new one will be in conflict
195 if (!arg.contains("-agentlib")) {
196 cmd.add(arg);
197 }
198 }
199 }
200
[5857]201 /**
202 * Returns a new {@code ButtonSpec} instance that performs this action.
203 * @return A new {@code ButtonSpec} instance that performs this action.
204 */
205 public static ButtonSpec getRestartButtonSpec() {
206 return new ButtonSpec(
207 tr("Restart"),
[13843]208 ImageProvider.get("restart", ImageSizes.LARGEICON),
[5857]209 tr("Restart the application."),
[5951]210 ht("/Action/Restart"),
211 isRestartSupported()
[5857]212 );
213 }
214
215 /**
216 * Returns a new {@code ButtonSpec} instance that do not perform this action.
217 * @return A new {@code ButtonSpec} instance that do not perform this action.
218 */
219 public static ButtonSpec getCancelButtonSpec() {
220 return new ButtonSpec(
221 tr("Cancel"),
[13842]222 new ImageProvider("cancel"),
[5857]223 tr("Click to restart later."),
224 null /* no specific help context */
225 );
226 }
[6069]227
[5857]228 /**
229 * Returns default {@code ButtonSpec} instances for this action (Restart/Cancel).
230 * @return Default {@code ButtonSpec} instances for this action.
231 * @see #getRestartButtonSpec
232 * @see #getCancelButtonSpec
233 */
234 public static ButtonSpec[] getButtonSpecs() {
235 return new ButtonSpec[] {
236 getRestartButtonSpec(),
237 getCancelButtonSpec()
238 };
239 }
240}
Note: See TracBrowser for help on using the repository browser.