001    /*
002     * (c) 2004, 2005, 2009, 2010 ThoughtWorks Ltd
003     * All rights reserved.
004     *
005     * The software in this package is published under the terms of the BSD
006     * style license a copy of which has been included with this distribution in
007     * the LICENSE.txt file.
008     * 
009     * Created on 01-Jul-2004
010     */
011    package com.thoughtworks.proxy.toys.pool;
012    
013    import java.io.ByteArrayOutputStream;
014    import java.io.IOException;
015    import java.io.NotSerializableException;
016    import java.io.ObjectInputStream;
017    import java.io.ObjectOutputStream;
018    import java.io.Serializable;
019    import java.lang.ref.WeakReference;
020    import java.lang.reflect.Method;
021    import java.util.ArrayList;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Map;
026    
027    import com.thoughtworks.proxy.ProxyFactory;
028    import com.thoughtworks.proxy.factory.InvokerReference;
029    import com.thoughtworks.proxy.factory.StandardProxyFactory;
030    import com.thoughtworks.proxy.kit.NoOperationResetter;
031    import com.thoughtworks.proxy.kit.ObjectReference;
032    import com.thoughtworks.proxy.kit.Resetter;
033    import com.thoughtworks.proxy.kit.SimpleReference;
034    import com.thoughtworks.proxy.toys.delegate.DelegatingInvoker;
035    import com.thoughtworks.proxy.toys.delegate.DelegationMode;
036    
037    /**
038     * A simple pool implementation that collects its unused components of a specific type automatically.
039     * <p>
040     * The pool will only manage instances that were explicitly passed into the pool before. For more sophisticated pooling
041     * strategies, derive from this class or wrap it.
042     * </p>
043     * <p>
044     * The implementation will provide these instances wrapped by a proxy, that will return the instance automatically to
045     * the pool, if it falls out of scope and is collected by the garbage collector. Since the pool only returns instances
046     * wrapped by a proxy that implements the {@link Poolable} interface, this can be used to release the instance manually
047     * to the pool also. With an implementation of the {@link Resetter} interface each element's status can be reset or the
048     * element can be dropped from the pool at all, if it is exhausted.
049     * </p>
050     * <p>
051     * A client can use the pool's monitor for an improved synchronization. Every time an object is returned to the pool, all
052     * waiting Threads of the monitor will be notified. This notification will happen independently of the result of the
053     * {@link Resetter#reset(Object)} method.
054     * </p>
055     * <p>
056     * A Pool instance can be created as usual with a builder, but also using various constructors to support dependency
057     * injection.
058     * </p>
059     *
060     * @author J&ouml;rg Schaible
061     * @author Paul Hammant
062     * @see com.thoughtworks.proxy.toys.pool
063     * @since 0.2
064     */
065    public class Pool<T> implements Serializable {
066        private static final long serialVersionUID = 1L;
067        private static final Method returnInstanceToPool;
068    
069        static {
070            try {
071                returnInstanceToPool = Poolable.class.getMethod("returnInstanceToPool");
072            } catch (NoSuchMethodException e) {
073                throw new ExceptionInInitializerError(e.toString());
074            }
075        }
076    
077        private Class<?> types[];
078        private ProxyFactory factory;
079        private transient Map<T, WeakReference<T>> busyInstances;
080        private transient List<ObjectReference<T>> availableInstances;
081        private Resetter<? super T> resetter;
082        private SerializationMode serializationMode = SerializationMode.STANDARD;
083    
084        /**
085         * Creates a factory for a pool instance which proxy the managed elements in the pool.
086         * 
087         * @param type the type of the instances
088         * @return return the pool with parameters specified
089         * @since 1.0
090         */
091        public static <T> PoolResettedBy<T> create(Class<T> type) {
092            return new PoolResettedBy<T>(new Pool<T>(type, new NoOperationResetter<T>()));
093        }
094        
095        public static class PoolBuild<T> {
096    
097            protected Pool<T> pool;
098    
099            private PoolBuild(Pool<T> pool) {
100                this.pool = pool;
101            }
102    
103            /**
104             * Build the pool using the {@link StandardProxyFactory}.
105             *
106             * @return the pool with predefined instances
107             * @since 1.0
108             */
109            public Pool<T> build() {
110                return build(new StandardProxyFactory());
111            }
112    
113            /**
114             * Build the pool using a special {@link ProxyFactory}.
115             *
116             * @param factory the proxy factory to use
117             * @return the pool with predefined instances
118             * @since 0.2
119             */
120            public Pool<T> build(ProxyFactory factory) {
121                pool.factory = factory;
122                return pool;
123            }
124        }
125    
126        public static class PoolResettedBy<T> extends PoolWith<T> {
127            private PoolResettedBy(Pool<T> pool) {
128                super(pool);
129            }
130    
131            public PoolWith<T> resettedBy(Resetter<? super T> resetter) {
132                pool.resetter = resetter;
133                return new PoolWith<T>(pool);
134            }
135        }
136    
137        public static class PoolWith<T> extends PoolModeOrBuild<T> {
138            private PoolWith(Pool<T> pool) {
139                super(pool);
140            }
141    
142            public PoolModeOrBuild<T> with(T... instances) {
143                pool.add(instances);
144                return new PoolModeOrBuild<T>(pool);
145            }
146        }
147    
148        public static class PoolModeOrBuild<T> extends PoolBuild<T> {
149    
150            private PoolModeOrBuild(Pool<T> pool) {
151                super(pool);
152            }
153    
154            /**
155             * Specify the serializationMode
156             * <ul>
157             * <li>{@link SerializationMode#STANDARD}: the standard mode, i.e. all elements of the
158             * pool are also serialized and a {@link NotSerializableException} may thrown</li>
159             * <li>{@link SerializationMode#NONE}: no element of the pool is also serialized and it
160             * must be populated again after serialization</li>
161             * <li>{@link SerializationMode#FORCE}: all element of the pool are serialized, if
162             * possible. Otherwise the pool is empty after serialization and must be populated
163             * again.</li>
164             * </ul>
165             * 
166             * @param serializationMode
167             * @return the pool with a certain serialization mode
168             * @throws IllegalArgumentException if the serialization mode is not one of the
169             *             predefined values
170             * @since 0.2
171             */
172            public PoolBuild<T> mode(SerializationMode serializationMode) {
173                pool.serializationMode = serializationMode;
174                return new PoolBuild<T>(pool);
175            }
176        }
177    
178        /**
179         * Construct an Pool using the {@link StandardProxyFactory} for elements that do not have to
180         * be resetted.
181         * 
182         * @param type the type of the instances
183         * @since 1.0
184         */
185        public Pool(final Class<T> type) {
186            this(type, new NoOperationResetter<T>(), new StandardProxyFactory());
187        }
188        
189        /**
190         * Construct an Pool using the {@link StandardProxyFactory}.
191         *
192         * @param type         the type of the instances
193         * @param resetter     the resetter of the pooled elements
194         * @since 0.2
195         */
196        public Pool(final Class<T> type, final Resetter<? super T> resetter) {
197            this(type, resetter, new StandardProxyFactory());
198        }
199    
200        /**
201         * Construct a populated Pool with a specific proxy factory for elements that do not have to
202         * be resetted.
203         * 
204         * @param type the type of the instances
205         * @param proxyFactory the proxy factory to use
206         * @since 1.0
207         */
208        public Pool(final Class<T> type, final ProxyFactory proxyFactory) {
209            this(type, new NoOperationResetter<T>(), proxyFactory, SerializationMode.STANDARD);
210        }
211    
212        /**
213         * Construct a populated Pool with a specific proxy factory.
214         * 
215         * @param type the type of the instances
216         * @param resetter the resetter of the pooled elements
217         * @param proxyFactory the proxy factory to use
218         * @since 0.2
219         */
220        public Pool(final Class<T> type, final Resetter<? super T> resetter, final ProxyFactory proxyFactory) {
221            this(type, resetter, proxyFactory, SerializationMode.STANDARD);
222        }
223    
224        /**
225         * Construct a populated Pool with a specific proxy factory and a serialization mode. This
226         * mode specify the behavior in case of a serialization of the Pool:
227         * <ul>
228         * <li>{@link SerializationMode#STANDARD}: the standard mode, i.e. all elements of the pool
229         * are also serialized and a {@link NotSerializableException} may thrown</li>
230         * <li>{@link SerializationMode#NONE}: no element of the pool is also serialized and it must
231         * be populated again after serialization</li>
232         * <li>{@link SerializationMode#FORCE}: all element of the pool are serialized, if possible.
233         * Otherwise the pool is empty after serialization and must be populated again.</li>
234         * </ul>
235         * 
236         * @param type the type of the instances
237         * @param resetter the resetter of the pooled elements
238         * @param proxyFactory the proxy factory to use
239         * @param mode the serialization mode.
240         * @since 1.0
241         */
242        public Pool(final Class<T> type, final Resetter<? super T> resetter, final ProxyFactory proxyFactory, final SerializationMode mode) {
243            this();
244            this.types = new Class[]{type, Poolable.class};
245            this.resetter = resetter;
246            this.factory = proxyFactory;
247            this.serializationMode = mode;
248        }
249        
250        private Pool() {
251            busyInstances = new HashMap<T, WeakReference<T>>();
252            availableInstances = new ArrayList<ObjectReference<T>>();
253        }
254    
255        /**
256         * Add an array of new instances as resources to the pool. The pool's monitor will be notified.
257         *
258         * @param instances the instances
259         * @throws NullPointerException if instance is <code>null</code>
260         * @since 0.2
261         */
262        public synchronized void add(final T... instances) {
263            if (instances != null) {
264                for (T instance : instances) {
265                    if (instance == null) {
266                        throw new NullPointerException();
267                    }
268                    availableInstances.add(new SimpleReference<T>(instance));
269                }
270                notifyAll();
271            }
272        }
273    
274        /**
275         * Get an instance from the pool. If no instance is immediately available, the method will check internally for
276         * returned objects from the garbage collector. This can be forced by calling {@link System#gc()} first.
277         *
278         * @return an available instance from the pool or <em>null</em>.
279         * @since 0.2
280         */
281        public synchronized T get() {
282            final T result;
283            if (availableInstances.size() > 0 || getAvailable() > 0) {
284                final ObjectReference<T> delegate = availableInstances.remove(0);
285                result = new PoolingInvoker<T>(this, factory, delegate, DelegationMode.DIRECT).proxy();
286                final WeakReference<T> weakReference = new WeakReference<T>(result);
287                busyInstances.put(delegate.get(), weakReference);
288            } else {
289                result = null;
290            }
291            return result;
292        }
293    
294        /**
295         * Release a pool instance manually.
296         *
297         * @param object the instance to release
298         * @throws ClassCastException       if object was not {@link Poolable}.
299         * @throws IllegalArgumentException if the object was not from this pool.
300         * @since 0.2
301         */
302        public void release(final T object) {
303            final Poolable poolable = Poolable.class.cast(object);
304            @SuppressWarnings("unchecked")
305            final PoolingInvoker<T> invoker = PoolingInvoker.class.cast(InvokerReference.class.cast(poolable).getInvoker());
306            if (this != invoker.getPoolInstance()) {
307                throw new IllegalArgumentException("Release object from different pool");
308            }
309            poolable.returnInstanceToPool();
310        }
311    
312        /**
313         * Return the number of available instances of the pool. The method will also try to collect any pool instance that
314         * was freed by the garbage collector. This can be forced by calling {@link System#gc()} first. The pool's monitor
315         * will be notified, if any object was collected and the {@link Resetter} returned the object.
316         *
317         * @return the number of available instances.
318         * @since 0.2
319         */
320        public synchronized int getAvailable() {
321            if (busyInstances.size() > 0) {
322                final List<T> freedInstances = new ArrayList<T>();
323                for (final T target : busyInstances.keySet()) {
324                    final WeakReference<T> ref = busyInstances.get(target);
325                    if (ref.get() == null) {
326                        freedInstances.add(target);
327                    }
328                }
329                final List<ObjectReference<T>> resettedInstances = new ArrayList<ObjectReference<T>>();
330                for (final T element : freedInstances) {
331                    busyInstances.remove(element);
332                    if (resetter.reset(element)) {
333                        resettedInstances.add(new SimpleReference<T>(element));
334                    }
335                }
336                availableInstances.addAll(resettedInstances);
337                if (freedInstances.size() > 0) {
338                    notifyAll();
339                }
340            }
341            return availableInstances.size();
342        }
343    
344        /**
345         * Retrieve the number of instances managed by the pool.
346         *
347         * @return the number of instances.
348         * @since 0.2
349         */
350        public synchronized int size() {
351            return availableInstances.size() + busyInstances.size();
352        }
353    
354        private synchronized void returnInstanceToPool(final ObjectReference<T> reference) {
355            busyInstances.remove(reference.get());
356            if (resetter.reset(reference.get())) {
357                availableInstances.add(reference);
358            }
359            notifyAll();
360        }
361    
362        private synchronized void writeObject(final ObjectOutputStream out) throws IOException {
363            out.defaultWriteObject();
364            final List<ObjectReference<T>> instances = new ArrayList<ObjectReference<T>>(availableInstances);
365            Iterator<T> iter;
366            for (iter = busyInstances.keySet().iterator(); iter.hasNext();) {
367                instances.add(new SimpleReference<T>(iter.next()));
368            }
369            SerializationMode mode = serializationMode;
370            if (mode == SerializationMode.FORCE) {
371                try {
372                    final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
373                    final ObjectOutputStream testStream = new ObjectOutputStream(buffer);
374                    testStream.writeObject(instances); // force NotSerializableException
375                    testStream.close();
376                    mode = SerializationMode.STANDARD;
377                } catch (final NotSerializableException e) {
378                    mode = SerializationMode.NONE;
379                }
380            }
381            if (mode == SerializationMode.STANDARD) {
382                out.writeObject(instances);
383            } else {
384                out.writeObject(new ArrayList<ObjectReference<T>>());
385            }
386        }
387    
388        private synchronized void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
389            in.defaultReadObject();
390            @SuppressWarnings("unchecked")
391            final List<ObjectReference<T>> list = List.class.cast(in.readObject());
392            availableInstances = list;
393            busyInstances = new HashMap<T, WeakReference<T>>();
394        }
395    
396        /**
397         * The {@link com.thoughtworks.proxy.Invoker} of the proxy.
398         *
399         * @since 0.2
400         */
401        protected static class PoolingInvoker<T> extends DelegatingInvoker<T> {
402            private static final long serialVersionUID = 1L;
403    
404            // explicit reference for serialization via reflection
405            private Pool<T> pool;
406    
407            /**
408             * Construct a PoolingInvoker.
409             *
410             * @param pool              the corresponding {@link Pool}
411             * @param proxyFactory      the {@link ProxyFactory} to use
412             * @param delegateReference the {@link ObjectReference} with the delegate
413             * @param delegationMode    one of the {@linkplain DelegationMode delegation modes}
414             * @since 1.0
415             */
416            protected PoolingInvoker(
417                    Pool<T> pool, ProxyFactory proxyFactory, ObjectReference<T> delegateReference, DelegationMode delegationMode) {
418                super(proxyFactory, delegateReference, delegationMode);
419                this.pool = pool;
420            }
421    
422            @Override
423            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
424                Object result;
425                if (method.equals(returnInstanceToPool)) {
426                    returnInstanceToPool();
427                    result = Void.TYPE; 
428                } else
429                    result = super.invoke(proxy, method, args);
430                return result;
431            }
432    
433            /**
434             * Return the current instance to the pool. The pool's monitor will be notified, if the {@link Resetter} returns
435             * the object.
436             *
437             * @since 0.2
438             */
439            public void returnInstanceToPool() {
440                pool.returnInstanceToPool(getDelegateReference());
441            }
442    
443            /**
444             * Create a proxy for the types of the pool.
445             *
446             * @return the new proxy instance
447             * @since 0.2
448             */
449            protected T proxy() {
450                return getProxyFactory().<T>createProxy(this, pool.types);
451            }
452    
453            private Pool<T> getPoolInstance() {
454                return pool;
455            }
456        }
457    }