Coverage details for org.chwf.registry.UserRegistry

LineHitsSource
1 /*
2 Chrysalis Web Framework [http://chrysalis.sourceforge.net]
3 Copyright (c) 2002, 2003, 2004, Paul Strack
4  
5 All rights reserved.
6  
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9  
10 1. Redistributions of source code must retain the above copyright notice, this
11 list of conditions and the following disclaimer.
12  
13 2. Redistributions in binary form must reproduce the above copyright notice,
14 this list of conditions and the following disclaimer in the documentation
15 and/or other materials provided with the distribution.
16  
17 3. Neither the name of the copyright holder nor the names of its contributors
18 may be used to endorse or promote products derived from this software without
19 specific prior written permission.
20  
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
25 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32  
33 package org.chwf.registry;
34  
35 import java.io.Serializable;
36 import java.util.HashMap;
37 import java.util.Map;
38  
39 /**
40  * <p>A class for caching user-specific data. It provides an abstraction layer
41  * for components that can run both in single-user applications (such as test
42  * applications) and multi-user applications (such as a web application).
43  * Single-user application should initialize a global registry by using the
44  * {@link GlobalUserRegistry#init()} method:</p>
45  *
46  * <pre>
47  * GlobalUserRegistry.init();</pre>
48  *
49  * <p>Multi-user applications should cache their registry in the user's session
50  * and transfer them to this class at the beginning of each thread of execution
51  * using the {@link #initLocalRegistry(UserRegistry)}. This method stores the
52  * registry in a <code>ThreadLocal</code> variable, so that it can be retrieved
53  * anywhere in the thread of execution. This local registry should be released
54  * when the thread of execution is complete using the
55  * {@link #releaseLocalRegistry()} method:</p>
56  *
57  * <pre>
58  * // A servlet example:
59  * UserRegistry registry =
60  * (UserRegistry) session.getAttribute("UserRegistry");
61  * UserRegistry.initLocalRegistry(registy);
62  *
63  * // Do work ...
64  *
65  * UserRegistry.releaseLocalRegistry();</pre>
66  *
67  * <p>Releasing the local registry is important because multi-user applications
68  * often use thread-pooling, and failing to release the registry might mean that
69  * the <code>ThreadLocal</code> variable could bleed between users. Failure to
70  * release local registries could lead to memory leaks and weird errors.</p>
71  *
72  * <p>The various initialization methods are <code>protected</code>, so that the
73  * user registry can only be initialized by subclasses. For each application,
74  * you should create a subclass of the <code>UserRegistry</code> class with the
75  * correct initializations for that application. See {@link GlobalUserRegistry}
76  * and {@link org.chwf.servlet.ServletData} for examples. The registry
77  * may be initialized in one way for production and another for testing.</p>
78  *
79  * <p>Whether the application is using global or local registries, data inside
80  * the registry is manipulated in the same way:</p>
81  *
82  * <pre>
83  * UserRegistry.setRegistryEntry("My data", value);
84  * Object data = UserRegistry.getRegistryEntry("My data");
85  * UserRegistry.removeRegistryEntry("My data");</pre>
86  *
87  * <p>Ideally, you should create encapsulating classes that prevent direct
88  * access to the user registry. You should use a good naming convention (based
89  * on class names) to minimize name collisions for information stored in the
90  * registry.</p>
91  *
92  * <pre>
93  * public class UserLocale {
94  * private static final String REGISTRY_NAME = UserLocale.class.getName();
95  *
96  * public Locale getLocale() {
97  * return (Locale) UserRegistry.getRegistryEntry(UserLocale.REGISTRY_NAME);
98  * }
99  *
100  * public void setLocale(Locale locale) {
101  * UserRegistry.overwriteRegistryEntry(UserLocale.REGISTRY_NAME, locale);
102  * }
103  * }</pre>
104  *
105  * <p>Finally, because the registry is global and global data is bad, you
106  * should use it sparingly.</p>
107  *
108  * @author <a href="mailto:pfstrack@users.sourceforge.net">Paul Strack</a>
109  */
110992public class UserRegistry implements Serializable {
111  
112   /** Standard prefix for user-singletons. */
113   private static final String SINGLETON_PREFIX = "singleton:";
114  
115   /** The global registry (if any). */
1162  private static UserRegistry globalRegistry = null;
117  
118   /** A ThreadLocal variable to hold the local registry. */
1191  private static final ThreadLocal LOCAL_REGISTRY = new ThreadLocal();
120  
121   /** Registry data. */
122496  private final Map data = new HashMap();
123  
124   /**
125    * Returns true if the registry is initialized.<p>
126    *
127    * @return true if the registry is initialized.
128    */
129   public static boolean isInitialized() {
130397    UserRegistry registry = UserRegistry.getGlobalRegistry();
131397    if (registry == null) {
132338      registry = UserRegistry.getLocalRegistry();
133     }
134397    return (registry != null);
135   }
136  
137   /**
138    * Retrieve the registry. This can be used for registry serialization, or
139    * to retrieve additional registry data from subclasses:<p>
140    *
141    * <pre>
142    * CustomRegistry custom = (CustomRegistry) UserRegistry.getRegistry();
143    * custom.getCustomData();</pre>
144    *
145    * @return The registry.
146    * @throws RegistryException If the registry is not initialized.
147    */
148   public static UserRegistry getRegistry() throws RegistryException {
149398    UserRegistry registry = UserRegistry.getGlobalRegistry();
150398    if (registry == null) {
151335      registry = UserRegistry.getLocalRegistry();
152     }
153398    if (registry == null) {
1545      throw new RegistryException(RegistryException.MESSAGE_NOT_INITIALIZED);
155     }
156393    return registry;
157   }
158  
159   /**
160    * Get registry entry value.<p>
161    *
162    * @param name The registry entry name.
163    * @return The registry entry value.
164    * @throws RegistryException If the registry is not initialized.
165    */
166   public static Object getRegistryEntry(String name) throws RegistryException {
167304    return UserRegistry.getRegistry().getData().get(name);
168   }
169  
170   /**
171    * Set registry entry value. Throws a runtime exception if this overwrites
172    * an existing registry entry.<p>
173    *
174    * @param name The registry entry name.
175    * @param value The registry entry value.
176    * @throws RegistryException If the registry is not initialized or an
177    * existing value is overwritten.
178    */
179   public static void setRegistryEntry(String name, Object value)
180     throws RegistryException {
18169    Object oldValue = overwriteRegistryEntry(name, value);
18269    if (oldValue != null) {
1832      UserRegistry.getRegistry().getData().put(name, oldValue);
1842      if (!oldValue.equals(value)) {
1851        Object[] arguments = { name };
1861        throw new RegistryException(
187           RegistryException.MESSAGE_ILLEGAL_OVERWRITE,
188           new Object[] { name });
189       }
190     }
19168  }
192  
193   /**
194    * Overwrite registry entry.<p>
195    *
196    * @param name The registry entry name.
197    * @param value The registry entry value.
198    * @return The original value.
199    * @throws RegistryException If the registry is not initialized.
200    */
201   public static Object overwriteRegistryEntry(String name, Object value)
202     throws RegistryException {
20376    return UserRegistry.getRegistry().getData().put(name, value);
204   }
205  
206   /**
207    * Remove and return registry entry.<p>
208    *
209    * @param name The registry entry name.
210    * @return The original value.
211    * @throws RegistryException If the registry is not initialized.
212    */
213   public static Object removeRegistryEntry(String name)
214     throws RegistryException {
2155    return UserRegistry.getRegistry().getData().remove(name);
216   }
217  
218   /**
219    * Get class-based, user-specific singleton for the given class,
220    * creating a new one if none exists. This method uses the class's
221    * no-parameter constructor.<p>
222    *
223    * @param cls The class for the singleton.
224    * @return The singleton object.
225    * @throws RegistryException If the registry is not initialized or
226    * singleton creation fails.
227    */
228   public static Object getSingleton(Class cls) throws RegistryException {
229112    String name = SINGLETON_PREFIX + cls.getName();
230112    Object singleton = UserRegistry.getRegistryEntry(name);
231112    if (singleton == null) {
232       try {
23362        singleton = cls.newInstance();
23461      } catch (IllegalAccessException ex) {
2350        throw new RegistryException(
236           RegistryException.MESSAGE_NO_PUBLIC_SINGLETON_CONSTRUCTOR);
237       } catch (InstantiationException ex) {
2381        throw new RegistryException(
239           RegistryException.MESSAGE_SINGLETON_CONSTRUCTOR_FAILED,
240           new Object[] { ex });
241       }
24261      UserRegistry.setRegistryEntry(name, singleton);
243     }
244111    return singleton;
245   }
246  
247   /**
248    * Get class-based, user-specific singleton for the given class,
249    * creating a new one if none exists. This method uses the class's
250    * no-parameter constructor.<p>
251    *
252    * @param cls The class for the singleton as a String.
253    * @return The singleton object.
254    * @throws RegistryException If the registry is not initialized or
255    * singleton creation fails.
256    */
257   public static Object getSingleton(String cls) throws RegistryException {
258     try {
25914      Class userClass = Class.forName(cls);
26014      return UserRegistry.getSingleton(userClass);
261     } catch (ClassNotFoundException ex) {
2620      throw new RegistryException(
263         RegistryException.MESSAGE_SINGLETON_CLASS_NOT_FOUND,
264         new Object[] { cls });
265     }
266   }
267  
268   /**
269    * Release registry singleton for the given class.<p>
270    *
271    * @param cls The class for the singleton.
272    * @throws RegistryException If the registry is not initialized.
273    */
274   public static void releaseSingleton(Class cls) throws RegistryException {
2753    String name = SINGLETON_PREFIX + cls.getName();
2763    UserRegistry.removeRegistryEntry(name);
2773  }
278  
279   /**
280    * Initialize a local registry. Used by subclasses. Re-initializing the
281    * registry over-writes existing data.<p>
282    *
283    * @param registry The registry.
284    */
285   protected static void initLocalRegistry(UserRegistry registry) {
286490    UserRegistry.setLocalRegistry(registry);
287490  }
288  
289   /** Release the local registry. Used by subclasses.<p> */
290   protected static void releaseLocalRegistry() {
291501    UserRegistry.setLocalRegistry(null);
292501  }
293  
294   /**
295    * Initialize a global registry. Used by subclasses. An application that
296    * uses a global registry should not use local registries.<p>
297    *
298    * @param registry The registry.
299    */
300   protected static void initGlobalRegistry(UserRegistry registry) {
3018    UserRegistry.setGlobalRegistry(registry);
3026  }
303  
304   /** Release the global registry. Used by subclasses.<p> */
305   protected static void releaseGlobalRegistry() {
30622    UserRegistry.globalRegistry = null;
30722  }
308  
309   /**
310    * Self-encapsulation.
311    *
312    * @param localRegistry The local registry.
313    */
314   private static void setLocalRegistry(UserRegistry localRegistry) {
315991    UserRegistry.LOCAL_REGISTRY.set(localRegistry);
316991  }
317  
318   /**
319    * Self-encapsulation.
320    *
321    * @return The local registry.
322    */
323   private static UserRegistry getLocalRegistry() {
324673    return (UserRegistry) LOCAL_REGISTRY.get();
325   }
326  
327   /**
328    * Self-encapsulation.
329    *
330    * @param globalRegistry The global registry.
331    */
332   private static void setGlobalRegistry(UserRegistry globalRegistry) {
3338    if (UserRegistry.globalRegistry != null) {
3342      throw new RegistryException(
335         RegistryException.MESSAGE_GLOBAL_REGISTRY_INITIALIZED);
336     }
3376    UserRegistry.globalRegistry = globalRegistry;
3386  }
339  
340   /**
341    * Self-encapsulation.
342    *
343    * @return The global registry.
344    */
345   private static UserRegistry getGlobalRegistry() {
346795    return UserRegistry.globalRegistry;
347   }
348  
349   /**
350    * Self-encapsulation.
351    *
352    * @return The registry data.
353    */
354   private Map getData() {
355387    return data;
356   }
357 }

this report was generated by version 1.0.5 of jcoverage.
visit www.jcoverage.com for updates.

copyright © 2003, jcoverage ltd. all rights reserved.
Java is a trademark of Sun Microsystems, Inc. in the United States and other countries.