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

Last change on this file since 8554 was 8471, checked in by Don-vip, 9 years ago

offer to automatically download missing required plugins and restart. i18n impact, but this needs to be done before releasing the new tested because of the new dependence on commons-imaging, to avoid future bug reports.

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