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 + -
显示快捷键?