fix for JDK-8019274 Java 7u25, 7u40, 6u51 RMI bug with SwingUtilities.invokeLater() and SwingUtilities.invokeAndWait()

uinerd uinerd at gmail.com
Wed Sep 25 12:48:47 PDT 2013


Here is the workaround, packaged in a utility class. (You'll need to
include the jnlp.jar in your project.)

Replace all your calls to invokeLater() and invokeAndWait() with
JreUtils.invokeNowOrLater() and JreUtils.invokeNowOrWait().

It's not a perfect solution, but if your web start app is offline because
of JDK-8019274, this should get it running again.

uinerd
Morrisville, NC


package com.uinerd;

import java.awt.Component;
import java.lang.reflect.Field;
import java.util.Map;

import javax.jnlp.BasicService;
import javax.jnlp.IntegrationService;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

import sun.awt.AppContext;

/**
 * Encapsulates the Java 7u25/7u40/6u51 hack
 */
public class JreUtils {
private static String badVersionInfo = null;
private static AppContext awtEventDispatchContext = null;
private static AppContext mainThreadContext = null;

private static Boolean isWebStart = null;
private static BasicService basicService = null;
private static IntegrationService integrationService = null;

/**
 * Call this early in main(). Do not call this using an invoke* method.
 */
public static void init() {
if (isWebstart() && isApplicableJvmType()) {
     String javaVersion = System.getProperty("java.version");

    if ("1.7.0_25".equals(javaVersion)) {
     badVersionInfo = "7u25";
    }
    else if ("1.7.0_40".equals(javaVersion)) {
     badVersionInfo = "7u40";
    }
    else if (javaVersion != null &&
"1.6.0_51".equals(javaVersion.substring(0,8))) {
     badVersionInfo = "6u51";
    }
    else if
("javaws-10.25.2.16".equals(System.getProperty("javawebstart.version"))) {
     badVersionInfo = "Web Start 10.25.2.16";
    }
}
    if (badVersionInfo != null) {
     mainThreadContext = AppContext.getAppContext();
     try {
SwingUtilities.invokeAndWait(new Runnable() {
    public void run() {
     awtEventDispatchContext = AppContext.getAppContext();
    }
});
     }
     catch (Exception e) {
     displayErrorAndExit(null);
     }

     if (mainThreadContext == null || awtEventDispatchContext == null) {
     displayErrorAndExit(null);
     }
    }
}
 public static void invokeNowOrLater(Runnable runnable) {
if (hasAppContextBug()) {
        invokeLaterOnAwtEventDispatchThreadContext(runnable);
}
else {
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
SwingUtilities.invokeLater(runnable);
}
}
}
 public static void invokeNowOrWait(Runnable runnable) {
if (hasAppContextBug()) {
        fixThreadAppContext(null);
}

if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
try {
SwingUtilities.invokeAndWait(runnable);
}
catch (Exception e) {
// handle it
}
}
}
 public static boolean hasAppContextBug() {
return isJreWithAppContextBug() && AppContext.getAppContext() == null;
}

public static void invokeLaterOnAwtEventDispatchThreadContext(Runnable
runnable) {
sun.awt.SunToolkit.invokeLaterOnAppContext(JreUtils.awtEventDispatchContext,
runnable);
}

        // this is the important part
public static void fixThreadAppContext(Component parent) {
        try {
            final Field field =
AppContext.class.getDeclaredField("threadGroup2appContext");
            field.setAccessible(true);
            Map<ThreadGroup, AppContext> threadGroup2appContext =
(Map<ThreadGroup, AppContext>)field.get(null);
    final ThreadGroup currentThreadGroup =
Thread.currentThread().getThreadGroup();
        threadGroup2appContext.put(currentThreadGroup,
JreUtils.mainThreadContext);
    }
    catch (Exception e) {
displayErrorAndExit(parent);
    }

if (AppContext.getAppContext() == null) {
displayErrorAndExit(parent);
}
}
 private static boolean isJreWithAppContextBug() {
return badVersionInfo != null;
}
 private static void displayErrorAndExit(Component parent) {
        JLabel msgLabel = new JLabel("<html>" +
"Application cannot run using Web Start with this version of Java.<p><p>" +
    "Java " + badVersionInfo + " contains a bug acknowledged by Oracle
(JDK-8019274).")
JOptionPane.showMessageDialog(parent, msgLabel, "Java Version Error",
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}

private static boolean isApplicableJvmType() {
String vendor = System.getProperty("java.vendor");
String vmName = System.getProperty("java.vm.name");
if (vendor != null && vmName != null) {
return vmName.contains("Java HotSpot") &&
   (vendor.equals("Oracle Corporation") ||
    vendor.equals("Sun Microsystems Inc."));
}
 return false;
}

    private static boolean isWebstart() {
if (isWebStart == null) {
try {
basicService = (BasicService)
ServiceManager.lookup("javax.jnlp.BasicService");
isWebStart = true;
}
            catch (UnavailableServiceException e) {
isWebStart = false;
}
 try {
integrationService = (IntegrationService)
ServiceManager.lookup("javax.jnlp.IntegrationService");
}
            catch (UnavailableServiceException e) {
           }
}
return isWebStart;
}
}



More information about the jdk7u-dev mailing list