src/share/classes/sun/awt/AppContext.java

Print this page




 154     /**
 155      * Returns a set containing all <code>AppContext</code>s.
 156      */
 157     public static Set<AppContext> getAppContexts() {
 158         synchronized (threadGroup2appContext) {
 159             return new HashSet<AppContext>(threadGroup2appContext.values());
 160         }
 161     }
 162 
 163     /* The main "system" AppContext, used by everything not otherwise
 164        contained in another AppContext.
 165      */
 166     private static volatile AppContext mainAppContext = null;
 167 
 168     /*
 169      * The hash map associated with this AppContext.  A private delegate
 170      * is used instead of subclassing HashMap so as to avoid all of
 171      * HashMap's potentially risky methods, such as clear(), elements(),
 172      * putAll(), etc.
 173      */
 174     private final HashMap table = new HashMap();
 175 
 176     private final ThreadGroup threadGroup;
 177 
 178     /**
 179      * If any <code>PropertyChangeListeners</code> have been registered,
 180      * the <code>changeSupport</code> field describes them.
 181      *
 182      * @see #addPropertyChangeListener
 183      * @see #removePropertyChangeListener
 184      * @see #firePropertyChange
 185      */
 186     private PropertyChangeSupport changeSupport = null;
 187 
 188     public static final String DISPOSED_PROPERTY_NAME = "disposed";
 189     public static final String GUI_DISPOSED = "guidisposed";
 190 
 191     private volatile boolean isDisposed = false; // true if AppContext is disposed
 192 
 193     public boolean isDisposed() {
 194         return isDisposed;
 195     }
 196 
 197     static {
 198         // On the main Thread, we get the ThreadGroup, make a corresponding
 199         // AppContext, and instantiate the Java EventQueue.  This way, legacy
 200         // code is unaffected by the move to multiple AppContext ability.
 201         AccessController.doPrivileged(new PrivilegedAction() {
 202             public Object run() {
 203                 ThreadGroup currentThreadGroup =
 204                         Thread.currentThread().getThreadGroup();
 205                 ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
 206                 while (parentThreadGroup != null) {
 207                     // Find the root ThreadGroup to construct our main AppContext
 208                     currentThreadGroup = parentThreadGroup;
 209                     parentThreadGroup = currentThreadGroup.getParent();
 210                 }
 211                 mainAppContext = new AppContext(currentThreadGroup);
 212                 numAppContexts = 1;
 213                 return mainAppContext;
 214             }
 215         });
 216     }
 217 
 218     /*
 219      * The total number of AppContexts, system-wide.  This number is
 220      * incremented at the beginning of the constructor, and decremented
 221      * at the end of dispose().  getAppContext() checks to see if this
 222      * number is 1.  If so, it returns the sole AppContext without
 223      * checking Thread.currentThread().
 224      */
 225     private static volatile int numAppContexts;
 226 
 227     /*
 228      * The context ClassLoader that was used to create this AppContext.
 229      */
 230     private final ClassLoader contextClassLoader;
 231 
 232     /**
 233      * Constructor for AppContext.  This method is <i>not</i> public,


 382         final PropertyChangeSupport changeSupport = this.changeSupport;
 383         if (changeSupport != null) {
 384             changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);
 385         }
 386 
 387         // First, we post an InvocationEvent to be run on the
 388         // EventDispatchThread which disposes of all top-level Frames and TrayIcons
 389 
 390         final Object notificationLock = new Object();
 391 
 392         Runnable runnable = new Runnable() {
 393             public void run() {
 394                 Window[] windowsToDispose = Window.getOwnerlessWindows();
 395                 for (Window w : windowsToDispose) {
 396                     try {
 397                         w.dispose();
 398                     } catch (Throwable t) {
 399                         log.finer("exception occured while disposing app context", t);
 400                     }
 401                 }
 402                 AccessController.doPrivileged(new PrivilegedAction() {
 403                         public Object run() {
 404                             if (!GraphicsEnvironment.isHeadless() && SystemTray.isSupported())
 405                             {
 406                                 SystemTray systemTray = SystemTray.getSystemTray();
 407                                 TrayIcon[] trayIconsToDispose = systemTray.getTrayIcons();
 408                                 for (TrayIcon ti : trayIconsToDispose) {
 409                                     systemTray.remove(ti);
 410                                 }
 411                             }
 412                             return null;
 413                         }
 414                     });
 415                 // Alert PropertyChangeListeners that the GUI has been disposed.
 416                 if (changeSupport != null) {
 417                     changeSupport.firePropertyChange(GUI_DISPOSED, false, true);
 418                 }
 419                 synchronized(notificationLock) {
 420                     notificationLock.notifyAll(); // Notify caller that we're done
 421                 }
 422             }
 423         };


 506         numAppContexts--;
 507 
 508         mostRecentKeyValue = null;
 509     }
 510 
 511     static final class PostShutdownEventRunnable implements Runnable {
 512         private final AppContext appContext;
 513 
 514         public PostShutdownEventRunnable(AppContext ac) {
 515             appContext = ac;
 516         }
 517 
 518         public void run() {
 519             final EventQueue eq = (EventQueue)appContext.get(EVENT_QUEUE_KEY);
 520             if (eq != null) {
 521                 eq.postEvent(AWTAutoShutdown.getShutdownEvent());
 522             }
 523         }
 524     }
 525 
 526     static final class CreateThreadAction implements PrivilegedAction {
 527         private final AppContext appContext;
 528         private final Runnable runnable;
 529 
 530         public CreateThreadAction(AppContext ac, Runnable r) {
 531             appContext = ac;
 532             runnable = r;
 533         }
 534 
 535         public Object run() {
 536             Thread t = new Thread(appContext.getThreadGroup(), runnable);
 537             t.setContextClassLoader(appContext.getContextClassLoader());
 538             t.setPriority(Thread.NORM_PRIORITY + 1);
 539             t.setDaemon(true);
 540             return t;
 541         }
 542     }
 543 
 544     static void stopEventDispatchThreads() {
 545         for (AppContext appContext: getAppContexts()) {
 546             if (appContext.isDisposed()) {
 547                 continue;
 548             }
 549             Runnable r = new PostShutdownEventRunnable(appContext);
 550             // For security reasons EventQueue.postEvent should only be called
 551             // on a thread that belongs to the corresponding thread group.
 552             if (appContext != AppContext.getAppContext()) {
 553                 // Create a thread that belongs to the thread group associated
 554                 // with the AppContext and invokes EventQueue.postEvent.
 555                 PrivilegedAction action = new CreateThreadAction(appContext, r);
 556                 Thread thread = (Thread)AccessController.doPrivileged(action);
 557                 thread.start();
 558             } else {
 559                 r.run();
 560             }
 561         }
 562     }
 563 
 564     private MostRecentKeyValue mostRecentKeyValue = null;
 565     private MostRecentKeyValue shadowMostRecentKeyValue = null;
 566 
 567     /**
 568      * Returns the value to which the specified key is mapped in this context.
 569      *
 570      * @param   key   a key in the AppContext.
 571      * @return  the value to which the key is mapped in this AppContext;
 572      *          <code>null</code> if the key is not mapped to any value.
 573      * @see     #put(Object, Object)
 574      * @since   1.2
 575      */
 576     public Object get(Object key) {




 154     /**
 155      * Returns a set containing all <code>AppContext</code>s.
 156      */
 157     public static Set<AppContext> getAppContexts() {
 158         synchronized (threadGroup2appContext) {
 159             return new HashSet<AppContext>(threadGroup2appContext.values());
 160         }
 161     }
 162 
 163     /* The main "system" AppContext, used by everything not otherwise
 164        contained in another AppContext.
 165      */
 166     private static volatile AppContext mainAppContext = null;
 167 
 168     /*
 169      * The hash map associated with this AppContext.  A private delegate
 170      * is used instead of subclassing HashMap so as to avoid all of
 171      * HashMap's potentially risky methods, such as clear(), elements(),
 172      * putAll(), etc.
 173      */
 174     private final Map<Object, Object> table = new HashMap<>();
 175 
 176     private final ThreadGroup threadGroup;
 177 
 178     /**
 179      * If any <code>PropertyChangeListeners</code> have been registered,
 180      * the <code>changeSupport</code> field describes them.
 181      *
 182      * @see #addPropertyChangeListener
 183      * @see #removePropertyChangeListener
 184      * @see #firePropertyChange
 185      */
 186     private PropertyChangeSupport changeSupport = null;
 187 
 188     public static final String DISPOSED_PROPERTY_NAME = "disposed";
 189     public static final String GUI_DISPOSED = "guidisposed";
 190 
 191     private volatile boolean isDisposed = false; // true if AppContext is disposed
 192 
 193     public boolean isDisposed() {
 194         return isDisposed;
 195     }
 196 
 197     static {
 198         // On the main Thread, we get the ThreadGroup, make a corresponding
 199         // AppContext, and instantiate the Java EventQueue.  This way, legacy
 200         // code is unaffected by the move to multiple AppContext ability.
 201         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 202             public Void run() {
 203                 ThreadGroup currentThreadGroup =
 204                         Thread.currentThread().getThreadGroup();
 205                 ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
 206                 while (parentThreadGroup != null) {
 207                     // Find the root ThreadGroup to construct our main AppContext
 208                     currentThreadGroup = parentThreadGroup;
 209                     parentThreadGroup = currentThreadGroup.getParent();
 210                 }
 211                 mainAppContext = new AppContext(currentThreadGroup);
 212                 numAppContexts = 1;
 213                 return null;
 214             }
 215         });
 216     }
 217 
 218     /*
 219      * The total number of AppContexts, system-wide.  This number is
 220      * incremented at the beginning of the constructor, and decremented
 221      * at the end of dispose().  getAppContext() checks to see if this
 222      * number is 1.  If so, it returns the sole AppContext without
 223      * checking Thread.currentThread().
 224      */
 225     private static volatile int numAppContexts;
 226 
 227     /*
 228      * The context ClassLoader that was used to create this AppContext.
 229      */
 230     private final ClassLoader contextClassLoader;
 231 
 232     /**
 233      * Constructor for AppContext.  This method is <i>not</i> public,


 382         final PropertyChangeSupport changeSupport = this.changeSupport;
 383         if (changeSupport != null) {
 384             changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);
 385         }
 386 
 387         // First, we post an InvocationEvent to be run on the
 388         // EventDispatchThread which disposes of all top-level Frames and TrayIcons
 389 
 390         final Object notificationLock = new Object();
 391 
 392         Runnable runnable = new Runnable() {
 393             public void run() {
 394                 Window[] windowsToDispose = Window.getOwnerlessWindows();
 395                 for (Window w : windowsToDispose) {
 396                     try {
 397                         w.dispose();
 398                     } catch (Throwable t) {
 399                         log.finer("exception occured while disposing app context", t);
 400                     }
 401                 }
 402                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
 403                         public Void run() {
 404                             if (!GraphicsEnvironment.isHeadless() && SystemTray.isSupported())
 405                             {
 406                                 SystemTray systemTray = SystemTray.getSystemTray();
 407                                 TrayIcon[] trayIconsToDispose = systemTray.getTrayIcons();
 408                                 for (TrayIcon ti : trayIconsToDispose) {
 409                                     systemTray.remove(ti);
 410                                 }
 411                             }
 412                             return null;
 413                         }
 414                     });
 415                 // Alert PropertyChangeListeners that the GUI has been disposed.
 416                 if (changeSupport != null) {
 417                     changeSupport.firePropertyChange(GUI_DISPOSED, false, true);
 418                 }
 419                 synchronized(notificationLock) {
 420                     notificationLock.notifyAll(); // Notify caller that we're done
 421                 }
 422             }
 423         };


 506         numAppContexts--;
 507 
 508         mostRecentKeyValue = null;
 509     }
 510 
 511     static final class PostShutdownEventRunnable implements Runnable {
 512         private final AppContext appContext;
 513 
 514         public PostShutdownEventRunnable(AppContext ac) {
 515             appContext = ac;
 516         }
 517 
 518         public void run() {
 519             final EventQueue eq = (EventQueue)appContext.get(EVENT_QUEUE_KEY);
 520             if (eq != null) {
 521                 eq.postEvent(AWTAutoShutdown.getShutdownEvent());
 522             }
 523         }
 524     }
 525 
 526     static final class CreateThreadAction implements PrivilegedAction<Thread> {
 527         private final AppContext appContext;
 528         private final Runnable runnable;
 529 
 530         public CreateThreadAction(AppContext ac, Runnable r) {
 531             appContext = ac;
 532             runnable = r;
 533         }
 534 
 535         public Thread run() {
 536             Thread t = new Thread(appContext.getThreadGroup(), runnable);
 537             t.setContextClassLoader(appContext.getContextClassLoader());
 538             t.setPriority(Thread.NORM_PRIORITY + 1);
 539             t.setDaemon(true);
 540             return t;
 541         }
 542     }
 543 
 544     static void stopEventDispatchThreads() {
 545         for (AppContext appContext: getAppContexts()) {
 546             if (appContext.isDisposed()) {
 547                 continue;
 548             }
 549             Runnable r = new PostShutdownEventRunnable(appContext);
 550             // For security reasons EventQueue.postEvent should only be called
 551             // on a thread that belongs to the corresponding thread group.
 552             if (appContext != AppContext.getAppContext()) {
 553                 // Create a thread that belongs to the thread group associated
 554                 // with the AppContext and invokes EventQueue.postEvent.
 555                 PrivilegedAction<Thread> action = new CreateThreadAction(appContext, r);
 556                 Thread thread = AccessController.doPrivileged(action);
 557                 thread.start();
 558             } else {
 559                 r.run();
 560             }
 561         }
 562     }
 563 
 564     private MostRecentKeyValue mostRecentKeyValue = null;
 565     private MostRecentKeyValue shadowMostRecentKeyValue = null;
 566 
 567     /**
 568      * Returns the value to which the specified key is mapped in this context.
 569      *
 570      * @param   key   a key in the AppContext.
 571      * @return  the value to which the key is mapped in this AppContext;
 572      *          <code>null</code> if the key is not mapped to any value.
 573      * @see     #put(Object, Object)
 574      * @since   1.2
 575      */
 576     public Object get(Object key) {