appcontext.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 761 行 · 第 1/2 页

JAVA
761
字号
/* * @(#)AppContext.java	1.35 06/10/10 * * Copyright  1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER *  * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation.  *  * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt).  *  * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA  *  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions.  */package sun.awt;import java.awt.AWTEvent;import java.awt.EventQueue;import java.awt.Frame;import java.awt.Toolkit;import java.awt.event.InvocationEvent;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.HashMap;import java.util.IdentityHashMap;import java.util.Enumeration;import java.beans.PropertyChangeSupport;import java.beans.PropertyChangeListener;/** * The AppContext is a table referenced by ThreadGroup which stores * application service instances.  (If you are not writing an application * service, or don't know what one is, please do not use this class.) * The AppContext allows applet access to what would otherwise be * potentially dangerous services, such as the ability to peek at * EventQueues or change the look-and-feel of a Swing application.<p> * * Most application services use a singleton object to provide their * services, either as a default (such as getSystemEventQueue or  * getDefaultToolkit) or as static methods with class data (System). * The AppContext works with the former method by extending the concept * of "default" to be ThreadGroup-specific.  Application services * lookup their singleton in the AppContext.<p> * * For example, here we have a Foo service, with its pre-AppContext * code:<p> * <code><pre> *    public class Foo { *        private static Foo defaultFoo = new Foo(); * *        public static Foo getDefaultFoo() { *            return defaultFoo; *        } * *    ... Foo service methods *    }</pre></code><p> * * The problem with the above is that the Foo service is global in scope, * so that applets and other untrusted code can execute methods on the * single, shared Foo instance.  The Foo service therefore either needs * to block its use by untrusted code using a SecurityManager test, or * restrict its capabilities so that it doesn't matter if untrusted code * executes it.<p> * * Here's the Foo class written to use the AppContext:<p> * <code><pre> *    public class Foo { *        public static Foo getDefaultFoo() { *            Foo foo = (Foo)AppContext.getAppContext().get(Foo.class); *            if (foo == null) { *                foo = new Foo(); *                getAppContext().put(Foo.class, foo); *            } *            return foo; *        } * *    ... Foo service methods *    }</pre></code><p> * * Since a separate AppContext can exist for each ThreadGroup, trusted * and untrusted code have access to different Foo instances.  This allows * untrusted code access to "system-wide" services -- the service remains * within the AppContext "sandbox".  For example, say a malicious applet  * wants to peek all of the key events on the EventQueue to listen for * passwords; if separate EventQueues are used for each ThreadGroup * using AppContexts, the only key events that applet will be able to * listen to are its own.  A more reasonable applet request would be to * change the Swing default look-and-feel; with that default stored in * an AppContext, the applet's look-and-feel will change without  * disrupting other applets or potentially the browser itself.<p> * * Because the AppContext is a facility for safely extending application * service support to applets, none of its methods may be blocked by a * a SecurityManager check in a valid Java implementation.  Applets may * therefore safely invoke any of its methods without worry of being  * blocked. * * Note: If a SecurityManager is installed which derives from * sun.awt.AWTSecurityManager, it may override the * AWTSecurityManager.getAppContext() method to return the proper * AppContext based on the execution context, in the case where * the default ThreadGroup-based AppContext indexing would return * the main "system" AppContext.  For example, in an applet situation, * if a system thread calls into an applet, rather than returning the * main "system" AppContext (the one corresponding to the system thread), * an installed AWTSecurityManager may return the applet's AppContext * based on the execution context. * * @author  Thomas Ball * @author  Fred Ecks * @version 1.35 10/10/06 */public final class AppContext {    /* Since the contents of an AppContext are unique to each Java      * session, this class should never be serialized. */    /* The key to put()/get() the Java EventQueue into/from the AppContext.     */    public static final Object EVENT_QUEUE_KEY = new StringBuffer("EventQueue");    /* A map of AppContexts, referenced by ThreadGroup.     */    private static IdentityHashMap threadGroup2appContext = null;    /* The main "system" AppContext, used by everything not otherwise       contained in another AppContext.     */    private static AppContext mainAppContext = null;    /*     * The hash map associated with this AppContext.  A private delegate     * is used instead of subclassing HashMap so as to avoid all of     * HashMap's potentially risky methods, such as clear(), elements(),     * putAll(), etc.     */    private final HashMap table = new HashMap();    private final ThreadGroup threadGroup;    /**     * If any <code>PropertyChangeListeners</code> have been registered,     * the <code>changeSupport</code> field describes them.     *     * @see #addPropertyChangeListener     * @see #removePropertyChangeListener     * @see #firePropertyChange     *     * private PropertyChangeSupport changeSupport = null;     */    public static final String DISPOSED_PROPERTY_NAME = "disposed";    private boolean isDisposed = false; // true if AppContext is disposed    public boolean isDisposed() {        return isDisposed;    }    static {        // On the main Thread, we get the ThreadGroup, make a corresponding        // AppContext, and instantiate the Java EventQueue.  This way, legacy        // code is unaffected by the move to multiple AppContext ability.        AccessController.doPrivileged(new PrivilegedAction() {          public Object run() {            ThreadGroup currentThreadGroup =                                Thread.currentThread().getThreadGroup();            ThreadGroup parentThreadGroup = currentThreadGroup.getParent();            while (parentThreadGroup != null) {                // Find the root ThreadGroup to construct our main AppContext                currentThreadGroup = parentThreadGroup;                parentThreadGroup = currentThreadGroup.getParent();            }            mainAppContext = new AppContext(currentThreadGroup);            numAppContexts = 1;            return mainAppContext;          }        });    }    /*     * The total number of AppContexts, system-wide.  This number is     * incremented at the beginning of the constructor, and decremented     * at the end of dispose().  getAppContext() checks to see if this     * number is 1.  If so, it returns the sole AppContext without     * checking Thread.currentThread().     */    private static int numAppContexts;    /*     * The context ClassLoader that was used to create this AppContext.     */    private final ClassLoader contextClassLoader;    /**     * Constructor for AppContext.  This method is <i>not</i> public,     * nor should it ever be used as such.  The proper way to construct     * an AppContext is through the use of SunToolkit.createNewAppContext.     * A ThreadGroup is created for the new AppContext, a Thread is     * created within that ThreadGroup, and that Thread calls     * SunToolkit.createNewAppContext before calling anything else.     * That creates both the new AppContext and its EventQueue.     *      * @param   threadGroup     The ThreadGroup for the new AppContext     * @see     sun.awt.SunToolkit     * @since   JDK1.2     */    AppContext(ThreadGroup threadGroup) {        numAppContexts++;        if (threadGroup2appContext == null) {            threadGroup2appContext = new IdentityHashMap();        }        this.threadGroup = threadGroup;        threadGroup2appContext.put(threadGroup, this);        this.contextClassLoader =             (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {                    public Object run() {                        return Thread.currentThread().getContextClassLoader();                    }                });    }    private static MostRecentThreadAppContext mostRecentThreadAppContext = null;    /**     * Returns the appropriate AppContext for the caller,      * as determined by its ThreadGroup.  If the main "system" AppContext     * would be returned and there's an AWTSecurityManager installed, it     * is called to get the proper AppContext based on the execution     * context.     *     * @return  the AppContext for the caller.     * @see     java.lang.ThreadGroup     * @since   JDK1.2     */    public final static AppContext getAppContext() {        if (numAppContexts == 1)   // If there's only one system-wide,            return mainAppContext; // return the main system AppContext.        final Thread currentThread = Thread.currentThread();        AppContext appContext = null;        // Note: this most recent Thread/AppContext caching is thread-hot.        // A simple test using SwingSet found that 96.8% of lookups        // were matched using the most recent Thread/AppContext.  By        // instantiating a simple MostRecentThreadAppContext object on        // cache misses, the cache hits can be processed without        // synchronization.        MostRecentThreadAppContext recent = mostRecentThreadAppContext;        if ((recent != null) && (recent.thread == currentThread))  {            appContext = recent.appContext; // Cache hit        } else {          appContext = (AppContext)AccessController.doPrivileged(                                            new PrivilegedAction() {            public Object run() {            // Get the current ThreadGroup, and look for it and its            // parents in the hash from ThreadGroup to AppContext --            // it should be found, because we use createNewContext()            // when new AppContext objects are created.            ThreadGroup currentThreadGroup = currentThread.getThreadGroup();            ThreadGroup threadGroup = currentThreadGroup;            AppContext context =                          (AppContext)threadGroup2appContext.get(threadGroup);            while (context == null) {                threadGroup = threadGroup.getParent();                if (threadGroup == null) {                    // If we get here, we're running under a ThreadGroup that                    // has no AppContext associated with it.  This should never                    // happen, because createNewContext() should be used by the                    // toolkit to create the ThreadGroup that everything runs                    // under.                    throw new RuntimeException("Invalid ThreadGroup");                }                context = (AppContext)threadGroup2appContext.get(threadGroup);            }            // In case we did anything in the above while loop, we add            // all the intermediate ThreadGroups to threadGroup2appContext            // so we won't spin again.            for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) {                threadGroup2appContext.put(tg, context);            }            // Now we're done, so we cache the latest key/value pair.            // (we do this before checking with any AWTSecurityManager, so if            // this Thread equates with the main AppContext in the cache, it            // still will)            mostRecentThreadAppContext =                new MostRecentThreadAppContext(currentThread, context);            return context;          }         });        }        if (appContext == mainAppContext)  {            // Before we return the main "system" AppContext, check to            // see if there's an AWTSecurityManager installed.  If so,            // allow it to choose the AppContext to return.            SecurityManager securityManager = System.getSecurityManager();            if ((securityManager != null) &&                (securityManager instanceof AWTSecurityManager))  {                AWTSecurityManager awtSecMgr =                                      (AWTSecurityManager)securityManager;                AppContext secAppContext = awtSecMgr.getAppContext();                if (secAppContext != null)  {                    appContext = secAppContext; // Return what we're told                }            }        }        return appContext;    }    private long DISPOSAL_TIMEOUT = 5000;  // Default to 5-second timeout                                           // for disposal of all Frames                                           // (we wait for this time twice,                                           // once for dispose(), and once                                           // to clear the EventQueue).    private long THREAD_INTERRUPT_TIMEOUT = 1000;                            // Default to 1-second timeout for all                            // interrupted Threads to exit, and another                            // 1 second for all stopped Threads to die.    /**     * Disposes of this AppContext, all of its top-level Frames, and     * all Threads and ThreadGroups contained within it.     *      * This method must be called from a Thread which is not contained     * within this AppContext.     *     * @exception  IllegalThreadStateException  if the current thread is     *                                    contained within this AppContext     * @since      JDK1.2     */    public void dispose() throws IllegalThreadStateException {        // Check to be sure that the current Thread isn't in this AppContext        if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) {            throw new IllegalThreadStateException(                "Current Thread is contained within AppContext to be disposed."              );        }        synchronized(this) {            if (this.isDisposed) {                return; // If already disposed, bail.            }            this.isDisposed = true;        }        //final PropertyChangeSupport changeSupport = this.changeSupport;        //if (changeSupport != null) {        //    changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);        //}        // First, we post an InvocationEvent to be run on the        // EventDispatchThread which disposes of all top-level Frames        final Object notificationLock = new Object();        /*no mutiple frames in basis         * Runnable runnable = new Runnable() { public void run() {        *     Frame [] frames = Frame.getFrames();        *     for (int i = frames.length - 1; i >= 0; i--) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?