001    /* ====================================================================
002     * The Apache Software License, Version 1.1
003     *
004     * Copyright (c) 2003 The Apache Software Foundation.  All rights
005     * reserved.
006     *
007     * Redistribution and use in source and binary forms, with or without
008     * modification, are permitted provided that the following conditions
009     * are met:
010     *
011     * 1. Redistributions of source code must retain the above copyright
012     *    notice, this list of conditions and the following disclaimer.
013     *
014     * 2. Redistributions in binary form must reproduce the above copyright
015     *    notice, this list of conditions and the following disclaimer in
016     *    the documentation and/or other materials provided with the
017     *    distribution.
018     *
019     * 3. The end-user documentation included with the redistribution,
020     *    if any, must include the following acknowledgment:
021     *       "This product includes software developed by the
022     *        Apache Software Foundation (http://www.apache.org/)."
023     *    Alternately, this acknowledgment may appear in the software itself,
024     *    if and wherever such third-party acknowledgments normally appear.
025     *
026     * 4. The names "The Jakarta Project", "Commons", and "Apache Software
027     *    Foundation" must not be used to endorse or promote products derived
028     *    from this software without prior written permission. For written
029     *    permission, please contact apache@apache.org.
030     *
031     * 5. Products derived from this software may not be called "Apache",
032     *    nor may "Apache" appear in their name, without prior written
033     *    permission of the Apache Software Foundation.
034     *
035     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038     * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046     * SUCH DAMAGE.
047     * ====================================================================
048     *
049     * This software consists of voluntary contributions made by many
050     * individuals on behalf of the Apache Software Foundation.  For more
051     * information on the Apache Software Foundation, please see
052     * <http://www.apache.org/>.
053     *
054     */
055    package org.jpu.patterns.singleton.onePerContext;
056    
057    import java.util.ArrayList;
058    import java.util.HashMap;
059    import java.util.HashSet;
060    import java.util.Iterator;
061    import java.util.List;
062    import java.util.Map;
063    import java.util.Set;
064    import java.util.WeakHashMap;
065    
066    import org.apache.commons.lang.exception.NestableRuntimeException;
067    import org.apache.commons.logging.Log;
068    import org.apache.commons.logging.LogFactory;
069    
070    /**
071     * This class and its associated interfaces implement
072     * a pattern that is a variant of Singleton intended for situations where you
073     * need one instance of the class per "context", rather than one per classloader as is the
074     * case with traditional singletons.  A context can be any object of your choice, but can
075     * optionally implement {@link IContext} if if it wishes to be notified when objects are
076     * created on its behalf.
077     * <p>
078     * To use it, have your class provide an accessible no-arg constructor, and declare a private
079     * static field like this:
080     * <blockquote>
081     * <code>
082     *     private static OnePerContextManager _opcMgr = new OnePerContextManager(<b><i>C</i></b>.class);
083     * </code>
084     * </blockquote>
085     * where <b><i>C</i></b> is the name of your class.  When you want an instance of it, call
086     * <blockquote>
087     * <code>
088     *     (<b><i>C</i></b>)_opcMgr.getInstance(ctx);
089     * </code>
090     * </blockquote>
091     * where <code>ctx</code> is the context.  Typically you would wrap the above call in a public static 
092     * method of <b><i>C</i></b> like this:
093     * <blockquote>
094     * <code>
095     *     public static <b><i>C</i></b> getInstance(Object ctx) {
096     *         return (<b><i>C</i></b>)_opcMgr.getInstance(ctx);
097     *     }
098     * </code>
099     * </blockquote>
100     * The class may then be treated much like a singleton, except that one instance will be 
101     * maintained <i>per context</i>, instead of one per classloader.  Note <code>ctx</code>
102     * can be <code>null</code>, in which case it defaults to <code><b><i>C</i></b>.class</code>,
103     * which provides traditional singleton behavior with one instance per classloader.
104     * <p>
105     * <b>Custom Instantiation</b><br>
106     * By default the no-arg constructor of the class passed to the constructor is used to generate
107     * the One-Per-Context instances.  However you can change this behavior in either of two ways: 1) have the
108     * context implement {@link IContext} and define a {@link IContext#newInstance} method that 
109     * instantiates the One-Per-Context and returns it; or 2) write your own {@link IOnePerContextManager.IInstantiator} and 
110     * set it via {@link IOnePerContextManager#setInstantiator}.  Method (1) takes precedence, so if 
111     * {@link IContext#newInstance} returns non-null, its return value will be used as the One-Per-Context
112     * instance and the instantiator will not be called.   
113     * <p>
114     * Method (2) is generally intended for use by
115     * the One-Per-Context class itself to control its own instantiation, while Method (1) is intended
116     * for use by clients of the One-Per-Context class who need to substitute their own subclass
117     * implementation for use in particular contexts.  
118     * <p>
119     * <b>Custom Initialization</b><br>
120     * If you want each One-Per-Context instance to be notified of its associated 
121     * context, you can have it implement {@link IOnePerContext} and implement the
122     * {@link IOnePerContext#initOnePerContext} method.  The method will be called
123     * on newly-created One-Per-Context's.
124     * <p>
125     * You can also perform custom initialization of One-Per-Context's by writing your own
126     * {@link IOnePerContextManager.IInitializer} and adding it via {@link IOnePerContextManager#addInitializer}.  You can
127     * register as many initializers as you want, and they will be called in order on each newly
128     * created One-Per-Context instance.  This sort of initialization is performed immediately
129     * <i>after</i> that described in the previous paragraph.
130     * <p>
131     * A third type of custom initialization can be performed by the context.  To have the context 
132     * be notified when a new One-Per-Context is created on its behalf,
133     * have it implement {@link IContext} and override {@link IContext#initialize}.  This
134     * method will be called immediately <i>after</i> that described in the previous paragraph.
135     * <p>
136     * <b>Thread local Contexts</b><br>
137     * To avoid the necessity of passing around context references, you might want
138     * to hold the context as a <code>ThreadLocal</code> and adjust its value when
139     * you want to change contexts.  The code might look something like this:
140     * <pre><code> 
141     *     public class Foo {
142     *          public static final Object DEFAULT_CTX = new Object();
143     *          public static Foo getInstance() {
144     *              return (Foo)_opcMgr.getInstance( _ctx.get() );
145     *          }
146     *          public static void setCtx(Object ctx) {
147     *              _ctx.set(ctx);
148     *          }
149     *          private static ThreadLocal _ctx = new ThreadLocal() {
150     *              protected Object initialValue() { return DEFAULT_CTX; }
151     *          };
152     *          private static OnePerContextManager _opcMgr = new OnePerContextManager(Foo.class);
153     *     }</code></pre>
154     * For the full example see the source code of {@link org.jpu.patterns.singleton.onePerContext.test.Foo} 
155     * (source is included in the Javadoc's).
156     * <p>
157     * <b>Context References</b><br>
158     * The One-Per-Context facility supports both weak and strong holding of 
159     * context references.  Strong referencing can be requested by passing <code>true</code>
160     * as the second parameter to {@link OnePerContextManager#OnePerContextManager(Class,boolean)}.  If weak referencing 
161     * is requested (which is the default if the second parameter is omitted), the 
162     * facility's internal data structures will not prevent garbage collection of the context.  When 
163     * the context is garbage collected, all One-Per-Context's associated with it
164     * become inaccessible through this facility (though of course the application may yet 
165     * retain other references to them).
166     * <p>
167     */
168    public class OnePerContextManager implements IOnePerContextManager {
169    
170        /**
171             * Default implementation of {@link IOnePerContextManager.IInstantiator}.  Its {@link IOnePerContextManager.IInstantiator#newInstance} method 
172             * simply calls "<code>onePerContextClass.newInstance()</code>".
173         */
174        public static class DefaultInstantiator implements IInstantiator {
175            public Object newInstance(IOnePerContextManager mgr, Object ctx) {
176                try {
177                    Object onePerContext = (Object)mgr.getOnePerContextClass().newInstance();
178                    return onePerContext;
179                }
180                catch( Throwable t ) {
181                    throw new NestableRuntimeException(t);
182                }
183            }
184        }
185    
186        /**
187         */
188        public static List findManagersByClass(Class opcClass) {
189            return findManagersByClass(opcClass, true);
190        }
191    
192        /**
193         */
194        public static List findManagersByClass(Class opcClass, boolean exact) {
195            synchronized(_managers) {
196                List result = new ArrayList();
197                Iterator it = _managers.keySet().iterator();
198                while ( it.hasNext() ) {
199                    OnePerContextManager mgr = (OnePerContextManager)it.next();
200                    synchronized(mgr) {
201                        if ( (exact && mgr.getOnePerContextClass().equals(opcClass)) ||
202                             opcClass.isAssignableFrom( mgr.getOnePerContextClass() ) ) {
203                            result.add(mgr);
204                        }
205                    }
206                }
207                return result;
208            }
209        }
210    
211        /**
212         * Returns the set of all currently active <code>OnePerContextManager</code>'s.  The returned
213         * set is a shallow copy of the internal data structure, so the caller can modify it at will.
214         */
215        public static Set getManagers() {
216            synchronized(_managers) {
217                Set mgrs = new HashSet();
218                mgrs.addAll( _managers.keySet() );
219                return mgrs;
220            }
221        }
222    
223        /**
224         * Alias for "<code>OnePerContextManager(onePerContextClass, false)</code>".
225         */
226        public OnePerContextManager( Class onePerContextClass ) {
227            this(onePerContextClass, false);
228        }
229    
230        /**
231         * Constructor.
232         *
233         * @param onePerContextClass The class of One-Per-Context's that will be created by subsequent calls to
234         * {@link #getInstance(Object)}.
235         * 
236         * @param strong Indicates whether references to newly-created instances should
237         * be held strongly or weakly.  If the context defines <code>equals()</code> and <code>hashCode()</code> in terms of 
238         * object identity, this should usually be <code>false</code>; else it should be <code>true</code>.  For instance if the 
239         * context is a <code>String</code> or a primitive type, <code>strong</code> should be <code>true</code>.
240         */
241        public OnePerContextManager( Class onePerContextClass, boolean strong ) {
242            _onePerContextClass = onePerContextClass;
243            synchronized(_managers) {
244                _managers.put(this, "");
245            }
246            if ( strong ) {
247                _objects = new HashMap();
248            }
249            else {
250                _objects = new WeakHashMap();
251            }
252        }
253    
254            // See interface documentation.
255        public synchronized Class getOnePerContextClass() {
256            return _onePerContextClass;
257        }
258    
259            // See interface documentation.
260        public synchronized Map getObjects() {
261            Map map = new HashMap();
262            map.putAll( _objects );
263            return map;
264        }
265    
266            // See interface documentation.
267        public synchronized List getInitializers() {
268            List list = new ArrayList();
269            list.addAll( _initializers );
270            return list;
271        }
272    
273            // See interface documentation.
274        public synchronized void addInitializer(int i, IInitializer initializer) {
275            _initializers.add(i, initializer);
276        }
277    
278            // See interface documentation.
279        public synchronized IInitializer removeInitializer(int i) {
280            return (IInitializer)_initializers.remove(i);
281        }
282    
283            // See interface documentation.
284        public synchronized boolean removeInitializer(IInitializer ini) {
285            return _initializers.remove(ini);
286        }
287    
288            // See interface documentation.
289        public synchronized IInstantiator getInstantiator() {
290            return _instantiator;
291        }
292    
293            // See interface documentation.
294        public synchronized void setInstantiator(IInstantiator i) {
295            _instantiator = i;
296        }
297    
298            protected Object getDefaultContext() {
299                    return IOnePerContextManager.DEFAULT_CONTEXT;
300            }
301    
302            // See interface documentation.
303        public synchronized Object getInstance( Object ctx ) {
304    
305            if ( ctx == null ) {
306                ctx = getDefaultContext();
307            }
308            Object onePerContext = (Object)_objects.get(ctx);
309            if ( onePerContext == null ) {
310                            if ( ctx instanceof IContext ) {
311                                    IContext myCtx = (IContext)ctx;
312                                    onePerContext = myCtx.newInstance( this );
313                            }
314                            if ( onePerContext == null ) {
315                                    onePerContext = getInstantiator().newInstance(this, ctx);
316                            }
317                            if ( onePerContext == null ) {
318                                    throw new IllegalArgumentException( "Instantiator returned null during instantiation of '" + getOnePerContextClass().getName() + "'" );
319                            }
320                            if ( onePerContext instanceof IOnePerContext ) {
321                                    IOnePerContext myOnePerContext = (IOnePerContext)onePerContext;
322                                    myOnePerContext.initOnePerContext(ctx);
323                            }
324                Iterator it = _initializers.iterator();
325                while ( it.hasNext() ) {
326                    IInitializer initializer = (IInitializer)it.next();
327                    initializer.initialize(this, ctx, onePerContext);
328                }
329                            if ( ctx instanceof IContext ) {
330                                    IContext myCtx = (IContext)ctx;
331                                    myCtx.initialize(this, onePerContext);
332                            }
333                _objects.put(ctx, onePerContext);
334            }
335            return onePerContext;
336        }
337    
338        private IInstantiator _instantiator = new DefaultInstantiator();
339        private Map _objects = null;
340        private List _initializers = new ArrayList();
341        private Class _onePerContextClass = null;
342        private static Map _managers = new WeakHashMap();
343        private static Log _log = LogFactory.getLog(OnePerContextManager.class); 
344    }