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

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

sonar - fb-contrib - minor performance improvements:

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