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

Print this page




  29 import java.awt.Window;
  30 import java.awt.SystemTray;
  31 import java.awt.TrayIcon;
  32 import java.awt.Toolkit;
  33 import java.awt.GraphicsEnvironment;
  34 import java.awt.event.InvocationEvent;
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 import java.util.Collections;
  38 import java.util.HashMap;
  39 import java.util.IdentityHashMap;
  40 import java.util.Map;
  41 import java.util.Set;
  42 import java.util.HashSet;
  43 import java.beans.PropertyChangeSupport;
  44 import java.beans.PropertyChangeListener;
  45 import sun.util.logging.PlatformLogger;
  46 import java.util.concurrent.locks.Condition;
  47 import java.util.concurrent.locks.Lock;
  48 import java.util.concurrent.locks.ReentrantLock;

  49 
  50 /**
  51  * The AppContext is a table referenced by ThreadGroup which stores
  52  * application service instances.  (If you are not writing an application
  53  * service, or don't know what one is, please do not use this class.)
  54  * The AppContext allows applet access to what would otherwise be
  55  * potentially dangerous services, such as the ability to peek at
  56  * EventQueues or change the look-and-feel of a Swing application.<p>
  57  *
  58  * Most application services use a singleton object to provide their
  59  * services, either as a default (such as getSystemEventQueue or
  60  * getDefaultToolkit) or as static methods with class data (System).
  61  * The AppContext works with the former method by extending the concept
  62  * of "default" to be ThreadGroup-specific.  Application services
  63  * lookup their singleton in the AppContext.<p>
  64  *
  65  * For example, here we have a Foo service, with its pre-AppContext
  66  * code:<p>
  67  * <code><pre>
  68  *    public class Foo {


 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,
 234      * nor should it ever be used as such.  The proper way to construct
 235      * an AppContext is through the use of SunToolkit.createNewAppContext.
 236      * A ThreadGroup is created for the new AppContext, a Thread is
 237      * created within that ThreadGroup, and that Thread calls
 238      * SunToolkit.createNewAppContext before calling anything else.
 239      * That creates both the new AppContext and its EventQueue.
 240      *
 241      * @param   threadGroup     The ThreadGroup for the new AppContext
 242      * @see     sun.awt.SunToolkit
 243      * @since   1.2
 244      */
 245     AppContext(ThreadGroup threadGroup) {
 246         numAppContexts++;
 247 
 248         this.threadGroup = threadGroup;
 249         threadGroup2appContext.put(threadGroup, this);
 250 
 251         this.contextClassLoader =
 252              AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
 253                     public ClassLoader run() {
 254                         return Thread.currentThread().getContextClassLoader();
 255                     }
 256                 });
 257 
 258         // Initialize push/pop lock and its condition to be used by all the
 259         // EventQueues within this AppContext
 260         Lock eventQueuePushPopLock = new ReentrantLock();
 261         put(EVENT_QUEUE_LOCK_KEY, eventQueuePushPopLock);
 262         Condition eventQueuePushPopCond = eventQueuePushPopLock.newCondition();
 263         put(EVENT_QUEUE_COND_KEY, eventQueuePushPopCond);
 264     }
 265 
 266     private static final ThreadLocal<AppContext> threadAppContext =
 267             new ThreadLocal<AppContext>();
 268 
 269     /**
 270      * Returns the appropriate AppContext for the caller,
 271      * as determined by its ThreadGroup.  If the main "system" AppContext
 272      * would be returned and there's an AWTSecurityManager installed, it
 273      * is called to get the proper AppContext based on the execution
 274      * context.
 275      *
 276      * @return  the AppContext for the caller.
 277      * @see     java.lang.ThreadGroup
 278      * @since   1.2
 279      */
 280     public final static AppContext getAppContext() {
 281         if (numAppContexts == 1)   // If there's only one system-wide,
 282             return mainAppContext; // return the main system AppContext.
 283 
 284         AppContext appContext = threadAppContext.get();
 285 
 286         if (null == appContext) {
 287             appContext = AccessController.doPrivileged(new PrivilegedAction<AppContext>()
 288             {
 289                 public AppContext run() {
 290                     // Get the current ThreadGroup, and look for it and its
 291                     // parents in the hash from ThreadGroup to AppContext --
 292                     // it should be found, because we use createNewContext()
 293                     // when new AppContext objects are created.
 294                     ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
 295                     ThreadGroup threadGroup = currentThreadGroup;
 296                     AppContext context = threadGroup2appContext.get(threadGroup);
 297                     while (context == null) {
 298                         threadGroup = threadGroup.getParent();
 299                         if (threadGroup == null) {
 300                             // If we get here, we're running under a ThreadGroup that
 301                             // has no AppContext associated with it.  This should never


 486             numSubGroups = this.threadGroup.enumerate(subGroups);
 487             for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
 488                 threadGroup2appContext.remove(subGroups[subGroup]);
 489             }
 490         }
 491         threadGroup2appContext.remove(this.threadGroup);
 492 
 493         threadAppContext.set(null);
 494 
 495         // Finally, we destroy the ThreadGroup entirely.
 496         try {
 497             this.threadGroup.destroy();
 498         } catch (IllegalThreadStateException e) {
 499             // Fired if not all the Threads died, ignore it and proceed
 500         }
 501 
 502         synchronized (table) {
 503             this.table.clear(); // Clear out the Hashtable to ease garbage collection
 504         }
 505 
 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 {




  29 import java.awt.Window;
  30 import java.awt.SystemTray;
  31 import java.awt.TrayIcon;
  32 import java.awt.Toolkit;
  33 import java.awt.GraphicsEnvironment;
  34 import java.awt.event.InvocationEvent;
  35 import java.security.AccessController;
  36 import java.security.PrivilegedAction;
  37 import java.util.Collections;
  38 import java.util.HashMap;
  39 import java.util.IdentityHashMap;
  40 import java.util.Map;
  41 import java.util.Set;
  42 import java.util.HashSet;
  43 import java.beans.PropertyChangeSupport;
  44 import java.beans.PropertyChangeListener;
  45 import sun.util.logging.PlatformLogger;
  46 import java.util.concurrent.locks.Condition;
  47 import java.util.concurrent.locks.Lock;
  48 import java.util.concurrent.locks.ReentrantLock;
  49 import java.util.concurrent.atomic.AtomicInteger;
  50 
  51 /**
  52  * The AppContext is a table referenced by ThreadGroup which stores
  53  * application service instances.  (If you are not writing an application
  54  * service, or don't know what one is, please do not use this class.)
  55  * The AppContext allows applet access to what would otherwise be
  56  * potentially dangerous services, such as the ability to peek at
  57  * EventQueues or change the look-and-feel of a Swing application.<p>
  58  *
  59  * Most application services use a singleton object to provide their
  60  * services, either as a default (such as getSystemEventQueue or
  61  * getDefaultToolkit) or as static methods with class data (System).
  62  * The AppContext works with the former method by extending the concept
  63  * of "default" to be ThreadGroup-specific.  Application services
  64  * lookup their singleton in the AppContext.<p>
  65  *
  66  * For example, here we have a Foo service, with its pre-AppContext
  67  * code:<p>
  68  * <code><pre>
  69  *    public class Foo {


 179     /**
 180      * If any <code>PropertyChangeListeners</code> have been registered,
 181      * the <code>changeSupport</code> field describes them.
 182      *
 183      * @see #addPropertyChangeListener
 184      * @see #removePropertyChangeListener
 185      * @see #firePropertyChange
 186      */
 187     private PropertyChangeSupport changeSupport = null;
 188 
 189     public static final String DISPOSED_PROPERTY_NAME = "disposed";
 190     public static final String GUI_DISPOSED = "guidisposed";
 191 
 192     private volatile boolean isDisposed = false; // true if AppContext is disposed
 193 
 194     public boolean isDisposed() {
 195         return isDisposed;
 196     }
 197 
 198     static {
 199                 numAppContexts = new AtomicInteger(1);
 200                         
 201         // On the main Thread, we get the ThreadGroup, make a corresponding
 202         // AppContext, and instantiate the Java EventQueue.  This way, legacy
 203         // code is unaffected by the move to multiple AppContext ability.
 204         AccessController.doPrivileged(new PrivilegedAction() {
 205             public Object run() {
 206                 ThreadGroup currentThreadGroup =
 207                         Thread.currentThread().getThreadGroup();
 208                 ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
 209                 while (parentThreadGroup != null) {
 210                     // Find the root ThreadGroup to construct our main AppContext
 211                     currentThreadGroup = parentThreadGroup;
 212                     parentThreadGroup = currentThreadGroup.getParent();
 213                 }
 214                 mainAppContext = new AppContext(currentThreadGroup);

 215                 return mainAppContext;
 216             }
 217         });
 218     }
 219 
 220     /*
 221      * The total number of AppContexts, system-wide.  This number is
 222      * incremented at the beginning of the constructor, and decremented
 223      * at the end of dispose().  getAppContext() checks to see if this
 224      * number is 1.  If so, it returns the sole AppContext without
 225      * checking Thread.currentThread().
 226      */
 227     private static final AtomicInteger numAppContexts;
 228 
 229     /*
 230      * The context ClassLoader that was used to create this AppContext.
 231      */
 232     private final ClassLoader contextClassLoader;
 233 
 234     /**
 235      * Constructor for AppContext.  This method is <i>not</i> public,
 236      * nor should it ever be used as such.  The proper way to construct
 237      * an AppContext is through the use of SunToolkit.createNewAppContext.
 238      * A ThreadGroup is created for the new AppContext, a Thread is
 239      * created within that ThreadGroup, and that Thread calls
 240      * SunToolkit.createNewAppContext before calling anything else.
 241      * That creates both the new AppContext and its EventQueue.
 242      *
 243      * @param   threadGroup     The ThreadGroup for the new AppContext
 244      * @see     sun.awt.SunToolkit
 245      * @since   1.2
 246      */
 247     AppContext(ThreadGroup threadGroup) {
 248         numAppContexts.incrementAndGet();
 249 
 250         this.threadGroup = threadGroup;
 251         threadGroup2appContext.put(threadGroup, this);
 252 
 253         this.contextClassLoader =
 254              AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
 255                     public ClassLoader run() {
 256                         return Thread.currentThread().getContextClassLoader();
 257                     }
 258                 });
 259 
 260         // Initialize push/pop lock and its condition to be used by all the
 261         // EventQueues within this AppContext
 262         Lock eventQueuePushPopLock = new ReentrantLock();
 263         put(EVENT_QUEUE_LOCK_KEY, eventQueuePushPopLock);
 264         Condition eventQueuePushPopCond = eventQueuePushPopLock.newCondition();
 265         put(EVENT_QUEUE_COND_KEY, eventQueuePushPopCond);
 266     }
 267 
 268     private static final ThreadLocal<AppContext> threadAppContext =
 269             new ThreadLocal<AppContext>();
 270 
 271     /**
 272      * Returns the appropriate AppContext for the caller,
 273      * as determined by its ThreadGroup.  If the main "system" AppContext
 274      * would be returned and there's an AWTSecurityManager installed, it
 275      * is called to get the proper AppContext based on the execution
 276      * context.
 277      *
 278      * @return  the AppContext for the caller.
 279      * @see     java.lang.ThreadGroup
 280      * @since   1.2
 281      */
 282     public final static AppContext getAppContext() {
 283         if (numAppContexts.get() == 1)   // If there's only one system-wide,
 284             return mainAppContext; // return the main system AppContext.
 285 
 286         AppContext appContext = threadAppContext.get();
 287 
 288         if (null == appContext) {
 289             appContext = AccessController.doPrivileged(new PrivilegedAction<AppContext>()
 290             {
 291                 public AppContext run() {
 292                     // Get the current ThreadGroup, and look for it and its
 293                     // parents in the hash from ThreadGroup to AppContext --
 294                     // it should be found, because we use createNewContext()
 295                     // when new AppContext objects are created.
 296                     ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
 297                     ThreadGroup threadGroup = currentThreadGroup;
 298                     AppContext context = threadGroup2appContext.get(threadGroup);
 299                     while (context == null) {
 300                         threadGroup = threadGroup.getParent();
 301                         if (threadGroup == null) {
 302                             // If we get here, we're running under a ThreadGroup that
 303                             // has no AppContext associated with it.  This should never


 488             numSubGroups = this.threadGroup.enumerate(subGroups);
 489             for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
 490                 threadGroup2appContext.remove(subGroups[subGroup]);
 491             }
 492         }
 493         threadGroup2appContext.remove(this.threadGroup);
 494 
 495         threadAppContext.set(null);
 496 
 497         // Finally, we destroy the ThreadGroup entirely.
 498         try {
 499             this.threadGroup.destroy();
 500         } catch (IllegalThreadStateException e) {
 501             // Fired if not all the Threads died, ignore it and proceed
 502         }
 503 
 504         synchronized (table) {
 505             this.table.clear(); // Clear out the Hashtable to ease garbage collection
 506         }
 507 
 508         numAppContexts.decrementAndGet();
 509 
 510         mostRecentKeyValue = null;
 511     }
 512 
 513     static final class PostShutdownEventRunnable implements Runnable {
 514         private final AppContext appContext;
 515 
 516         public PostShutdownEventRunnable(AppContext ac) {
 517             appContext = ac;
 518         }
 519 
 520         public void run() {
 521             final EventQueue eq = (EventQueue)appContext.get(EVENT_QUEUE_KEY);
 522             if (eq != null) {
 523                 eq.postEvent(AWTAutoShutdown.getShutdownEvent());
 524             }
 525         }
 526     }
 527 
 528     static final class CreateThreadAction implements PrivilegedAction {