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

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

fix #10795 - restart does not work with jnlp if process is launched by jp2launcher.exe

File size: 8.2 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.Arrays;
14import java.util.List;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
18import org.openstreetmap.josm.tools.ImageProvider;
19import org.openstreetmap.josm.tools.Shortcut;
20
21/**
22 * Restarts JOSM as it was launched. Comes from "restart" plugin, originally written by Upliner.
23 * <br><br>
24 * Mechanisms have been improved based on #8561 discussions and <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
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 is resolved later
93 cmd.add(null);
94 // vm arguments
95 for (String arg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
96 // if it's the agent argument : we ignore it otherwise the
97 // address of the old application and the new one will be in conflict
98 if (!arg.contains("-agentlib")) {
99 cmd.add(arg);
100 }
101 }
102 final String javadir = System.getProperty("java.home") + File.separator + "bin" + File.separator;
103 final String java;
104 // Detect JNLP files launched with jp2launcher
105 boolean jp2launcher = cmd.contains("-secure") && cmd.contains("-javaws");
106 if (jp2launcher) {
107 java = javadir + (Main.isPlatformWindows() ? "jp2launcher.exe" : "jp2launcher");
108 } else {
109 java = javadir + (Main.isPlatformWindows() ? "java.exe" : "java");
110 }
111 if (!new File(java).isFile()) {
112 throw new IOException("Unable to find suitable java runtime at "+java);
113 }
114 cmd.set(0, java);
115 if (!jp2launcher) {
116 // program main and program arguments (be careful a sun property. might not be supported by all JVM)
117 String[] mainCommand = System.getProperty("sun.java.command").split(" ");
118 // look for a .jar in all chunks to support paths with spaces (fix #9077)
119 String jarPath = mainCommand[0];
120 for (int i = 1; i < mainCommand.length && !jarPath.endsWith(".jar"); i++) {
121 jarPath += " " + mainCommand[i];
122 }
123 // program main is a jar
124 if (jarPath.endsWith(".jar")) {
125 // if it's a jar, add -jar mainJar
126 cmd.add("-jar");
127 cmd.add(new File(jarPath).getPath());
128 } else {
129 // else it's a .class, add the classpath and mainClass
130 cmd.add("-cp");
131 cmd.add("\"" + System.getProperty("java.class.path") + "\"");
132 cmd.add(mainCommand[0]);
133 }
134 // if it's webstart add JNLP file
135 String jnlp = System.getProperty("jnlp.application.href");
136 if (jnlp != null) {
137 cmd.add(jnlp);
138 }
139 // finally add program arguments
140 cmd.addAll(Arrays.asList(Main.commandLineArgs));
141 }
142 }
143 Main.info("Restart "+cmd);
144 // execute the command in a shutdown hook, to be sure that all the
145 // resources have been disposed before restarting the application
146 Runtime.getRuntime().addShutdownHook(new Thread() {
147 @Override
148 public void run() {
149 try {
150 Runtime.getRuntime().exec(cmd.toArray(new String[cmd.size()]));
151 } catch (IOException e) {
152 Main.error(e);
153 }
154 }
155 });
156 // exit
157 System.exit(0);
158 } catch (Exception e) {
159 // something went wrong
160 throw new IOException("Error while trying to restart the application", e);
161 }
162 }
163
164 /**
165 * Returns a new {@code ButtonSpec} instance that performs this action.
166 * @return A new {@code ButtonSpec} instance that performs this action.
167 */
168 public static ButtonSpec getRestartButtonSpec() {
169 return new ButtonSpec(
170 tr("Restart"),
171 ImageProvider.get("restart"),
172 tr("Restart the application."),
173 ht("/Action/Restart"),
174 isRestartSupported()
175 );
176 }
177
178 /**
179 * Returns a new {@code ButtonSpec} instance that do not perform this action.
180 * @return A new {@code ButtonSpec} instance that do not perform this action.
181 */
182 public static ButtonSpec getCancelButtonSpec() {
183 return new ButtonSpec(
184 tr("Cancel"),
185 ImageProvider.get("cancel"),
186 tr("Click to restart later."),
187 null /* no specific help context */
188 );
189 }
190
191 /**
192 * Returns default {@code ButtonSpec} instances for this action (Restart/Cancel).
193 * @return Default {@code ButtonSpec} instances for this action.
194 * @see #getRestartButtonSpec
195 * @see #getCancelButtonSpec
196 */
197 public static ButtonSpec[] getButtonSpecs() {
198 return new ButtonSpec[] {
199 getRestartButtonSpec(),
200 getCancelButtonSpec()
201 };
202 }
203}
Note: See TracBrowser for help on using the repository browser.