Changeset 18985 in josm


Ignore:
Timestamp:
2024-02-14T18:11:54+01:00 (9 months ago)
Author:
taylor.smock
Message:

Fix #23355: Sanity check JVM arguments on startup

See #17858: JOSM will no longer continue running if the user is on an unsupported
Java version (for this commit, older than Java 11; message indicates Java 17).
This does update the link for Azul from Java 17 to Java 21 as well.

In order to (hopefully) reduce confusion, the webstart and Java update nags will
also be reset in the event that JOSM will exit due to old Java versions. This is
mostly so that users will get the messages to update to OpenWebstart or the
appropriate Java link for their platform and architecture.

Additionally, this will (hopefully) reduce the number of tickets we have to close
due to missing JVM arguments by informing users of the missing arguments at startup.

Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/build.xml

    r18974 r18985  
    7777        <property name="dist-optimized.jar" location="${dist.dir}/josm-custom-optimized.jar"/>
    7878        <property name="dist-sources.jar" location="${dist.dir}/josm-custom-sources.jar"/>
     79        <!-- When incrementing the minimum Java version, don't forget to update the Java versions users will update to
     80             (PlatformHook#getJavaUrl, PlatformHook#startupSanityChecks and PlatformHook#warnSoonToBeUnsupportedJava) -->
    7981        <property name="java.lang.version" value="8" />
    8082        <property name="test.headless" value="true" />
     
    300302        <!-- Java 17 specific files (2021-09 LTS) -->
    301303        <call-javac-compile-mrjar release="17"/>
    302         <!-- Java 18 specific files -->
    303         <call-javac-compile-mrjar release="18"/>
    304         <!-- Java 19 specific files -->
    305         <call-javac-compile-mrjar release="19"/>
    306         <!-- Java 20 specific files -->
    307         <call-javac-compile-mrjar release="20"/>
    308304        <!-- Java 21 specific files (2023-09 LTS) -->
    309305        <call-javac-compile-mrjar release="21"/>
  • trunk/native/linux/latest/DEBIAN/control

    r18889 r18985  
    66Priority: extra
    77Architecture: all
    8 Depends: default-jre (>= 2:1.17) | java8-runtime,
     8Depends: default-jre (>= 2:1.17) | java11-runtime,
    99         proj-data, fonts-noto, openjfx
    1010Description: Editor for OpenStreetMap (daily development snapshot)
  • trunk/native/linux/tested/DEBIAN/control

    r18889 r18985  
    66Priority: extra
    77Architecture: all
    8 Depends: default-jre (>= 2:1.17) | java8-runtime,
     8Depends: default-jre (>= 2:1.17) | java11-runtime,
    99         proj-data, fonts-noto, openjfx
    1010Conflicts: josm-plugins
  • trunk/src/org/openstreetmap/josm/gui/MainApplication.java

    r18801 r18985  
    5858import javax.swing.JOptionPane;
    5959import javax.swing.JPanel;
     60import javax.swing.JTextPane;
    6061import javax.swing.KeyStroke;
    6162import javax.swing.LookAndFeel;
     
    130131import org.openstreetmap.josm.gui.util.RedirectInputMap;
    131132import org.openstreetmap.josm.gui.util.WindowGeometry;
     133import org.openstreetmap.josm.gui.widgets.TextContextualPopupMenu;
    132134import org.openstreetmap.josm.gui.widgets.UrlLabel;
    133135import org.openstreetmap.josm.io.CachedFile;
     
    404406        askUpdate(tr("Outdated Java WebStart version"), tr("Update to OpenWebStart"), "askUpdateWebStart", /* ICON */"presets/transport/rocket", content, url);
    405407        // CHECKSTYLE.ON: LineLength
     408    }
     409
     410    /**
     411     * Tells the user that a sanity check failed
     412     * @param title The title of the message to show
     413     * @param canContinue {@code true} if the failed sanity check(s) will not instantly kill JOSM when the user edits
     414     * @param message The message parts to show the user (as a list)
     415     */
     416    public static void sanityCheckFailed(String title, boolean canContinue, String... message) {
     417        final ExtendedDialog ed;
     418        if (canContinue) {
     419            ed = new ExtendedDialog(mainFrame, title, tr("Stop"), tr("Continue"));
     420            ed.setButtonIcons("cancel", "ok");
     421        } else {
     422            ed = new ExtendedDialog(mainFrame, title, tr("Stop"));
     423            ed.setButtonIcons("cancel");
     424        }
     425        ed.setDefaultButton(1).setCancelButton(1);
     426        // Check if the dialog has not already been permanently hidden by user
     427        if (!ed.toggleEnable("sanityCheckFailed").toggleCheckState() || !canContinue) {
     428            final String content = Arrays.stream(message).collect(Collectors.joining("</li><li>",
     429                    "<html><body><ul><li>", "</li></ul></body></html>"));
     430            final JTextPane textField = new JTextPane();
     431            textField.setContentType("text/html");
     432            textField.setText(content);
     433            TextContextualPopupMenu.enableMenuFor(textField, true);
     434            ed.setMinimumSize(new Dimension(480, 300));
     435            ed.setIcon(JOptionPane.WARNING_MESSAGE);
     436            ed.setContent(textField);
     437            ed.showDialog();
     438        }
     439        if (!canContinue || ed.getValue() <= 1) { // 0 == cancel (we want to stop) and 1 == stop
     440            Lifecycle.exitJosm(true, -1);
     441        }
    406442    }
    407443
  • trunk/src/org/openstreetmap/josm/gui/MainInitialization.java

    r17679 r18985  
    7272            new InitializationTask(tr("Starting file watcher"), FileWatcher.getDefaultInstance()::start),
    7373            new InitializationTask(tr("Executing platform startup hook"),
    74                     () -> PlatformManager.getPlatform().startupHook(MainApplication::askUpdateJava, MainApplication::askMigrateWebStart)),
     74                    () -> PlatformManager.getPlatform().startupHook(MainApplication::askUpdateJava,
     75                            MainApplication::askMigrateWebStart, MainApplication::sanityCheckFailed)),
    7576            new InitializationTask(tr("Building main menu"), application::initializeMainWindow),
    7677            new InitializationTask(tr("Updating user interface"), () -> {
  • trunk/src/org/openstreetmap/josm/tools/PlatformHook.java

    r18790 r18985  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.tools;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
    35
    46import java.awt.GraphicsEnvironment;
     
    911import java.io.IOException;
    1012import java.io.InputStreamReader;
     13import java.lang.management.ManagementFactory;
    1114import java.nio.charset.StandardCharsets;
    1215import java.security.KeyStoreException;
     
    1518import java.security.cert.X509Certificate;
    1619import java.text.DateFormat;
     20import java.util.ArrayList;
    1721import java.util.Collection;
    1822import java.util.Collections;
     
    8791      * @param javaCallback Java expiration callback, providing GUI feedback
    8892      * @param webStartCallback WebStart migration callback, providing GUI feedback
    89       * @since 17679 (signature)
     93      * @since 18985
    9094      */
    91     default void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback) {
    92         // Do nothing
     95    default void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback,
     96            SanityCheckCallback sanityCheckCallback) {
     97        startupSanityChecks(sanityCheckCallback);
    9398    }
    9499
     
    288293
    289294    /**
     295     * Inform the user that a sanity check or checks failed
     296     */
     297    @FunctionalInterface
     298    interface SanityCheckCallback {
     299        /**
     300         * Tells the user that a sanity check failed
     301         * @param title The title of the message to show
     302         * @param canContinue {@code true} if the failed sanity check(s) will not instantly kill JOSM when the user edits
     303         * @param message The message parts to show the user (as a list)
     304         */
     305        void sanityCheckFailed(String title, boolean canContinue, String... message);
     306    }
     307
     308    /**
    290309     * Checks if the running version of Java has expired, proposes to user to update it if needed.
    291310     * @param callback Java expiration callback
     
    332351     */
    333352    default String getJavaUrl() {
    334         StringBuilder defaultDownloadUrl = new StringBuilder("https://www.azul.com/downloads/?version=java-17-lts");
     353        StringBuilder defaultDownloadUrl = new StringBuilder("https://www.azul.com/downloads/?version=java-21-lts");
    335354        if (PlatformManager.isPlatformWindows()) {
    336355            defaultDownloadUrl.append("&os=windows");
     
    370389    }
    371390
     391    default void startupSanityChecks(SanityCheckCallback sanityCheckCallback) {
     392        final String arch = System.getProperty("os.arch");
     393        final List<String> messages = new ArrayList<>();
     394        final String jvmArch = System.getProperty("sun.arch.data.model");
     395        boolean canContinue = true;
     396        if (Utils.getJavaVersion() < 11) {
     397            canContinue = false;
     398            messages.add(tr("You must update Java to Java {0} or later in order to run this version of JOSM", 17));
     399            // Reset webstart/java update prompts
     400            Config.getPref().put("askUpdateWebStart", null);
     401            Config.getPref().put("askUpdateJava" + Utils.getJavaLatestVersion(), null);
     402            Config.getPref().put("askUpdateJavalatest", null);
     403        }
     404        if (!"x86".equals(arch) && "32".equals(jvmArch)) {
     405            messages.add(tr("Please use a 64 bit version of Java -- this will avoid out of memory errors"));
     406        }
     407        // Note: these might be able to be removed with the appropriate module-info.java settings.
     408        final String[] expectedJvmArguments = {
     409                "--add-exports=java.base/sun.security.action=ALL-UNNAMED",
     410                "--add-exports=java.desktop/com.sun.imageio.plugins.jpeg=ALL-UNNAMED",
     411                "--add-exports=java.desktop/com.sun.imageio.spi=ALL-UNNAMED"
     412        };
     413        final List<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
     414        final StringBuilder missingArguments = new StringBuilder();
     415        for (String arg : expectedJvmArguments) {
     416            if (!vmArguments.contains(arg)) {
     417                if (missingArguments.length() > 0) {
     418                    missingArguments.append("<br>");
     419                }
     420                missingArguments.append(arg);
     421            }
     422        }
     423        if (missingArguments.length() > 0) {
     424            final String args = missingArguments.toString();
     425            messages.add(tr("Missing JVM Arguments:<br>{0}", args));
     426        }
     427        if (!messages.isEmpty()) {
     428            if (canContinue) {
     429                sanityCheckCallback.sanityCheckFailed(tr("JOSM may work improperly"), true,
     430                        messages.toArray(new String[0]));
     431            } else {
     432                sanityCheckCallback.sanityCheckFailed(tr("JOSM will be unable to work properly and will exit"), false,
     433                        messages.toArray(new String[0]));
     434            }
     435        }
     436    }
     437
    372438    /**
    373439     * Called when interfacing with native OS functions. Currently only used with macOS.
  • trunk/src/org/openstreetmap/josm/tools/PlatformHookOsx.java

    r18771 r18985  
    6969
    7070    @Override
    71     public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback) {
     71    public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback,
     72            SanityCheckCallback sanityCheckCallback) {
    7273        // Here we register callbacks for the menu entries in the system menu and file opening through double-click
    7374        // https://openjdk.java.net/jeps/272
     
    107108        checkExpiredJava(javaCallback);
    108109        checkWebStartMigration(webStartCallback);
     110        PlatformHook.super.startupHook(javaCallback, webStartCallback, sanityCheckCallback);
    109111    }
    110112
  • trunk/src/org/openstreetmap/josm/tools/PlatformHookUnixoid.java

    r18580 r18985  
    6464
    6565    @Override
    66     public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback) {
     66    public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback,
     67            SanityCheckCallback sanityCheckCallback) {
    6768        checkWebStartMigration(webStartCallback);
     69        PlatformHook.super.startupHook(javaCallback, webStartCallback, sanityCheckCallback);
    6870    }
    6971
  • trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java

    r18801 r18985  
    154154
    155155    @Override
    156     public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback) {
     156    public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback,
     157            SanityCheckCallback sanityCheckCallback) {
    157158        warnSoonToBeUnsupportedJava(javaCallback);
    158159        checkExpiredJava(javaCallback);
    159160        checkWebStartMigration(webStartCallback);
     161        PlatformHook.super.startupHook(javaCallback, webStartCallback, sanityCheckCallback);
    160162    }
    161163
  • trunk/test/unit/org/openstreetmap/josm/tools/PlatformHookOsxTest.java

    r18853 r18985  
    3535    @Test
    3636    void testStartupHook() {
    37         hook.startupHook((a, b, c, d) -> System.out.println("java callback"), u -> System.out.println("webstart callback"));
     37        hook.startupHook((a, b, c, d) -> System.out.println("java callback"), u -> System.out.println("webstart callback"),
     38                (a, b, c) -> System.out.println("sanity check callback"));
    3839    }
    3940
  • trunk/test/unit/org/openstreetmap/josm/tools/PlatformHookWindowsTest.java

    r18893 r18985  
    4747        final PlatformHook.JavaExpirationCallback javaCallback = (a, b, c, d) -> System.out.println("java callback");
    4848        final PlatformHook.WebStartMigrationCallback webstartCallback = u -> System.out.println("webstart callback");
    49         assertDoesNotThrow(() -> hook.startupHook(javaCallback, webstartCallback));
     49        final PlatformHook.SanityCheckCallback sanityCheckCallback = (a, b, c) -> System.out.println("sanity check callback");
     50        assertDoesNotThrow(() -> hook.startupHook(javaCallback, webstartCallback, sanityCheckCallback));
    5051    }
    5152
Note: See TracChangeset for help on using the changeset viewer.