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

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

fix some Findbugs violations

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