Source Code Cross Referenced for AppContext.java in  » 6.0-JDK-Modules-sun » awt » sun » awt » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules sun » awt » sun.awt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 1998-2007 Sun Microsystems, Inc.  All Rights Reserved.
003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004:         *
005:         * This code is free software; you can redistribute it and/or modify it
006:         * under the terms of the GNU General Public License version 2 only, as
007:         * published by the Free Software Foundation.  Sun designates this
008:         * particular file as subject to the "Classpath" exception as provided
009:         * by Sun in the LICENSE file that accompanied this code.
010:         *
011:         * This code is distributed in the hope that it will be useful, but WITHOUT
012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014:         * version 2 for more details (a copy is included in the LICENSE file that
015:         * accompanied this code).
016:         *
017:         * You should have received a copy of the GNU General Public License version
018:         * 2 along with this work; if not, write to the Free Software Foundation,
019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020:         *
021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022:         * CA 95054 USA or visit www.sun.com if you need additional information or
023:         * have any questions.
024:         */
025:
026:        package sun.awt;
027:
028:        import java.awt.EventQueue;
029:        import java.awt.Window;
030:        import java.awt.SystemTray;
031:        import java.awt.TrayIcon;
032:        import java.awt.Toolkit;
033:        import java.awt.GraphicsEnvironment;
034:        import java.awt.event.InvocationEvent;
035:        import java.security.AccessController;
036:        import java.security.PrivilegedAction;
037:        import java.util.Collections;
038:        import java.util.HashMap;
039:        import java.util.IdentityHashMap;
040:        import java.util.Map;
041:        import java.util.Set;
042:        import java.util.HashSet;
043:        import java.beans.PropertyChangeSupport;
044:        import java.beans.PropertyChangeListener;
045:
046:        /**
047:         * The AppContext is a table referenced by ThreadGroup which stores
048:         * application service instances.  (If you are not writing an application
049:         * service, or don't know what one is, please do not use this class.)
050:         * The AppContext allows applet access to what would otherwise be
051:         * potentially dangerous services, such as the ability to peek at
052:         * EventQueues or change the look-and-feel of a Swing application.<p>
053:         *
054:         * Most application services use a singleton object to provide their
055:         * services, either as a default (such as getSystemEventQueue or 
056:         * getDefaultToolkit) or as static methods with class data (System).
057:         * The AppContext works with the former method by extending the concept
058:         * of "default" to be ThreadGroup-specific.  Application services
059:         * lookup their singleton in the AppContext.<p>
060:         *
061:         * For example, here we have a Foo service, with its pre-AppContext
062:         * code:<p>
063:         * <code><pre>
064:         *    public class Foo {
065:         *        private static Foo defaultFoo = new Foo();
066:         *
067:         *        public static Foo getDefaultFoo() {
068:         *            return defaultFoo;
069:         *        }
070:         *
071:         *    ... Foo service methods
072:         *    }</pre></code><p>
073:         *
074:         * The problem with the above is that the Foo service is global in scope,
075:         * so that applets and other untrusted code can execute methods on the
076:         * single, shared Foo instance.  The Foo service therefore either needs
077:         * to block its use by untrusted code using a SecurityManager test, or
078:         * restrict its capabilities so that it doesn't matter if untrusted code
079:         * executes it.<p>
080:         *
081:         * Here's the Foo class written to use the AppContext:<p>
082:         * <code><pre>
083:         *    public class Foo {
084:         *        public static Foo getDefaultFoo() {
085:         *            Foo foo = (Foo)AppContext.getAppContext().get(Foo.class);
086:         *            if (foo == null) {
087:         *                foo = new Foo();
088:         *                getAppContext().put(Foo.class, foo);
089:         *            }
090:         *            return foo;
091:         *        }
092:         *
093:         *    ... Foo service methods
094:         *    }</pre></code><p>
095:         *
096:         * Since a separate AppContext can exist for each ThreadGroup, trusted
097:         * and untrusted code have access to different Foo instances.  This allows
098:         * untrusted code access to "system-wide" services -- the service remains
099:         * within the AppContext "sandbox".  For example, say a malicious applet 
100:         * wants to peek all of the key events on the EventQueue to listen for
101:         * passwords; if separate EventQueues are used for each ThreadGroup
102:         * using AppContexts, the only key events that applet will be able to
103:         * listen to are its own.  A more reasonable applet request would be to
104:         * change the Swing default look-and-feel; with that default stored in
105:         * an AppContext, the applet's look-and-feel will change without 
106:         * disrupting other applets or potentially the browser itself.<p>
107:         *
108:         * Because the AppContext is a facility for safely extending application
109:         * service support to applets, none of its methods may be blocked by a
110:         * a SecurityManager check in a valid Java implementation.  Applets may
111:         * therefore safely invoke any of its methods without worry of being 
112:         * blocked.
113:         *
114:         * Note: If a SecurityManager is installed which derives from
115:         * sun.awt.AWTSecurityManager, it may override the
116:         * AWTSecurityManager.getAppContext() method to return the proper
117:         * AppContext based on the execution context, in the case where
118:         * the default ThreadGroup-based AppContext indexing would return
119:         * the main "system" AppContext.  For example, in an applet situation,
120:         * if a system thread calls into an applet, rather than returning the
121:         * main "system" AppContext (the one corresponding to the system thread),
122:         * an installed AWTSecurityManager may return the applet's AppContext
123:         * based on the execution context.
124:         *
125:         * @author  Thomas Ball
126:         * @author  Fred Ecks
127:         * @version 1.47 05/28/07
128:         */
129:        public final class AppContext {
130:
131:            /* Since the contents of an AppContext are unique to each Java 
132:             * session, this class should never be serialized. */
133:
134:            /* The key to put()/get() the Java EventQueue into/from the AppContext.
135:             */
136:            public static final Object EVENT_QUEUE_KEY = new StringBuffer(
137:                    "EventQueue");
138:
139:            /* A map of AppContexts, referenced by ThreadGroup.
140:             */
141:            private static final Map<ThreadGroup, AppContext> threadGroup2appContext = Collections
142:                    .synchronizedMap(new IdentityHashMap<ThreadGroup, AppContext>());
143:
144:            /**
145:             * Returns a set containing all <code>AppContext</code>s.
146:             */
147:            public static Set<AppContext> getAppContexts() {
148:                return new HashSet<AppContext>(threadGroup2appContext.values());
149:            }
150:
151:            /* The main "system" AppContext, used by everything not otherwise
152:               contained in another AppContext.
153:             */
154:            private static AppContext mainAppContext = null;
155:
156:            /*
157:             * The hash map associated with this AppContext.  A private delegate
158:             * is used instead of subclassing HashMap so as to avoid all of
159:             * HashMap's potentially risky methods, such as clear(), elements(),
160:             * putAll(), etc.
161:             */
162:            private final HashMap table = new HashMap();
163:
164:            private final ThreadGroup threadGroup;
165:
166:            /**
167:             * If any <code>PropertyChangeListeners</code> have been registered,
168:             * the <code>changeSupport</code> field describes them.
169:             *
170:             * @see #addPropertyChangeListener
171:             * @see #removePropertyChangeListener
172:             * @see #firePropertyChange
173:             */
174:            private PropertyChangeSupport changeSupport = null;
175:
176:            public static final String DISPOSED_PROPERTY_NAME = "disposed";
177:            public static final String GUI_DISPOSED = "guidisposed";
178:
179:            private boolean isDisposed = false; // true if AppContext is disposed
180:
181:            public boolean isDisposed() {
182:                return isDisposed;
183:            }
184:
185:            static {
186:                // On the main Thread, we get the ThreadGroup, make a corresponding
187:                // AppContext, and instantiate the Java EventQueue.  This way, legacy
188:                // code is unaffected by the move to multiple AppContext ability.
189:                AccessController.doPrivileged(new PrivilegedAction() {
190:                    public Object run() {
191:                        ThreadGroup currentThreadGroup = Thread.currentThread()
192:                                .getThreadGroup();
193:                        ThreadGroup parentThreadGroup = currentThreadGroup
194:                                .getParent();
195:                        while (parentThreadGroup != null) {
196:                            // Find the root ThreadGroup to construct our main AppContext
197:                            currentThreadGroup = parentThreadGroup;
198:                            parentThreadGroup = currentThreadGroup.getParent();
199:                        }
200:                        mainAppContext = new AppContext(currentThreadGroup);
201:                        numAppContexts = 1;
202:                        return mainAppContext;
203:                    }
204:                });
205:            }
206:
207:            /*
208:             * The total number of AppContexts, system-wide.  This number is
209:             * incremented at the beginning of the constructor, and decremented
210:             * at the end of dispose().  getAppContext() checks to see if this
211:             * number is 1.  If so, it returns the sole AppContext without
212:             * checking Thread.currentThread().
213:             */
214:            private static int numAppContexts;
215:
216:            /*
217:             * The context ClassLoader that was used to create this AppContext.
218:             */
219:            private final ClassLoader contextClassLoader;
220:
221:            /**
222:             * Constructor for AppContext.  This method is <i>not</i> public,
223:             * nor should it ever be used as such.  The proper way to construct
224:             * an AppContext is through the use of SunToolkit.createNewAppContext.
225:             * A ThreadGroup is created for the new AppContext, a Thread is
226:             * created within that ThreadGroup, and that Thread calls
227:             * SunToolkit.createNewAppContext before calling anything else.
228:             * That creates both the new AppContext and its EventQueue.
229:             * 
230:             * @param   threadGroup     The ThreadGroup for the new AppContext
231:             * @see     sun.awt.SunToolkit
232:             * @since   1.2
233:             */
234:            AppContext(ThreadGroup threadGroup) {
235:                numAppContexts++;
236:
237:                this .threadGroup = threadGroup;
238:                threadGroup2appContext.put(threadGroup, this );
239:
240:                this .contextClassLoader = (ClassLoader) AccessController
241:                        .doPrivileged(new PrivilegedAction() {
242:                            public Object run() {
243:                                return Thread.currentThread()
244:                                        .getContextClassLoader();
245:                            }
246:                        });
247:            }
248:
249:            private static MostRecentThreadAppContext mostRecentThreadAppContext = null;
250:
251:            /**
252:             * Returns the appropriate AppContext for the caller, 
253:             * as determined by its ThreadGroup.  If the main "system" AppContext
254:             * would be returned and there's an AWTSecurityManager installed, it
255:             * is called to get the proper AppContext based on the execution
256:             * context.
257:             *
258:             * @return  the AppContext for the caller.
259:             * @see     java.lang.ThreadGroup
260:             * @since   1.2
261:             */
262:            public final static AppContext getAppContext() {
263:                if (numAppContexts == 1) // If there's only one system-wide,
264:                    return mainAppContext; // return the main system AppContext.
265:
266:                final Thread currentThread = Thread.currentThread();
267:
268:                AppContext appContext = null;
269:
270:                // Note: this most recent Thread/AppContext caching is thread-hot.
271:                // A simple test using SwingSet found that 96.8% of lookups
272:                // were matched using the most recent Thread/AppContext.  By
273:                // instantiating a simple MostRecentThreadAppContext object on
274:                // cache misses, the cache hits can be processed without
275:                // synchronization.
276:
277:                MostRecentThreadAppContext recent = mostRecentThreadAppContext;
278:                if ((recent != null) && (recent.thread == currentThread)) {
279:                    appContext = recent.appContext; // Cache hit
280:                } else {
281:                    appContext = (AppContext) AccessController
282:                            .doPrivileged(new PrivilegedAction() {
283:                                public Object run() {
284:                                    // Get the current ThreadGroup, and look for it and its
285:                                    // parents in the hash from ThreadGroup to AppContext --
286:                                    // it should be found, because we use createNewContext()
287:                                    // when new AppContext objects are created.
288:                                    ThreadGroup currentThreadGroup = currentThread
289:                                            .getThreadGroup();
290:                                    ThreadGroup threadGroup = currentThreadGroup;
291:                                    AppContext context = threadGroup2appContext
292:                                            .get(threadGroup);
293:                                    while (context == null) {
294:                                        threadGroup = threadGroup.getParent();
295:                                        if (threadGroup == null) {
296:                                            // If we get here, we're running under a ThreadGroup that
297:                                            // has no AppContext associated with it.  This should never
298:                                            // happen, because createNewContext() should be used by the
299:                                            // toolkit to create the ThreadGroup that everything runs
300:                                            // under.
301:                                            throw new RuntimeException(
302:                                                    "Invalid ThreadGroup");
303:                                        }
304:                                        context = threadGroup2appContext
305:                                                .get(threadGroup);
306:                                    }
307:                                    // In case we did anything in the above while loop, we add
308:                                    // all the intermediate ThreadGroups to threadGroup2appContext
309:                                    // so we won't spin again.
310:                                    for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg
311:                                            .getParent()) {
312:                                        threadGroup2appContext.put(tg, context);
313:                                    }
314:                                    // Now we're done, so we cache the latest key/value pair.
315:                                    // (we do this before checking with any AWTSecurityManager, so if
316:                                    // this Thread equates with the main AppContext in the cache, it
317:                                    // still will)
318:                                    mostRecentThreadAppContext = new MostRecentThreadAppContext(
319:                                            currentThread, context);
320:
321:                                    return context;
322:                                }
323:                            });
324:                }
325:
326:                if (appContext == mainAppContext) {
327:                    // Before we return the main "system" AppContext, check to
328:                    // see if there's an AWTSecurityManager installed.  If so,
329:                    // allow it to choose the AppContext to return.
330:                    SecurityManager securityManager = System
331:                            .getSecurityManager();
332:                    if ((securityManager != null)
333:                            && (securityManager instanceof  AWTSecurityManager)) {
334:                        AWTSecurityManager awtSecMgr = (AWTSecurityManager) securityManager;
335:                        AppContext secAppContext = awtSecMgr.getAppContext();
336:                        if (secAppContext != null) {
337:                            appContext = secAppContext; // Return what we're told
338:                        }
339:                    }
340:                }
341:
342:                return appContext;
343:            }
344:
345:            private long DISPOSAL_TIMEOUT = 5000; // Default to 5-second timeout
346:            // for disposal of all Frames
347:            // (we wait for this time twice,
348:            // once for dispose(), and once
349:            // to clear the EventQueue).
350:
351:            private long THREAD_INTERRUPT_TIMEOUT = 1000;
352:
353:            // Default to 1-second timeout for all
354:            // interrupted Threads to exit, and another
355:            // 1 second for all stopped Threads to die.
356:
357:            /**
358:             * Disposes of this AppContext, all of its top-level Frames, and
359:             * all Threads and ThreadGroups contained within it.
360:             * 
361:             * This method must be called from a Thread which is not contained
362:             * within this AppContext.
363:             *
364:             * @exception  IllegalThreadStateException  if the current thread is
365:             *                                    contained within this AppContext
366:             * @since      1.2
367:             */
368:            public void dispose() throws IllegalThreadStateException {
369:                // Check to be sure that the current Thread isn't in this AppContext
370:                if (this .threadGroup.parentOf(Thread.currentThread()
371:                        .getThreadGroup())) {
372:                    throw new IllegalThreadStateException(
373:                            "Current Thread is contained within AppContext to be disposed.");
374:                }
375:
376:                synchronized (this ) {
377:                    if (this .isDisposed) {
378:                        return; // If already disposed, bail.
379:                    }
380:                    this .isDisposed = true;
381:                }
382:
383:                final PropertyChangeSupport changeSupport = this .changeSupport;
384:                if (changeSupport != null) {
385:                    changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME,
386:                            false, true);
387:                }
388:
389:                // First, we post an InvocationEvent to be run on the
390:                // EventDispatchThread which disposes of all top-level Frames and TrayIcons
391:
392:                final Object notificationLock = new Object();
393:
394:                Runnable runnable = new Runnable() {
395:                    public void run() {
396:                        Window[] windowsToDispose = Window
397:                                .getOwnerlessWindows();
398:                        for (Window w : windowsToDispose) {
399:                            w.dispose();
400:                        }
401:                        AccessController.doPrivileged(new PrivilegedAction() {
402:                            public Object run() {
403:                                if (!GraphicsEnvironment.isHeadless()
404:                                        && SystemTray.isSupported()) {
405:                                    SystemTray systemTray = SystemTray
406:                                            .getSystemTray();
407:                                    TrayIcon[] trayIconsToDispose = systemTray
408:                                            .getTrayIcons();
409:                                    for (TrayIcon ti : trayIconsToDispose) {
410:                                        systemTray.remove(ti);
411:                                    }
412:                                }
413:                                return null;
414:                            }
415:                        });
416:                        // Alert PropertyChangeListeners that the GUI has been disposed.
417:                        if (changeSupport != null) {
418:                            changeSupport.firePropertyChange(GUI_DISPOSED,
419:                                    false, true);
420:                        }
421:                        synchronized (notificationLock) {
422:                            notificationLock.notifyAll(); // Notify caller that we're done
423:                        }
424:                    }
425:                };
426:                synchronized (notificationLock) {
427:                    SunToolkit.postEvent(this , new InvocationEvent(Toolkit
428:                            .getDefaultToolkit(), runnable));
429:                    try {
430:                        notificationLock.wait(DISPOSAL_TIMEOUT);
431:                    } catch (InterruptedException e) {
432:                    }
433:                }
434:
435:                // Next, we post another InvocationEvent to the end of the
436:                // EventQueue.  When it's executed, we know we've executed all
437:                // events in the queue.
438:
439:                runnable = new Runnable() {
440:                    public void run() {
441:                        synchronized (notificationLock) {
442:                            notificationLock.notifyAll(); // Notify caller that we're done
443:                        }
444:                    }
445:                };
446:                synchronized (notificationLock) {
447:                    SunToolkit.postEvent(this , new InvocationEvent(Toolkit
448:                            .getDefaultToolkit(), runnable));
449:                    try {
450:                        notificationLock.wait(DISPOSAL_TIMEOUT);
451:                    } catch (InterruptedException e) {
452:                    }
453:                }
454:
455:                // Next, we interrupt all Threads in the ThreadGroup
456:                this .threadGroup.interrupt();
457:                // Note, the EventDispatchThread we've interrupted may dump an
458:                // InterruptedException to the console here.  This needs to be
459:                // fixed in the EventDispatchThread, not here.
460:
461:                // Next, we sleep 10ms at a time, waiting for all of the active
462:                // Threads in the ThreadGroup to exit.
463:
464:                long startTime = System.currentTimeMillis();
465:                long endTime = startTime + (long) THREAD_INTERRUPT_TIMEOUT;
466:                while ((this .threadGroup.activeCount() > 0)
467:                        && (System.currentTimeMillis() < endTime)) {
468:                    try {
469:                        Thread.sleep(10);
470:                    } catch (InterruptedException e) {
471:                    }
472:                }
473:
474:                // Then, we stop any remaining Threads
475:                this .threadGroup.stop();
476:
477:                // Next, we sleep 10ms at a time, waiting for all of the active
478:                // Threads in the ThreadGroup to die.
479:
480:                startTime = System.currentTimeMillis();
481:                endTime = startTime + (long) THREAD_INTERRUPT_TIMEOUT;
482:                while ((this .threadGroup.activeCount() > 0)
483:                        && (System.currentTimeMillis() < endTime)) {
484:                    try {
485:                        Thread.sleep(10);
486:                    } catch (InterruptedException e) {
487:                    }
488:                }
489:
490:                // Next, we remove this and all subThreadGroups from threadGroup2appContext
491:                int numSubGroups = this .threadGroup.activeGroupCount();
492:                if (numSubGroups > 0) {
493:                    ThreadGroup[] subGroups = new ThreadGroup[numSubGroups];
494:                    numSubGroups = this .threadGroup.enumerate(subGroups);
495:                    for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
496:                        threadGroup2appContext.remove(subGroups[subGroup]);
497:                    }
498:                }
499:                threadGroup2appContext.remove(this .threadGroup);
500:
501:                MostRecentThreadAppContext recent = mostRecentThreadAppContext;
502:                if ((recent != null) && (recent.appContext == this ))
503:                    mostRecentThreadAppContext = null;
504:                // If the "most recent" points to this, clear it for GC
505:
506:                // Finally, we destroy the ThreadGroup entirely.
507:                try {
508:                    this .threadGroup.destroy();
509:                } catch (IllegalThreadStateException e) {
510:                    // Fired if not all the Threads died, ignore it and proceed
511:                }
512:
513:                synchronized (table) {
514:                    this .table.clear(); // Clear out the Hashtable to ease garbage collection
515:                }
516:
517:                numAppContexts--;
518:
519:                mostRecentKeyValue = null;
520:            }
521:
522:            static final class PostShutdownEventRunnable implements  Runnable {
523:                private final AppContext appContext;
524:
525:                public PostShutdownEventRunnable(AppContext ac) {
526:                    appContext = ac;
527:                }
528:
529:                public void run() {
530:                    final EventQueue eq = (EventQueue) appContext
531:                            .get(EVENT_QUEUE_KEY);
532:                    if (eq != null) {
533:                        eq.postEvent(AWTAutoShutdown.getShutdownEvent());
534:                    }
535:                }
536:            }
537:
538:            static final class CreateThreadAction implements  PrivilegedAction {
539:                private final AppContext appContext;
540:                private final Runnable runnable;
541:
542:                public CreateThreadAction(AppContext ac, Runnable r) {
543:                    appContext = ac;
544:                    runnable = r;
545:                }
546:
547:                public Object run() {
548:                    Thread t = new Thread(appContext.getThreadGroup(), runnable);
549:                    t.setContextClassLoader(appContext.getContextClassLoader());
550:                    t.setPriority(Thread.NORM_PRIORITY + 1);
551:                    t.setDaemon(true);
552:                    return t;
553:                }
554:            }
555:
556:            static void stopEventDispatchThreads() {
557:                for (AppContext appContext : getAppContexts()) {
558:                    if (appContext.isDisposed()) {
559:                        continue;
560:                    }
561:                    Runnable r = new PostShutdownEventRunnable(appContext);
562:                    // For security reasons EventQueue.postEvent should only be called
563:                    // on a thread that belongs to the corresponding thread group.
564:                    if (appContext != AppContext.getAppContext()) {
565:                        // Create a thread that belongs to the thread group associated
566:                        // with the AppContext and invokes EventQueue.postEvent.
567:                        PrivilegedAction action = new CreateThreadAction(
568:                                appContext, r);
569:                        Thread thread = (Thread) AccessController
570:                                .doPrivileged(action);
571:                        thread.start();
572:                    } else {
573:                        r.run();
574:                    }
575:                }
576:            }
577:
578:            private MostRecentKeyValue mostRecentKeyValue = null;
579:            private MostRecentKeyValue shadowMostRecentKeyValue = null;
580:
581:            /**
582:             * Returns the value to which the specified key is mapped in this context.
583:             *
584:             * @param   key   a key in the AppContext.
585:             * @return  the value to which the key is mapped in this AppContext;
586:             *          <code>null</code> if the key is not mapped to any value.
587:             * @see     #put(Object, Object)
588:             * @since   1.2
589:             */
590:            public Object get(Object key) {
591:                /*
592:                 * The most recent reference should be updated inside a synchronized
593:                 * block to avoid a race when put() and get() are executed in
594:                 * parallel on different threads.
595:                 */
596:                synchronized (table) {
597:                    // Note: this most recent key/value caching is thread-hot.
598:                    // A simple test using SwingSet found that 72% of lookups
599:                    // were matched using the most recent key/value.  By instantiating
600:                    // a simple MostRecentKeyValue object on cache misses, the
601:                    // cache hits can be processed without synchronization.
602:
603:                    MostRecentKeyValue recent = mostRecentKeyValue;
604:                    if ((recent != null) && (recent.key == key)) {
605:                        return recent.value;
606:                    }
607:
608:                    Object value = table.get(key);
609:                    if (mostRecentKeyValue == null) {
610:                        mostRecentKeyValue = new MostRecentKeyValue(key, value);
611:                        shadowMostRecentKeyValue = new MostRecentKeyValue(key,
612:                                value);
613:                    } else {
614:                        MostRecentKeyValue auxKeyValue = mostRecentKeyValue;
615:                        shadowMostRecentKeyValue.setPair(key, value);
616:                        mostRecentKeyValue = shadowMostRecentKeyValue;
617:                        shadowMostRecentKeyValue = auxKeyValue;
618:                    }
619:                    return value;
620:                }
621:            }
622:
623:            /**
624:             * Maps the specified <code>key</code> to the specified 
625:             * <code>value</code> in this AppContext.  Neither the key nor the 
626:             * value can be <code>null</code>.
627:             * <p>
628:             * The value can be retrieved by calling the <code>get</code> method 
629:             * with a key that is equal to the original key. 
630:             *
631:             * @param      key     the AppContext key.
632:             * @param      value   the value.
633:             * @return     the previous value of the specified key in this 
634:             *             AppContext, or <code>null</code> if it did not have one.
635:             * @exception  NullPointerException  if the key or value is
636:             *               <code>null</code>.
637:             * @see     #get(Object)
638:             * @since   1.2
639:             */
640:            public Object put(Object key, Object value) {
641:                synchronized (table) {
642:                    MostRecentKeyValue recent = mostRecentKeyValue;
643:                    if ((recent != null) && (recent.key == key))
644:                        recent.value = value;
645:                    return table.put(key, value);
646:                }
647:            }
648:
649:            /**
650:             * Removes the key (and its corresponding value) from this 
651:             * AppContext. This method does nothing if the key is not in the
652:             * AppContext.
653:             *
654:             * @param   key   the key that needs to be removed.
655:             * @return  the value to which the key had been mapped in this AppContext,
656:             *          or <code>null</code> if the key did not have a mapping.
657:             * @since   1.2
658:             */
659:            public Object remove(Object key) {
660:                synchronized (table) {
661:                    MostRecentKeyValue recent = mostRecentKeyValue;
662:                    if ((recent != null) && (recent.key == key))
663:                        recent.value = null;
664:                    return table.remove(key);
665:                }
666:            }
667:
668:            /**
669:             * Returns the root ThreadGroup for all Threads contained within
670:             * this AppContext.
671:             * @since   1.2
672:             */
673:            public ThreadGroup getThreadGroup() {
674:                return threadGroup;
675:            }
676:
677:            /**
678:             * Returns the context ClassLoader that was used to create this
679:             * AppContext.
680:             *
681:             * @see java.lang.Thread#getContextClassLoader
682:             */
683:            public ClassLoader getContextClassLoader() {
684:                return contextClassLoader;
685:            }
686:
687:            /**
688:             * Returns a string representation of this AppContext.
689:             * @since   1.2
690:             */
691:            public String toString() {
692:                return getClass().getName() + "[threadGroup="
693:                        + threadGroup.getName() + "]";
694:            }
695:
696:            /**
697:             * Returns an array of all the property change listeners
698:             * registered on this component.
699:             *
700:             * @return all of this component's <code>PropertyChangeListener</code>s
701:             *         or an empty array if no property change
702:             *         listeners are currently registered
703:             *
704:             * @see      #addPropertyChangeListener
705:             * @see      #removePropertyChangeListener
706:             * @see      #getPropertyChangeListeners(java.lang.String)
707:             * @see      java.beans.PropertyChangeSupport#getPropertyChangeListeners
708:             * @since    1.4
709:             */
710:            public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
711:                if (changeSupport == null) {
712:                    return new PropertyChangeListener[0];
713:                }
714:                return changeSupport.getPropertyChangeListeners();
715:            }
716:
717:            /**
718:             * Adds a PropertyChangeListener to the listener list for a specific
719:             * property. The specified property may be one of the following:
720:             * <ul>
721:             *    <li>if this AppContext is disposed ("disposed")</li>
722:             * </ul>
723:             * <ul>
724:             *    <li>if this AppContext's unowned Windows have been disposed
725:             *    ("guidisposed").  Code to cleanup after the GUI is disposed
726:             *    (such as LookAndFeel.uninitialize()) should execute in response to
727:             *    this property being fired.  Notifications for the "guidisposed"
728:             *    property are sent on the event dispatch thread.</li>
729:             * </ul>
730:             * <p>
731:             * If listener is null, no exception is thrown and no action is performed.
732:             *
733:             * @param propertyName one of the property names listed above
734:             * @param listener the PropertyChangeListener to be added
735:             *
736:             * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
737:             * @see #getPropertyChangeListeners(java.lang.String)
738:             * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
739:             */
740:            public synchronized void addPropertyChangeListener(
741:                    String propertyName, PropertyChangeListener listener) {
742:                if (listener == null) {
743:                    return;
744:                }
745:                if (changeSupport == null) {
746:                    changeSupport = new PropertyChangeSupport(this );
747:                }
748:                changeSupport.addPropertyChangeListener(propertyName, listener);
749:            }
750:
751:            /**
752:             * Removes a PropertyChangeListener from the listener list for a specific
753:             * property. This method should be used to remove PropertyChangeListeners
754:             * that were registered for a specific bound property.
755:             * <p>
756:             * If listener is null, no exception is thrown and no action is performed.
757:             *
758:             * @param propertyName a valid property name
759:             * @param listener the PropertyChangeListener to be removed
760:             *
761:             * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
762:             * @see #getPropertyChangeListeners(java.lang.String)
763:             * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
764:             */
765:            public synchronized void removePropertyChangeListener(
766:                    String propertyName, PropertyChangeListener listener) {
767:                if (listener == null || changeSupport == null) {
768:                    return;
769:                }
770:                changeSupport.removePropertyChangeListener(propertyName,
771:                        listener);
772:            }
773:
774:            /**
775:             * Returns an array of all the listeners which have been associated 
776:             * with the named property.
777:             *
778:             * @return all of the <code>PropertyChangeListeners</code> associated with
779:             *         the named property or an empty array if no listeners have 
780:             *         been added
781:             *
782:             * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
783:             * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
784:             * @see #getPropertyChangeListeners
785:             * @since 1.4
786:             */
787:            public synchronized PropertyChangeListener[] getPropertyChangeListeners(
788:                    String propertyName) {
789:                if (changeSupport == null) {
790:                    return new PropertyChangeListener[0];
791:                }
792:                return changeSupport.getPropertyChangeListeners(propertyName);
793:            }
794:        }
795:
796:        final class MostRecentThreadAppContext {
797:            final Thread thread;
798:            final AppContext appContext;
799:
800:            MostRecentThreadAppContext(Thread key, AppContext value) {
801:                thread = key;
802:                appContext = value;
803:            }
804:        }
805:
806:        final class MostRecentKeyValue {
807:            Object key;
808:            Object value;
809:
810:            MostRecentKeyValue(Object k, Object v) {
811:                key = k;
812:                value = v;
813:            }
814:
815:            void setPair(Object k, Object v) {
816:                key = k;
817:                value = v;
818:            }
819:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.