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, 5 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.