package com.onaro.sanscreen.client.jmxframework.service; import java.lang.reflect.Field; import java.util.Map; import javax.swing.SwingUtilities; import com.onaro.sanscreen.client.MainDirector; import com.onaro.sanscreen.client.jmxframework.FrameworkService; /** * MBean Shutdown service class. * Exposes functionality to shutdown the Client. Mainly used by UT. * * @author Rick Noel * */ @SuppressWarnings("nls") public class ShutdownService extends FrameworkService implements ShutdownServiceMBean { /** * Name of service. Used to look up service via JNDI */ public static final String NAME = "Shutdown Service"; // Using sun.awt.AppContext to work around Oracle bug in Java 7 only. @SuppressWarnings("restriction") private static sun.awt.AppContext mainThreadContext = null; public ShutdownService() { super(NAME); } @SuppressWarnings("restriction") @Override public void doStart() { // Using sun.awt.AppContext to work around Oracle bug in Java 7 only. if (mainThreadContext == null && System.getProperty("java.version").startsWith("1.7.")) { mainThreadContext = sun.awt.AppContext.getAppContext(); } } @Override public void doStop() { } @Override public String getStatus() { return "Running"; } /** * Main method of the service callable from JMX. Shuts down the client. */ @Override public void shutdown() { // Special shutdown required when running on Java 7 VM. if (mainThreadContext != null) { shutdown_java7(); } else { MainDirector.getMainDirector().exit(false); } } /** * Shuts down client when client is running on a Java 7 VM. *

* There is a bug introduced by Oracle in Java 7u25 that causes a null pointer exception * when the test tries to close the application. The NPE occurs within the Sun AWT Toolkit. * See Sun bug 8017776. * Unfortunately, this will not be fixed until Java 8. *

* Below is a workaround based on info discovered from various sources. * Note we don't support Java 7 prior to update 25, so we use this workaround for all Java 7 VMs. */ @SuppressWarnings({"unchecked", "restriction"}) private void shutdown_java7() { try { // Change context to that used by MainDirector class (Swing thread). final Field field = sun.awt.AppContext.class.getDeclaredField ("threadGroup2appContext"); //$NON-NLS-1$ field.setAccessible(true); Map threadGroup2appContext = (Map)field.get (null); final ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup(); threadGroup2appContext.put (currentThreadGroup, mainThreadContext); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { try { // Shutdown. MainDirector.getMainDirector().exit(false); } catch (Exception e) { e.printStackTrace(); } } }); } catch (Exception e) { e.printStackTrace(); } } }