Source Code Cross Referenced for AppContext.java in  » 6.0-JDK-Modules » j2me » 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 » j2me » sun.awt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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