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