source: josm/trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java@ 6962

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

see #8465 - rework apturl stuff

  • Property svn:eol-style set to native
File size: 16.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Desktop;
7import java.awt.Dimension;
8import java.awt.GraphicsEnvironment;
9import java.awt.event.KeyEvent;
10import java.io.BufferedReader;
11import java.io.File;
12import java.io.FileReader;
13import java.io.IOException;
14import java.io.InputStreamReader;
15import java.net.URI;
16import java.net.URISyntaxException;
17import java.util.Arrays;
18
19import javax.swing.JOptionPane;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.gui.ExtendedDialog;
23import org.openstreetmap.josm.gui.util.GuiHelper;
24
25/**
26 * see PlatformHook.java
27 *
28 * BTW: THIS IS A STUB. See comments below for details.
29 *
30 * Don't write (Main.platform instanceof PlatformHookUnixoid) because other platform
31 * hooks are subclasses of this class.
32 */
33public class PlatformHookUnixoid implements PlatformHook {
34
35 private String osDescription;
36
37 @Override
38 public void preStartupHook() {
39 }
40
41 @Override
42 public void startupHook() {
43 if (isDebianOrUbuntu()) {
44 // Invite users to install Java 7 if they are still with Java 6 and using a compatible distrib (Debian >= 7 or Ubuntu >= 12.04)
45 String java = System.getProperty("java.version");
46 String os = getOSDescription();
47 if (java != null && java.startsWith("1.6") && os != null && (
48 os.startsWith("Linux Debian GNU/Linux 7") || os.startsWith("Linux Mint") ||
49 os.startsWith("Linux Ubuntu 12") || os.startsWith("Linux Ubuntu 13") || os.startsWith("Linux Ubuntu 14"))) {
50 String url;
51 // apturl does not exist on Debian (see #8465)
52 if (os.startsWith("Linux Debian")) {
53 url = "https://packages.debian.org/stable/openjdk-7-jre";
54 } else if (getPackageDetails("apturl") != null) {
55 url = "apt://openjdk-7-jre";
56 } else if (os.startsWith("Linux Mint")) {
57 url = "http://community.linuxmint.com/software/view/openjdk-7-jre";
58 } else {
59 url = "http://packages.ubuntu.com/trusty/openjdk-7-jre";
60 }
61 askUpdateJava(java, url);
62 }
63 }
64 }
65
66 @Override
67 public void openUrl(String url) throws IOException {
68 for (String program : Main.pref.getCollection("browser.unix",
69 Arrays.asList("xdg-open", "#DESKTOP#", "$BROWSER", "gnome-open", "kfmclient openURL", "firefox"))) {
70 try {
71 if ("#DESKTOP#".equals(program)) {
72 Desktop.getDesktop().browse(new URI(url));
73 } else if (program.startsWith("$")) {
74 program = System.getenv().get(program.substring(1));
75 Runtime.getRuntime().exec(new String[]{program, url});
76 } else {
77 Runtime.getRuntime().exec(new String[]{program, url});
78 }
79 return;
80 } catch (IOException e) {
81 Main.warn(e);
82 } catch (URISyntaxException e) {
83 Main.warn(e);
84 }
85 }
86 }
87
88 @Override
89 public void initSystemShortcuts() {
90 // TODO: Insert system shortcuts here. See Windows and especially OSX to see how to.
91 for(int i = KeyEvent.VK_F1; i <= KeyEvent.VK_F12; ++i)
92 Shortcut.registerSystemShortcut("screen:toogle"+i, tr("reserved"), i, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic();
93 Shortcut.registerSystemShortcut("system:reset", tr("reserved"), KeyEvent.VK_DELETE, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic();
94 Shortcut.registerSystemShortcut("system:resetX", tr("reserved"), KeyEvent.VK_BACK_SPACE, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK).setAutomatic();
95 }
96
97 /**
98 * This should work for all platforms. Yeah, should.
99 * See PlatformHook.java for a list of reasons why
100 * this is implemented here...
101 */
102 @Override
103 public String makeTooltip(String name, Shortcut sc) {
104 String result = "";
105 result += "<html>";
106 result += name;
107 if (sc != null && sc.getKeyText().length() != 0) {
108 result += " ";
109 result += "<font size='-2'>";
110 result += "("+sc.getKeyText()+")";
111 result += "</font>";
112 }
113 result += "&nbsp;</html>";
114 return result;
115 }
116
117 @Override
118 public String getDefaultStyle() {
119 return "javax.swing.plaf.metal.MetalLookAndFeel";
120 }
121
122 @Override
123 public boolean canFullscreen() {
124 return GraphicsEnvironment.getLocalGraphicsEnvironment()
125 .getDefaultScreenDevice().isFullScreenSupported();
126 }
127
128 @Override
129 public boolean rename(File from, File to) {
130 return from.renameTo(to);
131 }
132
133 /**
134 * Determines if the distribution is Debian or Ubuntu, or a derivative.
135 * @return {@code true} if the distribution is Debian, Ubuntu or Mint, {@code false} otherwise
136 */
137 public static boolean isDebianOrUbuntu() {
138 try {
139 String dist = Utils.execOutput(Arrays.asList("lsb_release", "-i", "-s"));
140 return "Debian".equalsIgnoreCase(dist) || "Ubuntu".equalsIgnoreCase(dist) || "Mint".equalsIgnoreCase(dist);
141 } catch (IOException e) {
142 Main.warn(e);
143 return false;
144 }
145 }
146
147 /**
148 * Determines if the JVM is OpenJDK-based.
149 * @return {@code true} if {@code java.home} contains "openjdk", {@code false} otherwise
150 * @since 6951
151 */
152 public static boolean isOpenJDK() {
153 String javaHome = System.getProperty("java.home");
154 return javaHome != null && javaHome.contains("openjdk");
155 }
156
157 /**
158 * Get the package name including detailed version.
159 * @param packageName The package name
160 * @return The package name and package version if it can be identified, null otherwise
161 */
162 public static String getPackageDetails(String packageName) {
163 try {
164 String version = Utils.execOutput(Arrays.asList(
165 "dpkg-query", "--show", "--showformat", "${Architecture}-${Version}", packageName));
166 if (version != null) {
167 return packageName + ":" + version;
168 }
169 } catch (IOException e) {
170 Main.warn(e);
171 }
172 return null;
173 }
174
175 /**
176 * Get the Java package name including detailed version.
177 *
178 * Some Java bugs are specific to a certain security update, so in addition
179 * to the Java version, we also need the exact package version.
180 *
181 * This was originally written for #8921, so only Debian based distributions
182 * are covered at the moment. This can be extended to other distributions
183 * if needed.
184 *
185 * @return The package name and package version if it can be identified, null
186 * otherwise
187 */
188 public String getJavaPackageDetails() {
189 if (isDebianOrUbuntu()) {
190 String javaHome = System.getProperty("java.home");
191 if ("/usr/lib/jvm/java-6-openjdk-amd64/jre".equals(javaHome) ||
192 "/usr/lib/jvm/java-6-openjdk-i386/jre".equals(javaHome) ||
193 "/usr/lib/jvm/java-6-openjdk/jre".equals(javaHome)) {
194 return getPackageDetails("openjdk-6-jre");
195 }
196 if ("/usr/lib/jvm/java-7-openjdk-amd64/jre".equals(javaHome) ||
197 "/usr/lib/jvm/java-7-openjdk-i386/jre".equals(javaHome)) {
198 return getPackageDetails("openjdk-7-jre");
199 }
200 }
201 return null;
202 }
203
204 /**
205 * Get the Web Start package name including detailed version.
206 *
207 * Debian and Ubuntu OpenJDK packages are shipped with icedtea-web package,
208 * but its version does not match main java package version.
209 *
210 * Only Debian based distributions are covered at the moment.
211 * This can be extended to other distributions if needed.
212 *
213 * Simply return {@code null} if there's no separate package for Java WebStart.
214 *
215 * @return The package name and package version if it can be identified, null otherwise
216 */
217 public String getWebStartPackageDetails() {
218 if (isDebianOrUbuntu() && isOpenJDK()) {
219 return getPackageDetails("icedtea-netx");
220 }
221 return null;
222 }
223
224 protected String buildOSDescription() {
225 String osName = System.getProperty("os.name");
226 if ("Linux".equalsIgnoreCase(osName)) {
227 try {
228 // Try lsb_release (only available on LSB-compliant Linux systems, see https://www.linuxbase.org/lsb-cert/productdir.php?by_prod )
229 Process p = Runtime.getRuntime().exec("lsb_release -ds");
230 BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
231 String line = Utils.strip(input.readLine());
232 Utils.close(input);
233 if (line != null && !line.isEmpty()) {
234 line = line.replaceAll("\"+","");
235 line = line.replaceAll("NAME=",""); // strange code for some Gentoo's
236 if(line.startsWith("Linux ")) // e.g. Linux Mint
237 return line;
238 else if(!line.isEmpty())
239 return "Linux " + line;
240 }
241 } catch (IOException e) {
242 // Non LSB-compliant Linux system. List of common fallback release files: http://linuxmafia.com/faq/Admin/release-files.html
243 for (LinuxReleaseInfo info : new LinuxReleaseInfo[]{
244 new LinuxReleaseInfo("/etc/lsb-release", "DISTRIB_DESCRIPTION", "DISTRIB_ID", "DISTRIB_RELEASE"),
245 new LinuxReleaseInfo("/etc/os-release", "PRETTY_NAME", "NAME", "VERSION"),
246 new LinuxReleaseInfo("/etc/arch-release"),
247 new LinuxReleaseInfo("/etc/debian_version", "Debian GNU/Linux "),
248 new LinuxReleaseInfo("/etc/fedora-release"),
249 new LinuxReleaseInfo("/etc/gentoo-release"),
250 new LinuxReleaseInfo("/etc/redhat-release")
251 }) {
252 String description = info.extractDescription();
253 if (description != null && !description.isEmpty()) {
254 return "Linux " + description;
255 }
256 }
257 }
258 }
259 return osName;
260 }
261
262 @Override
263 public String getOSDescription() {
264 if (osDescription == null) {
265 osDescription = buildOSDescription();
266 }
267 return osDescription;
268 }
269
270 protected static class LinuxReleaseInfo {
271 private final String path;
272 private final String descriptionField;
273 private final String idField;
274 private final String releaseField;
275 private final boolean plainText;
276 private final String prefix;
277
278 public LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField) {
279 this(path, descriptionField, idField, releaseField, false, null);
280 }
281
282 public LinuxReleaseInfo(String path) {
283 this(path, null, null, null, true, null);
284 }
285
286 public LinuxReleaseInfo(String path, String prefix) {
287 this(path, null, null, null, true, prefix);
288 }
289
290 private LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField, boolean plainText, String prefix) {
291 this.path = path;
292 this.descriptionField = descriptionField;
293 this.idField = idField;
294 this.releaseField = releaseField;
295 this.plainText = plainText;
296 this.prefix = prefix;
297 }
298
299 @Override public String toString() {
300 return "ReleaseInfo [path=" + path + ", descriptionField=" + descriptionField +
301 ", idField=" + idField + ", releaseField=" + releaseField + "]";
302 }
303
304 /**
305 * Extracts OS detailed information from a Linux release file (/etc/xxx-release)
306 * @return The OS detailed information, or {@code null}
307 */
308 public String extractDescription() {
309 String result = null;
310 if (path != null) {
311 File file = new File(path);
312 if (file.exists()) {
313 BufferedReader reader = null;
314 try {
315 reader = new BufferedReader(new FileReader(file));
316 String id = null;
317 String release = null;
318 String line;
319 while (result == null && (line = reader.readLine()) != null) {
320 if (line.contains("=")) {
321 String[] tokens = line.split("=");
322 if (tokens.length >= 2) {
323 // Description, if available, contains exactly what we need
324 if (descriptionField != null && descriptionField.equalsIgnoreCase(tokens[0])) {
325 result = Utils.strip(tokens[1]);
326 } else if (idField != null && idField.equalsIgnoreCase(tokens[0])) {
327 id = Utils.strip(tokens[1]);
328 } else if (releaseField != null && releaseField.equalsIgnoreCase(tokens[0])) {
329 release = Utils.strip(tokens[1]);
330 }
331 }
332 } else if (plainText && !line.isEmpty()) {
333 // Files composed of a single line
334 result = Utils.strip(line);
335 }
336 }
337 // If no description has been found, try to rebuild it with "id" + "release" (i.e. "name" + "version")
338 if (result == null && id != null && release != null) {
339 result = id + " " + release;
340 }
341 } catch (IOException e) {
342 // Ignore
343 } finally {
344 Utils.close(reader);
345 }
346 }
347 }
348 // Append prefix if any
349 if (result != null && !result.isEmpty() && prefix != null && !prefix.isEmpty()) {
350 result = prefix + result;
351 }
352 if(result != null)
353 result = result.replaceAll("\"+","");
354 return result;
355 }
356 }
357
358 protected void askUpdateJava(String version) {
359 askUpdateJava(version, "https://www.java.com/download");
360 }
361
362 protected void askUpdateJava(final String version, final String url) {
363 GuiHelper.runInEDTAndWait(new Runnable() {
364 @Override
365 public void run() {
366 ExtendedDialog ed = new ExtendedDialog(
367 Main.parent,
368 tr("Outdated Java version"),
369 new String[]{tr("Update Java"), tr("Cancel")});
370 // Check if the dialog has not already been permanently hidden by user
371 if (!ed.toggleEnable("askUpdateJava7").toggleCheckState()) {
372 ed.setButtonIcons(new String[]{"java.png", "cancel.png"}).setCancelButton(2);
373 ed.setMinimumSize(new Dimension(480, 300));
374 ed.setIcon(JOptionPane.WARNING_MESSAGE);
375 String content = tr("You are running version {0} of Java.", "<b>"+version+"</b>")+"<br><br>";
376 if ("Sun Microsystems Inc.".equals(System.getProperty("java.vendor")) && !isOpenJDK()) {
377 content += "<b>"+tr("This version is no longer supported by {0} since {1} and is not recommended for use.",
378 "Oracle", tr("February 2013"))+"</b><br><br>";
379 }
380 content += "<b>"+tr("JOSM will soon stop working with this version; we highly recommend you to update to Java {0}.", "7")+"</b><br><br>"+
381 tr("Would you like to update now ?");
382 ed.setContent(content);
383
384 if (ed.showDialog().getValue() == 1) {
385 try {
386 openUrl(url);
387 } catch (IOException e) {
388 Main.warn(e);
389 }
390 }
391 }
392 }
393 });
394 }
395}
Note: See TracBrowser for help on using the repository browser.