1. /*
  2. * @(#)AppContext.java 1.3 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.util.Hashtable;
  9. import java.util.Enumeration;
  10. /**
  11. * The AppContext is a per-SecurityContext table which stores application
  12. * service instances. (If you are not writing an application service, or
  13. * don't know what one is, please do not use this class.) The AppContext
  14. * allows applet access to what would otherwise be potentially dangerous
  15. * services, such as the ability to peek at EventQueues or change the
  16. * look-and-feel of a Swing application.<p>
  17. *
  18. * Most application services use a singleton object to provide their
  19. * services, either as a default (such as getSystemEventQueue or
  20. * getDefaultToolkit) or as static methods with class data (System).
  21. * The AppContext works with the former method by extending the concept
  22. * of "default" to be SecurityContext-specific. Application services
  23. * lookup their singleton in the AppContext; if it hasn't been created,
  24. * the service creates the singleton and stores it in the AppContext.<p>
  25. *
  26. * For example, here we have a Foo service, with its pre-AppContext
  27. * code:<p>
  28. * <code><pre>
  29. * public class Foo {
  30. * private static Foo defaultFoo = new Foo();
  31. *
  32. * public static Foo getDefaultFoo() {
  33. * return defaultFoo;
  34. * }
  35. *
  36. * ... Foo service methods
  37. * }</pre></code><p>
  38. *
  39. * The problem with the above is that the Foo service is global in scope,
  40. * so that applets and other untrusted code can execute methods on the
  41. * single, shared Foo instance. The Foo service therefore either needs
  42. * to block its use by untrusted code using a SecurityManager test, or
  43. * restrict its capabilities so that it doesn't matter if untrusted code
  44. * executes it.<p>
  45. *
  46. * Here's the Foo class written to use the AppContext:<p>
  47. * <code><pre>
  48. * public class Foo {
  49. * public static Foo getDefaultFoo() {
  50. * Foo foo = (Foo)AppContext.getAppContext().get(Foo.class);
  51. * if (foo == null) {
  52. * foo = new Foo();
  53. * getAppContext().put(Foo.class, foo);
  54. * }
  55. * return foo;
  56. * }
  57. *
  58. * ... Foo service methods
  59. * }</pre></code><p>
  60. *
  61. * Since a separate AppContext exists for each SecurityContext, trusted
  62. * and untrusted code have access to different Foo instances. This allows
  63. * untrusted code access to "system-wide" services -- the service remains
  64. * within the security "sandbox". For example, say a malicious applet
  65. * wants to peek all of the key events on the EventQueue to listen for
  66. * passwords; if separate EventQueues are used for each SecurityContext
  67. * using AppContexts, the only key events that applet will be able to
  68. * listen to are its own. A more reasonable applet request would be to
  69. * change the Swing default look-and-feel; with that default stored in
  70. * an AppContext, the applet's look-and-feel will change without
  71. * disrupting other applets or potentially the browser itself.<p>
  72. *
  73. * Because the AppContext is a facility for safely extending application
  74. * service support to applets, none of its methods may be blocked by a
  75. * a SecurityManager check in a valid Java implementation. Applets may
  76. * therefore safely invoke any of its methods without worry of being
  77. * blocked.
  78. *
  79. * @author Thomas Ball
  80. * @version 1.3 11/29/01
  81. */
  82. final class AppContext {
  83. /* Since the contents of an AppContext are unique to each Java
  84. * session, this class should never be serialized. */
  85. /* A map of AppContexts, referenced by SecurityContext.
  86. * If the map is null then only one context, the systemAppContext,
  87. * has been referenced so far.
  88. */
  89. private static Hashtable security2appContexts = null;
  90. // A handle to be used when the SecurityContext is null.
  91. private static Object nullSecurityContext = new Object();
  92. private static AppContext systemAppContext =
  93. new AppContext(nullSecurityContext);
  94. /*
  95. * The hashtable associated with this AppContext. A private delegate
  96. * is used instead of subclassing Hashtable so as to avoid all of
  97. * Hashtable's potentially risky methods, such as clear(), elements(),
  98. * putAll(), etc. (It probably doesn't need to be final since the
  99. * class is, but I don't trust the compiler to be that smart.)
  100. */
  101. private final Hashtable table;
  102. /* The last key-pair cache -- comparing to this before doing a
  103. * lookup in the table can save some time, at the small cost of
  104. * one additional pointer comparison.
  105. */
  106. private static Object lastKey;
  107. private static Object lastValue;
  108. private AppContext(Object securityContext) {
  109. table = new Hashtable(2);
  110. if (securityContext != nullSecurityContext) {
  111. if (security2appContexts == null) {
  112. security2appContexts = new Hashtable(2, 0.2f);
  113. }
  114. security2appContexts.put(securityContext, this);
  115. }
  116. }
  117. /**
  118. * Returns the appropriate AppContext for the caller,
  119. * as determined by its SecurityContext.
  120. *
  121. * @returns the AppContext for the caller.
  122. * @see java.lang.SecurityManager#getSecurityContext
  123. * @since JDK1.2
  124. */
  125. public static AppContext getAppContext() {
  126. // Get security context, if any.
  127. Object securityContext = nullSecurityContext;
  128. /*
  129. Commenting out until we can reliably compute AppContexts
  130. SecurityManager sm = System.getSecurityManager();
  131. if (sm != null) {
  132. Object context = sm.getSecurityContext();
  133. if (context != null) {
  134. securityContext = context;
  135. }
  136. }
  137. */
  138. // Map security context to AppContext.
  139. if (securityContext == nullSecurityContext) {
  140. return systemAppContext;
  141. }
  142. AppContext appContext =
  143. (AppContext)security2appContexts.get(securityContext);
  144. if (appContext == null) {
  145. appContext = new AppContext(securityContext);
  146. security2appContexts.put(securityContext, appContext);
  147. }
  148. return appContext;
  149. }
  150. /**
  151. * Returns the value to which the specified key is mapped in this context.
  152. *
  153. * @param key a key in the AppContext.
  154. * @return the value to which the key is mapped in this AppContext;
  155. * <code>null</code> if the key is not mapped to any value.
  156. * @see #put(Object, Object)
  157. * @since JDK1.2
  158. */
  159. public synchronized Object get(Object key) {
  160. if (key != lastKey || lastValue == null) {
  161. lastValue = table.get(key);
  162. lastKey = key;
  163. }
  164. return lastValue;
  165. }
  166. /**
  167. * Maps the specified <code>key</code> to the specified
  168. * <code>value</code> in this AppContext. Neither the key nor the
  169. * value can be <code>null</code>.
  170. * <p>
  171. * The value can be retrieved by calling the <code>get</code> method
  172. * with a key that is equal to the original key.
  173. *
  174. * @param key the AppContext key.
  175. * @param value the value.
  176. * @return the previous value of the specified key in this
  177. * AppContext, or <code>null</code> if it did not have one.
  178. * @exception NullPointerException if the key or value is
  179. * <code>null</code>.
  180. * @see #get(Object)
  181. * @since JDK1.2
  182. */
  183. public synchronized Object put(Object key, Object value) {
  184. return table.put(key, value);
  185. }
  186. /**
  187. * Removes the key (and its corresponding value) from this
  188. * AppContext. This method does nothing if the key is not in the
  189. * AppContext.
  190. *
  191. * @param key the key that needs to be removed.
  192. * @return the value to which the key had been mapped in this AppContext,
  193. * or <code>null</code> if the key did not have a mapping.
  194. * @since JDK1.2
  195. */
  196. public synchronized Object remove(Object key) {
  197. return table.remove(key);
  198. }
  199. /**
  200. * Returns a string representation of this AppContext.
  201. * @since JDK1.2
  202. */
  203. public String toString() {
  204. Object securityContext = nullSecurityContext;
  205. SecurityManager sm = System.getSecurityManager();
  206. if (sm != null) {
  207. Object context =
  208. System.getSecurityManager().getSecurityContext();
  209. if (context != null) {
  210. securityContext = context;
  211. }
  212. }
  213. String contextName = (securityContext.equals(nullSecurityContext) ?
  214. "null" : securityContext.toString());
  215. return getClass().getName() + "[SecurityContext=" + contextName + "]";
  216. }
  217. }