KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > pool > impl > GenericKeyedObjectPool


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.pool.impl;
18
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.ListIterator JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.NoSuchElementException JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.TreeMap JavaDoc;
26
27 import org.apache.commons.collections.CursorableLinkedList;
28 import org.apache.commons.pool.BaseKeyedObjectPool;
29 import org.apache.commons.pool.KeyedObjectPool;
30 import org.apache.commons.pool.KeyedPoolableObjectFactory;
31
32 /**
33  * A configurable {@link KeyedObjectPool} implementation.
34  * <p>
35  * When coupled with the appropriate {@link KeyedPoolableObjectFactory},
36  * <tt>GenericKeyedObjectPool</tt> provides robust pooling functionality for
37  * arbitrary objects.
38  * <p>
39  * A <tt>GenericKeyedObjectPool</tt> provides a number of configurable parameters:
40  * <ul>
41  * <li>
42  * {@link #setMaxActive <i>maxActive</i>} controls the maximum number of objects (per key)
43  * that can be borrowed from the pool at one time. When non-positive, there
44  * is no limit to the number of objects that may be active at one time.
45  * When {@link #setMaxActive <i>maxActive</i>} is exceeded, the pool is said to be exhausted.
46  * </li>
47  * <li>
48  * {@link #setMaxIdle <i>maxIdle</i>} controls the maximum number of objects that can
49  * sit idle in the pool (per key) at any time. When negative, there
50  * is no limit to the number of objects that may be idle at one time.
51  * </li>
52  * <li>
53  * {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} specifies the
54  * behaviour of the {@link #borrowObject} method when the pool is exhausted:
55  * <ul>
56  * <li>
57  * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
58  * {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject} will throw
59  * a {@link NoSuchElementException}
60  * </li>
61  * <li>
62  * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
63  * {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject} will create a new
64  * object and return it(essentially making {@link #setMaxActive <i>maxActive</i>}
65  * meaningless.)
66  * </li>
67  * <li>
68  * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>}
69  * is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject} will block
70  * (invoke {@link Object#wait} until a new or idle object is available.
71  * If a positive {@link #setMaxWait <i>maxWait</i>}
72  * value is supplied, the {@link #borrowObject} will block for at
73  * most that many milliseconds, after which a {@link NoSuchElementException}
74  * will be thrown. If {@link #setMaxWait <i>maxWait</i>} is non-positive,
75  * the {@link #borrowObject} method will block indefinitely.
76  * </li>
77  * </ul>
78  * </li>
79  * <li>
80  * When {@link #setTestOnBorrow <i>testOnBorrow</i>} is set, the pool will
81  * attempt to validate each object before it is returned from the
82  * {@link #borrowObject} method. (Using the provided factory's
83  * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject} method.) Objects that fail
84  * to validate will be dropped from the pool, and a different object will
85  * be borrowed.
86  * </li>
87  * <li>
88  * When {@link #setTestOnReturn <i>testOnReturn</i>} is set, the pool will
89  * attempt to validate each object before it is returned to the pool in the
90  * {@link #returnObject} method. (Using the provided factory's
91  * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject}
92  * method.) Objects that fail to validate will be dropped from the pool.
93  * </li>
94  * </ul>
95  * <p>
96  * Optionally, one may configure the pool to examine and possibly evict objects as they
97  * sit idle in the pool. This is performed by an "idle object eviction" thread, which
98  * runs asychronously. The idle object eviction thread may be configured using the
99  * following attributes:
100  * <ul>
101  * <li>
102  * {@link #setTimeBetweenEvictionRunsMillis <i>timeBetweenEvictionRunsMillis</i>}
103  * indicates how long the eviction thread should sleep before "runs" of examining
104  * idle objects. When non-positive, no eviction thread will be launched.
105  * </li>
106  * <li>
107  * {@link #setMinEvictableIdleTimeMillis <i>minEvictableIdleTimeMillis</i>}
108  * specifies the minimum amount of time that an object may sit idle in the pool
109  * before it is eligable for eviction due to idle time. When non-positive, no object
110  * will be dropped from the pool due to idle time alone.
111  * </li>
112  * <li>
113  * {@link #setTestWhileIdle <i>testWhileIdle</i>} indicates whether or not idle
114  * objects should be validated using the factory's
115  * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject} method. Objects
116  * that fail to validate will be dropped from the pool.
117  * </li>
118  * </ul>
119  * <p>
120  * GenericKeyedObjectPool is not usable without a {@link KeyedPoolableObjectFactory}. A
121  * non-<code>null</code> factory must be provided either as a constructor argument
122  * or via a call to {@link #setFactory} before the pool is used.
123  * </p>
124  * @see GenericObjectPool
125  * @author Rodney Waldhoff
126  * @author Dirk Verbeeck
127  * @version $Revision$ $Date: 2005-02-26 05:13:28 -0800 (Sat, 26 Feb 2005) $
128  */

129 public class GenericKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
130
131     //--- public constants -------------------------------------------
132

133     /**
134      * A "when exhausted action" type indicating that when the pool is
135      * exhausted (i.e., the maximum number of active objects has
136      * been reached), the {@link #borrowObject}
137      * method should fail, throwing a {@link NoSuchElementException}.
138      * @see #WHEN_EXHAUSTED_BLOCK
139      * @see #WHEN_EXHAUSTED_GROW
140      * @see #setWhenExhaustedAction
141      */

142     public static final byte WHEN_EXHAUSTED_FAIL = 0;
143
144     /**
145      * A "when exhausted action" type indicating that when the pool
146      * is exhausted (i.e., the maximum number
147      * of active objects has been reached), the {@link #borrowObject}
148      * method should block until a new object is available, or the
149      * {@link #getMaxWait maximum wait time} has been reached.
150      * @see #WHEN_EXHAUSTED_FAIL
151      * @see #WHEN_EXHAUSTED_GROW
152      * @see #setMaxWait
153      * @see #getMaxWait
154      * @see #setWhenExhaustedAction
155      */

156     public static final byte WHEN_EXHAUSTED_BLOCK = 1;
157
158     /**
159      * A "when exhausted action" type indicating that when the pool is
160      * exhausted (i.e., the maximum number
161      * of active objects has been reached), the {@link #borrowObject}
162      * method should simply create a new object anyway.
163      * @see #WHEN_EXHAUSTED_FAIL
164      * @see #WHEN_EXHAUSTED_GROW
165      * @see #setWhenExhaustedAction
166      */

167     public static final byte WHEN_EXHAUSTED_GROW = 2;
168
169     /**
170      * The default cap on the number of idle instances in the pool
171      * (per key).
172      * @see #getMaxIdle
173      * @see #setMaxIdle
174      */

175     public static final int DEFAULT_MAX_IDLE = 8;
176
177     /**
178      * The default cap on the total number of active instances from the pool
179      * (per key).
180      * @see #getMaxActive
181      * @see #setMaxActive
182      */

183     public static final int DEFAULT_MAX_ACTIVE = 8;
184
185     /**
186      * The default cap on the the maximum number of objects that can exists at one time.
187      * @see #getMaxTotal
188      * @see #setMaxTotal
189      */

190     public static final int DEFAULT_MAX_TOTAL = -1;
191
192     /**
193      * The default "when exhausted action" for the pool.
194      * @see #WHEN_EXHAUSTED_BLOCK
195      * @see #WHEN_EXHAUSTED_FAIL
196      * @see #WHEN_EXHAUSTED_GROW
197      * @see #setWhenExhaustedAction
198      */

199     public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = WHEN_EXHAUSTED_BLOCK;
200
201     /**
202      * The default maximum amount of time (in millis) the
203      * {@link #borrowObject} method should block before throwing
204      * an exception when the pool is exhausted and the
205      * {@link #getWhenExhaustedAction "when exhausted" action} is
206      * {@link #WHEN_EXHAUSTED_BLOCK}.
207      * @see #getMaxWait
208      * @see #setMaxWait
209      */

210     public static final long DEFAULT_MAX_WAIT = -1L;
211
212     /**
213      * The default "test on borrow" value.
214      * @see #getTestOnBorrow
215      * @see #setTestOnBorrow
216      */

217     public static final boolean DEFAULT_TEST_ON_BORROW = false;
218
219     /**
220      * The default "test on return" value.
221      * @see #getTestOnReturn
222      * @see #setTestOnReturn
223      */

224     public static final boolean DEFAULT_TEST_ON_RETURN = false;
225
226     /**
227      * The default "test while idle" value.
228      * @see #getTestWhileIdle
229      * @see #setTestWhileIdle
230      * @see #getTimeBetweenEvictionRunsMillis
231      * @see #setTimeBetweenEvictionRunsMillis
232      */

233     public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
234
235     /**
236      * The default "time between eviction runs" value.
237      * @see #getTimeBetweenEvictionRunsMillis
238      * @see #setTimeBetweenEvictionRunsMillis
239      */

240     public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
241
242     /**
243      * The default number of objects to examine per run in the
244      * idle object evictor.
245      * @see #getNumTestsPerEvictionRun
246      * @see #setNumTestsPerEvictionRun
247      * @see #getTimeBetweenEvictionRunsMillis
248      * @see #setTimeBetweenEvictionRunsMillis
249      */

250     public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
251
252     /**
253      * The default value for {@link #getMinEvictableIdleTimeMillis}.
254      * @see #getMinEvictableIdleTimeMillis
255      * @see #setMinEvictableIdleTimeMillis
256      */

257     public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
258
259     /**
260      * The default minimum level of idle objects in the pool.
261      * @see #setMinIdle
262      * @see #getMinIdle
263      */

264     public static final int DEFAULT_MIN_IDLE = 0;
265     
266     //--- constructors -----------------------------------------------
267

268     /**
269      * Create a new <tt>GenericKeyedObjectPool</tt>..
270      */

271     public GenericKeyedObjectPool() {
272         this(null,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
273     }
274
275     /**
276      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
277      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
278      */

279     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) {
280         this(factory,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
281     }
282
283     /**
284      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
285      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
286      * @param config a non-<tt>null</tt> {@link GenericKeyedObjectPool.Config} describing my configuration
287      */

288     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, GenericKeyedObjectPool.Config config) {
289         this(factory,config.maxActive,config.whenExhaustedAction,config.maxWait,config.maxIdle,config.maxTotal,config.testOnBorrow,config.testOnReturn,config.timeBetweenEvictionRunsMillis,config.numTestsPerEvictionRun,config.minEvictableIdleTimeMillis,config.testWhileIdle);
290     }
291
292     /**
293      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
294      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
295      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
296      */

297     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive) {
298         this(factory,maxActive,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
299     }
300
301     /**
302      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
303      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
304      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
305      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
306      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
307      */

308     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait) {
309         this(factory,maxActive,whenExhaustedAction,maxWait,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
310     }
311
312     /**
313      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
314      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
315      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
316      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
317      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
318      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
319      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
320      */

321     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, boolean testOnBorrow, boolean testOnReturn) {
322         this(factory,maxActive,whenExhaustedAction,maxWait,DEFAULT_MAX_IDLE,testOnBorrow,testOnReturn,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
323     }
324
325     /**
326      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
327      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
328      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
329      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
330      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
331      * @param maxIdle the maximum number of idle objects in my pool (per key) (see {@link #setMaxIdle})
332      */

333     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle) {
334         this(factory,maxActive,whenExhaustedAction,maxWait,maxIdle,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
335     }
336
337     /**
338      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
339      * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
340      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
341      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
342      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
343      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
344      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
345      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
346      */

347     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn) {
348         this(factory,maxActive,whenExhaustedAction,maxWait,maxIdle,testOnBorrow,testOnReturn,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
349     }
350
351     /**
352      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
353      * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
354      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
355      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
356      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
357      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
358      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
359      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
360      * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
361      * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
362      * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
363      * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
364      */

365     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
366         this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
367     }
368
369     /**
370      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
371      * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
372      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
373      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
374      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
375      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
376      * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
377      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
378      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
379      * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
380      * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
381      * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
382      * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
383      */

384     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
385         this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, GenericKeyedObjectPool.DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
386     }
387     
388     /**
389      * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
390      * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
391      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
392      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
393      * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
394      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
395      * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
396      * @param minIdle the minimum number of idle objects to have in the pool at any one time (see {@link #setMinIdle})
397      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
398      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
399      * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
400      * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
401      * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
402      * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
403      */

404     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
405         _factory = factory;
406         _maxActive = maxActive;
407         switch(whenExhaustedAction) {
408             case WHEN_EXHAUSTED_BLOCK:
409             case WHEN_EXHAUSTED_FAIL:
410             case WHEN_EXHAUSTED_GROW:
411                 _whenExhaustedAction = whenExhaustedAction;
412                 break;
413             default:
414                 throw new IllegalArgumentException JavaDoc("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
415         }
416         _maxWait = maxWait;
417         _maxIdle = maxIdle;
418         _maxTotal = maxTotal;
419         _minIdle = minIdle;
420         _testOnBorrow = testOnBorrow;
421         _testOnReturn = testOnReturn;
422         _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
423         _numTestsPerEvictionRun = numTestsPerEvictionRun;
424         _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
425         _testWhileIdle = testWhileIdle;
426
427         _poolMap = new HashMap JavaDoc();
428         _activeMap = new HashMap JavaDoc();
429         _poolList = new CursorableLinkedList();
430
431         startEvictor(_timeBetweenEvictionRunsMillis);
432     }
433
434     //--- public methods ---------------------------------------------
435

436     //--- configuration methods --------------------------------------
437

438     /**
439      * Returns the cap on the number of active instances from my pool (per key).
440      * @return the cap on the number of active instances from my pool (per key).
441      * @see #setMaxActive
442      */

443     public synchronized int getMaxActive() {
444         return _maxActive;
445     }
446
447     /**
448      * Sets the cap on the number of active instances from my pool (per key).
449      * @param maxActive The cap on the number of active instances from my pool (per key).
450      * Use a negative value for an infinite number of instances.
451      * @see #getMaxActive
452      */

453     public synchronized void setMaxActive(int maxActive) {
454         _maxActive = maxActive;
455         notifyAll();
456     }
457
458     /**
459      * Returns the cap on the total number of instances from my pool.
460      * @return the cap on the total number of instances from my pool.
461      * @see #setMaxTotal
462      */

463     public synchronized int getMaxTotal() {
464         return _maxTotal;
465     }
466
467     /**
468      * Sets the cap on the total number of instances from my pool.
469      * @param maxTotal The cap on the total number of instances from my pool.
470      * Use a negative value for an infinite number of instances.
471      * @see #getMaxTotal
472      */

473     public synchronized void setMaxTotal(int maxTotal) {
474         _maxTotal = maxTotal;
475         notifyAll();
476     }
477
478     /**
479      * Returns the action to take when the {@link #borrowObject} method
480      * is invoked when the pool is exhausted (the maximum number
481      * of "active" objects has been reached).
482      *
483      * @return one of {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL} or {@link #WHEN_EXHAUSTED_GROW}
484      * @see #setWhenExhaustedAction
485      */

486     public synchronized byte getWhenExhaustedAction() {
487         return _whenExhaustedAction;
488     }
489
490     /**
491      * Sets the action to take when the {@link #borrowObject} method
492      * is invoked when the pool is exhausted (the maximum number
493      * of "active" objects has been reached).
494      *
495      * @param whenExhaustedAction the action code, which must be one of
496      * {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL},
497      * or {@link #WHEN_EXHAUSTED_GROW}
498      * @see #getWhenExhaustedAction
499      */

500     public synchronized void setWhenExhaustedAction(byte whenExhaustedAction) {
501         switch(whenExhaustedAction) {
502             case WHEN_EXHAUSTED_BLOCK:
503             case WHEN_EXHAUSTED_FAIL:
504             case WHEN_EXHAUSTED_GROW:
505                 _whenExhaustedAction = whenExhaustedAction;
506                 notifyAll();
507                 break;
508             default:
509                 throw new IllegalArgumentException JavaDoc("whenExhaustedAction " + whenExhaustedAction + " not recognized.");
510         }
511     }
512
513
514     /**
515      * Returns the maximum amount of time (in milliseconds) the
516      * {@link #borrowObject} method should block before throwing
517      * an exception when the pool is exhausted and the
518      * {@link #setWhenExhaustedAction "when exhausted" action} is
519      * {@link #WHEN_EXHAUSTED_BLOCK}.
520      *
521      * When less than 0, the {@link #borrowObject} method
522      * may block indefinitely.
523      *
524      * @see #setMaxWait
525      * @see #setWhenExhaustedAction
526      * @see #WHEN_EXHAUSTED_BLOCK
527      */

528     public synchronized long getMaxWait() {
529         return _maxWait;
530     }
531
532     /**
533      * Sets the maximum amount of time (in milliseconds) the
534      * {@link #borrowObject} method should block before throwing
535      * an exception when the pool is exhausted and the
536      * {@link #setWhenExhaustedAction "when exhausted" action} is
537      * {@link #WHEN_EXHAUSTED_BLOCK}.
538      *
539      * When less than 0, the {@link #borrowObject} method
540      * may block indefinitely.
541      *
542      * @see #getMaxWait
543      * @see #setWhenExhaustedAction
544      * @see #WHEN_EXHAUSTED_BLOCK
545      */

546     public synchronized void setMaxWait(long maxWait) {
547         _maxWait = maxWait;
548     }
549
550     /**
551      * Returns the cap on the number of "idle" instances in the pool.
552      * @return the cap on the number of "idle" instances in the pool.
553      * @see #setMaxIdle
554      */

555     public synchronized int getMaxIdle() {
556         return _maxIdle;
557     }
558
559     /**
560      * Sets the cap on the number of "idle" instances in the pool.
561      * @param maxIdle The cap on the number of "idle" instances in the pool.
562      * Use a negative value to indicate an unlimited number
563      * of idle instances.
564      * @see #getMaxIdle
565      */

566     public synchronized void setMaxIdle(int maxIdle) {
567         _maxIdle = maxIdle;
568         notifyAll();
569     }
570
571     /**
572      * Sets the minimum number of idle objects in pool to maintain (per key)
573      * @param poolSize - The minimum size of the pool
574      * @see #getMinIdle
575      */

576     public synchronized void setMinIdle(int poolSize) {
577         _minIdle = poolSize;
578     }
579     
580     /**
581      * Returns the minimum number of idle objects in pool to maintain (per key)
582      * @return the minimum number of idle objects in pool to maintain (per key)
583      * @see #setMinIdle
584      */

585     public synchronized int getMinIdle() {
586         return _minIdle;
587     }
588     
589     /**
590      * When <tt>true</tt>, objects will be
591      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
592      * before being returned by the {@link #borrowObject}
593      * method. If the object fails to validate,
594      * it will be dropped from the pool, and we will attempt
595      * to borrow another.
596      *
597      * @see #setTestOnBorrow
598      */

599     public synchronized boolean getTestOnBorrow() {
600         return _testOnBorrow;
601     }
602
603     /**
604      * When <tt>true</tt>, objects will be
605      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
606      * before being returned by the {@link #borrowObject}
607      * method. If the object fails to validate,
608      * it will be dropped from the pool, and we will attempt
609      * to borrow another.
610      *
611      * @see #getTestOnBorrow
612      */

613     public synchronized void setTestOnBorrow(boolean testOnBorrow) {
614         _testOnBorrow = testOnBorrow;
615     }
616
617     /**
618      * When <tt>true</tt>, objects will be
619      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
620      * before being returned to the pool within the
621      * {@link #returnObject}.
622      *
623      * @see #setTestOnReturn
624      */

625     public synchronized boolean getTestOnReturn() {
626         return _testOnReturn;
627     }
628
629     /**
630      * When <tt>true</tt>, objects will be
631      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
632      * before being returned to the pool within the
633      * {@link #returnObject}.
634      *
635      * @see #getTestOnReturn
636      */

637     public synchronized void setTestOnReturn(boolean testOnReturn) {
638         _testOnReturn = testOnReturn;
639     }
640
641     /**
642      * Returns the number of milliseconds to sleep between runs of the
643      * idle object evictor thread.
644      * When non-positive, no idle object evictor thread will be
645      * run.
646      *
647      * @see #setTimeBetweenEvictionRunsMillis
648      */

649     public synchronized long getTimeBetweenEvictionRunsMillis() {
650         return _timeBetweenEvictionRunsMillis;
651     }
652
653     /**
654      * Sets the number of milliseconds to sleep between runs of the
655      * idle object evictor thread.
656      * When non-positive, no idle object evictor thread will be
657      * run.
658      *
659      * @see #getTimeBetweenEvictionRunsMillis
660      */

661     public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
662         _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
663         startEvictor(_timeBetweenEvictionRunsMillis);
664     }
665
666     /**
667      * Returns the number of objects to examine during each run of the
668      * idle object evictor thread (if any).
669      *
670      * @see #setNumTestsPerEvictionRun
671      * @see #setTimeBetweenEvictionRunsMillis
672      */

673     public synchronized int getNumTestsPerEvictionRun() {
674         return _numTestsPerEvictionRun;
675     }
676
677     /**
678      * Sets the number of objects to examine during each run of the
679      * idle object evictor thread (if any).
680      * <p>
681      * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
682      * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
683      * idle objects will be tested per run.
684      *
685      * @see #getNumTestsPerEvictionRun
686      * @see #setTimeBetweenEvictionRunsMillis
687      */

688     public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
689         _numTestsPerEvictionRun = numTestsPerEvictionRun;
690     }
691
692     /**
693      * Returns the minimum amount of time an object may sit idle in the pool
694      * before it is eligable for eviction by the idle object evictor
695      * (if any).
696      *
697      * @see #setMinEvictableIdleTimeMillis
698      * @see #setTimeBetweenEvictionRunsMillis
699      */

700     public synchronized long getMinEvictableIdleTimeMillis() {
701         return _minEvictableIdleTimeMillis;
702     }
703
704     /**
705      * Sets the minimum amount of time an object may sit idle in the pool
706      * before it is eligable for eviction by the idle object evictor
707      * (if any).
708      * When non-positive, no objects will be evicted from the pool
709      * due to idle time alone.
710      *
711      * @see #getMinEvictableIdleTimeMillis
712      * @see #setTimeBetweenEvictionRunsMillis
713      */

714     public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
715         _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
716     }
717
718     /**
719      * When <tt>true</tt>, objects will be
720      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
721      * by the idle object evictor (if any). If an object
722      * fails to validate, it will be dropped from the pool.
723      *
724      * @see #setTestWhileIdle
725      * @see #setTimeBetweenEvictionRunsMillis
726      */

727     public synchronized boolean getTestWhileIdle() {
728         return _testWhileIdle;
729     }
730
731     /**
732      * When <tt>true</tt>, objects will be
733      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
734      * by the idle object evictor (if any). If an object
735      * fails to validate, it will be dropped from the pool.
736      *
737      * @see #getTestWhileIdle
738      * @see #setTimeBetweenEvictionRunsMillis
739      */

740     public synchronized void setTestWhileIdle(boolean testWhileIdle) {
741         _testWhileIdle = testWhileIdle;
742     }
743
744     /**
745      * Sets my configuration.
746      * @see GenericKeyedObjectPool.Config
747      */

748     public synchronized void setConfig(GenericKeyedObjectPool.Config conf) {
749         setMaxIdle(conf.maxIdle);
750         setMaxActive(conf.maxActive);
751         setMaxTotal(conf.maxTotal);
752         setMinIdle(conf.minIdle);
753         setMaxWait(conf.maxWait);
754         setWhenExhaustedAction(conf.whenExhaustedAction);
755         setTestOnBorrow(conf.testOnBorrow);
756         setTestOnReturn(conf.testOnReturn);
757         setTestWhileIdle(conf.testWhileIdle);
758         setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
759         setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
760         setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
761     }
762
763     //-- ObjectPool methods ------------------------------------------
764

765     public synchronized Object JavaDoc borrowObject(Object JavaDoc key) throws Exception JavaDoc {
766         long starttime = System.currentTimeMillis();
767         boolean newlyCreated = false;
768         for(;;) {
769             CursorableLinkedList pool = (CursorableLinkedList)(_poolMap.get(key));
770             if(null == pool) {
771                 pool = new CursorableLinkedList();
772                 _poolMap.put(key,pool);
773                 _poolList.add(key);
774             }
775             ObjectTimestampPair pair = null;
776             // if there are any sleeping, just grab one of those
777
try {
778                 pair = (ObjectTimestampPair)(pool.removeFirst());
779                 if(null != pair) {
780                     _totalIdle--;
781                 }
782             } catch(NoSuchElementException JavaDoc e) { /* ignored */
783             }
784             // otherwise
785
if(null == pair) {
786                 // if there is a totalMaxActive and we are at the limit then
787
// we have to make room
788
if ((_maxTotal > 0) && (_totalActive + _totalIdle >= _maxTotal)) {
789                     clearOldest();
790                 }
791                 
792                 // check if we can create one
793
// (note we know that the num sleeping is 0, else we wouldn't be here)
794
int active = getActiveCount(key);
795                 if ((_maxActive < 0 || active < _maxActive) &&
796                     (_maxTotal < 0 || _totalActive + _totalIdle < _maxTotal)) {
797                     Object JavaDoc obj = _factory.makeObject(key);
798                     pair = new ObjectTimestampPair(obj);
799                     newlyCreated = true;
800                 } else {
801                     // the pool is exhausted
802
switch(_whenExhaustedAction) {
803                         case WHEN_EXHAUSTED_GROW:
804                             Object JavaDoc obj = _factory.makeObject(key);
805                             pair = new ObjectTimestampPair(obj);
806                             break;
807                         case WHEN_EXHAUSTED_FAIL:
808                             throw new NoSuchElementException JavaDoc();
809                         case WHEN_EXHAUSTED_BLOCK:
810                             try {
811                                 if(_maxWait <= 0) {
812                                     wait();
813                                 } else {
814                                     wait(_maxWait);
815                                 }
816                             } catch(InterruptedException JavaDoc e) {
817                                 // ignored
818
}
819                             if(_maxWait > 0 && ((System.currentTimeMillis() - starttime) >= _maxWait)) {
820                                 throw new NoSuchElementException JavaDoc("Timeout waiting for idle object");
821                             } else {
822                                 continue; // keep looping
823
}
824                         default:
825                             throw new IllegalArgumentException JavaDoc("whenExhaustedAction " + _whenExhaustedAction + " not recognized.");
826                     }
827                 }
828             }
829             _factory.activateObject(key,pair.value);
830             if(_testOnBorrow && !_factory.validateObject(key,pair.value)) {
831                 _factory.destroyObject(key,pair.value);
832                 if(newlyCreated) {
833                     throw new NoSuchElementException JavaDoc("Could not create a validated object");
834                 } // else keep looping
835
} else {
836                 incrementActiveCount(key);
837                 return pair.value;
838             }
839         }
840     }
841
842     public synchronized void clear() {
843         for(Iterator JavaDoc keyiter = _poolList.iterator(); keyiter.hasNext(); ) {
844             Object JavaDoc key = keyiter.next();
845             CursorableLinkedList list = (CursorableLinkedList)(_poolMap.get(key));
846             for(Iterator JavaDoc it = list.iterator(); it.hasNext(); ) {
847                 try {
848                     _factory.destroyObject(key,((ObjectTimestampPair)(it.next())).value);
849                 } catch(Exception JavaDoc e) {
850                     // ignore error, keep destroying the rest
851
}
852                 it.remove();
853             }
854         }
855         _poolMap.clear();
856         _poolList.clear();
857         _totalIdle = 0;
858         notifyAll();
859     }
860
861     /**
862      * Method clears oldest 15% of objects in pool. The method sorts the
863      * objects into a TreeMap and then iterates the first 15% for removal
864      */

865     public synchronized void clearOldest() {
866         // build sorted map of idle objects
867
TreeMap JavaDoc map = new TreeMap JavaDoc();
868         for (Iterator JavaDoc keyiter = _poolList.iterator(); keyiter.hasNext();) {
869             Object JavaDoc key = keyiter.next();
870             CursorableLinkedList list = (CursorableLinkedList) _poolMap.get(key);
871             for (Iterator JavaDoc it = list.iterator(); it.hasNext();) {
872                 // each item into the map uses the objectimestamppair object
873
// as the key. It then gets sorted based on the timstamp field
874
// each value in the map is the parent list it belongs in.
875
ObjectTimestampPair pair = (ObjectTimestampPair) it.next();
876                 map.put(pair, key);
877             }
878         }
879         
880         // Now iterate created map and kill the first 15% plus one to account for zero
881
Set JavaDoc setPairKeys = map.entrySet();
882         int itemsToRemove = ((int) (map.size() * 0.15)) + 1;
883         
884         Iterator JavaDoc iter = setPairKeys.iterator();
885         while (iter.hasNext() && itemsToRemove > 0) {
886             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
887             // kind of backwards on naming. In the map, each key is the objecttimestamppair
888
// because it has the ordering with the timestamp value. Each value that the
889
// key references is the key of the list it belongs to.
890
Object JavaDoc key = entry.getValue();
891             ObjectTimestampPair pairTimeStamp = (ObjectTimestampPair) entry.getKey();
892             CursorableLinkedList list = (CursorableLinkedList) _poolMap.get(key);
893             list.remove(pairTimeStamp);
894
895             try {
896                 _factory.destroyObject(key, pairTimeStamp.value);
897             } catch (Exception JavaDoc e) {
898                 // ignore error, keep destroying the rest
899
}
900             // if that was the last object for that key, drop that pool
901
if (list.isEmpty()) {
902                 _poolMap.remove(key);
903                 _poolList.remove(key);
904             }
905             _totalIdle--;
906             itemsToRemove--;
907         }
908         notifyAll();
909     }
910      
911     public synchronized void clear(Object JavaDoc key) {
912         CursorableLinkedList pool = (CursorableLinkedList)(_poolMap.remove(key));
913         if(null == pool) {
914             return;
915         } else {
916             _poolList.remove(key);
917             for(Iterator JavaDoc it = pool.iterator(); it.hasNext(); ) {
918                 try {
919                     _factory.destroyObject(key,((ObjectTimestampPair)(it.next())).value);
920                 } catch(Exception JavaDoc e) {
921                     // ignore error, keep destroying the rest
922
}
923                 it.remove();
924                 _totalIdle--;
925             }
926         }
927         notifyAll();
928     }
929
930     public synchronized int getNumActive() {
931         return _totalActive;
932     }
933
934     public synchronized int getNumIdle() {
935         return _totalIdle;
936     }
937
938     public synchronized int getNumActive(Object JavaDoc key) {
939         return getActiveCount(key);
940     }
941
942     public synchronized int getNumIdle(Object JavaDoc key) {
943         try {
944             return((CursorableLinkedList)(_poolMap.get(key))).size();
945         } catch(Exception JavaDoc e) {
946             return 0;
947         }
948     }
949
950     public void returnObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
951
952         // if we need to validate this object, do so
953
boolean success = true; // whether or not this object passed validation
954
if(_testOnReturn && !_factory.validateObject(key, obj)) {
955             success = false;
956             try {
957                 _factory.destroyObject(key, obj);
958             } catch(Exception JavaDoc e) {
959                 // ignored
960
}
961         } else {
962             try {
963                 _factory.passivateObject(key, obj);
964             } catch(Exception JavaDoc e) {
965                 success = false;
966             }
967         }
968
969         boolean shouldDestroy = false;
970         synchronized(this) {
971             // grab the pool (list) of objects associated with the given key
972
CursorableLinkedList pool = (CursorableLinkedList) (_poolMap.get(key));
973             // if it doesn't exist, create it
974
if(null == pool) {
975                 pool = new CursorableLinkedList();
976                 _poolMap.put(key, pool);
977                 _poolList.add(key);
978             }
979             decrementActiveCount(key);
980             // if there's no space in the pool, flag the object for destruction
981
// else if we passivated succesfully, return it to the pool
982
if(_maxIdle >= 0 && (pool.size() >= _maxIdle)) {
983                 shouldDestroy = true;
984             } else if(success) {
985                 pool.addFirst(new ObjectTimestampPair(obj));
986                 _totalIdle++;
987             }
988             notifyAll();
989         }
990
991         if(shouldDestroy) {
992             try {
993                 _factory.destroyObject(key, obj);
994             } catch(Exception JavaDoc e) {
995                 // ignored?
996
}
997         }
998     }
999
1000    public void invalidateObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
1001        try {
1002            _factory.destroyObject(key, obj);
1003        }
1004        finally {
1005            synchronized(this) {
1006                decrementActiveCount(key);
1007                notifyAll(); // _totalActive has changed
1008
}
1009        }
1010    }
1011
1012    public void addObject(Object JavaDoc key) throws Exception JavaDoc {
1013        Object JavaDoc obj = _factory.makeObject(key);
1014        synchronized(this) {
1015            incrementActiveCount(key); // returnObject will decrement this
1016
returnObject(key,obj);
1017        }
1018    }
1019
1020    /**
1021     * Registers a key for pool control.
1022     *
1023     * If <i>populateImmediately</i> is <code>true</code>, the pool will immediately commence
1024     * a sustain cycle. If <i>populateImmediately</i> is <code>false</code>, the pool will be
1025     * populated when the next schedules sustain task is run.
1026     *
1027     * @param key - The key to register for pool control.
1028     * @param populateImmediately - If this is <code>true</code>, the pool
1029     * will start a sustain cycle immediately.
1030     */

1031    public void preparePool(Object JavaDoc key, boolean populateImmediately) {
1032        synchronized(this) {
1033            CursorableLinkedList pool = (CursorableLinkedList)(_poolMap.get(key));
1034            if (null == pool) {
1035                pool = new CursorableLinkedList();
1036                _poolMap.put(key,pool);
1037                _poolList.add(key);
1038            }
1039        }
1040        if (populateImmediately) {
1041            try {
1042                // Create the pooled objects
1043
ensureMinIdle(key);
1044            }
1045            catch (Exception JavaDoc e) {
1046                //Do nothing
1047
}
1048        }
1049    }
1050    
1051    public synchronized void close() throws Exception JavaDoc {
1052        clear();
1053        _poolList = null;
1054        _poolMap = null;
1055        _activeMap = null;
1056        if(null != _evictionCursor) {
1057            _evictionCursor.close();
1058            _evictionCursor = null;
1059        }
1060        if(null != _evictionKeyCursor) {
1061            _evictionKeyCursor.close();
1062            _evictionKeyCursor = null;
1063        }
1064        if(null != _evictor) {
1065            _evictor.cancel();
1066            _evictor = null;
1067        }
1068    }
1069
1070    public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException JavaDoc {
1071        if(0 < getNumActive()) {
1072            throw new IllegalStateException JavaDoc("Objects are already active");
1073        } else {
1074            clear();
1075            _factory = factory;
1076        }
1077    }
1078
1079    public synchronized void evict() throws Exception JavaDoc {
1080        Object JavaDoc key = null;
1081        for(int i=0,m=getNumTests();i<m;i++) {
1082            if(_poolMap.size() > 0) {
1083                // if we don't have a key cursor, then create one, and close any object cursor
1084
if(null == _evictionKeyCursor) {
1085                    _evictionKeyCursor = _poolList.cursor();
1086                    key = null;
1087                    if(null != _evictionCursor) {
1088                        _evictionCursor.close();
1089                        _evictionCursor = null;
1090                    }
1091                }
1092                // if we don't have an object cursor
1093
if(null == _evictionCursor) {
1094                    // if the _evictionKeyCursor has a next value, then use it
1095
if(_evictionKeyCursor.hasNext()) {
1096                        key = _evictionKeyCursor.next();
1097                        CursorableLinkedList pool = (CursorableLinkedList)(_poolMap.get(key));
1098                        _evictionCursor = pool.cursor(pool.size());
1099                    } else {
1100                        // else close the key cursor and loop back around
1101
if(null != _evictionKeyCursor) {
1102                            _evictionKeyCursor.close();
1103                            _evictionKeyCursor = _poolList.cursor();
1104                            if(null != _evictionCursor) {
1105                                _evictionCursor.close();
1106                                _evictionCursor = null;
1107                            }
1108                        }
1109                        continue;
1110                    }
1111                }
1112                // if the _evictionCursor has a previous object, then test it
1113
if(_evictionCursor.hasPrevious()) {
1114                    ObjectTimestampPair pair = (ObjectTimestampPair)(_evictionCursor.previous());
1115                    boolean removeObject=false;
1116                    if(_minEvictableIdleTimeMillis > 0 &&
1117                       System.currentTimeMillis() - pair.tstamp > _minEvictableIdleTimeMillis) {
1118                       removeObject=true;
1119                    } else if(_testWhileIdle) {
1120                        boolean active = false;
1121                        try {
1122                            _factory.activateObject(key,pair.value);
1123                            active = true;
1124                        } catch(Exception JavaDoc e) {
1125                            removeObject=true;
1126                        }
1127                        if(active) {
1128                            if(!_factory.validateObject(key,pair.value)) {
1129                                removeObject=true;
1130                            } else {
1131                                try {
1132                                    _factory.passivateObject(key,pair.value);
1133                                } catch(Exception JavaDoc e) {
1134                                    removeObject=true;
1135                                }
1136                            }
1137                        }
1138                    }
1139                    if(removeObject) {
1140                        try {
1141                            _evictionCursor.remove();
1142                            _totalIdle--;
1143                            _factory.destroyObject(key,pair.value);
1144
1145                            // Do not remove the key from the _poolList or _poolmap, even if the list
1146
// stored in the _poolMap for this key is empty when the
1147
// {@link #getMinIdle <i>minIdle</i>} is > 0.
1148
//
1149
// Otherwise if it was the last object for that key, drop that pool
1150
if ((_minIdle == 0) && (((CursorableLinkedList)(_poolMap.get(key))).isEmpty())) {
1151                                _poolMap.remove(key);
1152                                _poolList.remove(key);
1153                            }
1154                        } catch(Exception JavaDoc e) {
1155                            ; // ignored
1156
}
1157                    }
1158                } else {
1159                    // else the _evictionCursor is done, so close it and loop around
1160
if(_evictionCursor != null) {
1161                        _evictionCursor.close();
1162                        _evictionCursor = null;
1163                    }
1164                }
1165            }
1166        }
1167    }
1168
1169    /**
1170     * Iterates through all the known keys and creates any necessary objects to maintain
1171     * the minimum level of pooled objects.
1172     * @see #getMinIdle
1173     * @see #setMinIdle
1174     * @throws Exception If there was an error whilst creating the pooled objects.
1175     */

1176    private synchronized void ensureMinIdle() throws Exception JavaDoc {
1177        ListIterator JavaDoc iterator = _poolList.cursor();
1178   
1179        //Check if should sustain the pool
1180
if (_minIdle > 0) {
1181            // Loop through all elements in _poolList
1182
// Find out the total number of max active and max idle for that class
1183
// If the number is less than the minIdle, do creation loop to boost numbers
1184
// Increment idle count + 1
1185
while (iterator.hasNext()) {
1186                //Get the next key to process
1187
Object JavaDoc key = iterator.next();
1188                ensureMinIdle(key);
1189            }
1190        }
1191    }
1192
1193    /**
1194     * Re-creates any needed objects to maintain the minimum levels of
1195     * pooled objects for the specified key.
1196     *
1197     * This method uses {@link #calculateDefecit} to calculate the number
1198     * of objects to be created. {@link #calculateDefecit} can be overridden to
1199     * provide a different method of calculating the number of objects to be
1200     * created.
1201     * @param key The key to process
1202     * @throws Exception If there was an error whilst creating the pooled objects
1203     */

1204    private synchronized void ensureMinIdle(Object JavaDoc key) throws Exception JavaDoc {
1205        // Calculate current pool objects
1206
int numberToCreate = calculateDefecit(key);
1207        
1208        //Create required pool objects, if none to create, this loop will not be run.
1209
for (int i = 0; i < numberToCreate; i++) {
1210            addObject(key);
1211        }
1212    }
1213    
1214    //--- non-public methods ----------------------------------------
1215

1216    /**
1217     * Start the eviction thread or service, or when
1218     * <i>delay</i> is non-positive, stop it
1219     * if it is already running.
1220     */

1221    protected synchronized void startEvictor(long delay) {
1222        if(null != _evictor) {
1223            _evictor.cancel();
1224            _evictor = null;
1225        }
1226        if(delay > 0) {
1227            _evictor = new Evictor(delay);
1228            Thread JavaDoc t = new Thread JavaDoc(_evictor);
1229            t.setDaemon(true);
1230            t.start();
1231        }
1232    }
1233
1234    synchronized String JavaDoc debugInfo() {
1235        StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1236        buf.append("Active: ").append(getNumActive()).append("\n");
1237        buf.append("Idle: ").append(getNumIdle()).append("\n");
1238        Iterator JavaDoc it = _poolList.iterator();
1239        while(it.hasNext()) {
1240            buf.append("\t").append(_poolMap.get(it.next())).append("\n");
1241        }
1242        return buf.toString();
1243    }
1244
1245    private synchronized int getNumTests() {
1246        if(_numTestsPerEvictionRun >= 0) {
1247            return _numTestsPerEvictionRun;
1248        } else {
1249            return(int)(Math.ceil((double)_totalIdle/Math.abs((double)_numTestsPerEvictionRun)));
1250        }
1251    }
1252
1253    private synchronized void incrementActiveCount(Object JavaDoc key) {
1254        _totalActive++;
1255        Integer JavaDoc active = (Integer JavaDoc)(_activeMap.get(key));
1256        if(null == active) {
1257            _activeMap.put(key,new Integer JavaDoc(1));
1258        } else {
1259            _activeMap.put(key,new Integer JavaDoc(active.intValue() + 1));
1260        }
1261    }
1262
1263    private synchronized void decrementActiveCount(Object JavaDoc key) {
1264        _totalActive--;
1265        Integer JavaDoc active = (Integer JavaDoc)(_activeMap.get(key));
1266        if(null == active) {
1267            // do nothing, either null or zero is OK
1268
} else if(active.intValue() <= 1) {
1269            _activeMap.remove(key);
1270        } else {
1271            _activeMap.put(key, new Integer JavaDoc(active.intValue() - 1));
1272        }
1273    }
1274
1275    private synchronized int getActiveCount(Object JavaDoc key) {
1276        int active = 0;
1277        Integer JavaDoc act = (Integer JavaDoc)(_activeMap.get(key));
1278        if(null != act) {
1279            active = act.intValue();
1280        }
1281        return active;
1282    }
1283    /**
1284     * This returns the number of objects to create during the pool
1285     * sustain cycle. This will ensure that the minimum number of idle
1286     * connections is maintained without going past the maxPool value.
1287     * <p>
1288     * This method has been left public so derived classes can override
1289     * the way the defecit is calculated. ie... Increase/decrease the pool
1290     * size at certain times of day to accomodate for usage patterns.
1291     *
1292     * @param key - The key of the pool to calculate the number of
1293     * objects to be re-created
1294     * @return The number of objects to be created
1295     */

1296    private synchronized int calculateDefecit(Object JavaDoc key) {
1297        int objectDefecit = 0;
1298        
1299        //Calculate no of objects needed to be created, in order to have
1300
//the number of pooled objects < maxActive();
1301
objectDefecit = getMinIdle() - getNumIdle(key);
1302        if (getMaxActive() > 0) {
1303            int growLimit = Math.max(0, getMaxActive() - getNumActive(key) - getNumIdle(key));
1304            objectDefecit = Math.min(objectDefecit, growLimit);
1305        }
1306        
1307        // Take the maxTotal limit into account
1308
if (getMaxTotal() > 0) {
1309            int growLimit = Math.max(0, getMaxTotal() - getNumActive() - getNumIdle());
1310            objectDefecit = Math.min(objectDefecit, growLimit);
1311        }
1312
1313        return objectDefecit;
1314    }
1315
1316    //--- inner classes ----------------------------------------------
1317

1318    /**
1319     * A simple "struct" encapsulating an object instance and a timestamp.
1320     *
1321     * Implements Comparable, objects are sorted from old to new.
1322     */

1323    class ObjectTimestampPair implements Comparable JavaDoc {
1324        Object JavaDoc value;
1325        long tstamp;
1326
1327        ObjectTimestampPair(Object JavaDoc val) {
1328            value = val;
1329            tstamp = System.currentTimeMillis();
1330        }
1331
1332        ObjectTimestampPair(Object JavaDoc val, long time) {
1333            value = val;
1334            tstamp = time;
1335        }
1336
1337        public String JavaDoc toString() {
1338            return value + ";" + tstamp;
1339        }
1340
1341        public int compareTo(Object JavaDoc obj) {
1342            return compareTo((ObjectTimestampPair) obj);
1343        }
1344
1345        public int compareTo(ObjectTimestampPair other) {
1346            return (int) (this.tstamp - other.tstamp);
1347        }
1348    }
1349
1350    /**
1351     * The idle object evictor thread.
1352     * @see #setTimeBetweenEvictionRunsMillis
1353     */

1354    class Evictor implements Runnable JavaDoc {
1355        private boolean _cancelled = false;
1356        private long _delay = 0L;
1357
1358        public Evictor(long delay) {
1359            _delay = delay;
1360        }
1361
1362        void cancel() {
1363            _cancelled = true;
1364        }
1365
1366        public void run() {
1367            while(!_cancelled) {
1368                long sleeptime = 0L;
1369                synchronized(GenericKeyedObjectPool.this) {
1370                    sleeptime = _timeBetweenEvictionRunsMillis;
1371                }
1372                try {
1373                    Thread.sleep(sleeptime);
1374                } catch(Exception JavaDoc e) {
1375                    ; // ignored
1376
}
1377                //Evict from the pool
1378
try {
1379                    evict();
1380                } catch(Exception JavaDoc e) {
1381                    ; // ignored
1382
}
1383                //Re-create the connections.
1384
try {
1385                    ensureMinIdle();
1386                } catch (Exception JavaDoc e) {
1387                    ; // ignored
1388
}
1389            }
1390            synchronized(GenericKeyedObjectPool.this) {
1391                if(null != _evictionCursor) {
1392                    _evictionCursor.close();
1393                    _evictionCursor = null;
1394                }
1395                if(null != _evictionKeyCursor) {
1396                    _evictionKeyCursor.close();
1397                    _evictionKeyCursor = null;
1398                }
1399            }
1400        }
1401    }
1402
1403    /**
1404     * A simple "struct" encapsulating the
1405     * configuration information for a {@link GenericKeyedObjectPool}.
1406     * @see GenericKeyedObjectPool#GenericKeyedObjectPool(KeyedPoolableObjectFactory,GenericKeyedObjectPool.Config)
1407     * @see GenericKeyedObjectPool#setConfig
1408     */

1409    public static class Config {
1410        public int maxIdle = GenericKeyedObjectPool.DEFAULT_MAX_IDLE;
1411        public int maxActive = GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE;
1412        public int maxTotal = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
1413        public int minIdle = GenericKeyedObjectPool.DEFAULT_MIN_IDLE;
1414        public long maxWait = GenericKeyedObjectPool.DEFAULT_MAX_WAIT;
1415        public byte whenExhaustedAction = GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
1416        public boolean testOnBorrow = GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW;
1417        public boolean testOnReturn = GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN;
1418        public boolean testWhileIdle = GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE;
1419        public long timeBetweenEvictionRunsMillis = GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
1420        public int numTestsPerEvictionRun = GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
1421        public long minEvictableIdleTimeMillis = GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
1422    }
1423
1424    //--- protected attributes ---------------------------------------
1425

1426    /**
1427     * The cap on the number of idle instances in the pool (per key).
1428     * @see #setMaxIdle
1429     * @see #getMaxIdle
1430     */

1431    private int _maxIdle = DEFAULT_MAX_IDLE;
1432
1433    /**
1434     * The minimum no of idle objects to keep in the pool (per key)
1435     * @see #setMinIdle
1436     * @see #getMinIdle
1437     */

1438    private int _minIdle = DEFAULT_MIN_IDLE;
1439
1440    /**
1441     * The cap on the number of active instances from the pool (per key).
1442     * @see #setMaxActive
1443     * @see #getMaxActive
1444     */

1445    private int _maxActive = DEFAULT_MAX_ACTIVE;
1446
1447    /**
1448     * The cap on the total number of instances from the pool.
1449     * @see #setMaxTotal
1450     * @see #getMaxTotal
1451     */

1452    private int _maxTotal = DEFAULT_MAX_TOTAL;
1453    
1454    /**
1455     * The maximum amount of time (in millis) the
1456     * {@link #borrowObject} method should block before throwing
1457     * an exception when the pool is exhausted and the
1458     * {@link #getWhenExhaustedAction "when exhausted" action} is
1459     * {@link #WHEN_EXHAUSTED_BLOCK}.
1460     *
1461     * When less than 0, the {@link #borrowObject} method
1462     * may block indefinitely.
1463     *
1464     * @see #setMaxWait
1465     * @see #getMaxWait
1466     * @see #WHEN_EXHAUSTED_BLOCK
1467     * @see #setWhenExhaustedAction
1468     * @see #getWhenExhaustedAction
1469     */

1470    private long _maxWait = DEFAULT_MAX_WAIT;
1471
1472    /**
1473     * The action to take when the {@link #borrowObject} method
1474     * is invoked when the pool is exhausted (the maximum number
1475     * of "active" objects has been reached).
1476     *
1477     * @see #WHEN_EXHAUSTED_BLOCK
1478     * @see #WHEN_EXHAUSTED_FAIL
1479     * @see #WHEN_EXHAUSTED_GROW
1480     * @see #DEFAULT_WHEN_EXHAUSTED_ACTION
1481     * @see #setWhenExhaustedAction
1482     * @see #getWhenExhaustedAction
1483     */

1484    private byte _whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;
1485
1486    /**
1487     * When <tt>true</tt>, objects will be
1488     * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1489     * before being returned by the {@link #borrowObject}
1490     * method. If the object fails to validate,
1491     * it will be dropped from the pool, and we will attempt
1492     * to borrow another.
1493     *
1494     * @see #setTestOnBorrow
1495     * @see #getTestOnBorrow
1496     */

1497    private boolean _testOnBorrow = DEFAULT_TEST_ON_BORROW;
1498
1499    /**
1500     * When <tt>true</tt>, objects will be
1501     * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1502     * before being returned to the pool within the
1503     * {@link #returnObject}.
1504     *
1505     * @see #getTestOnReturn
1506     * @see #setTestOnReturn
1507     */

1508    private boolean _testOnReturn = DEFAULT_TEST_ON_RETURN;
1509
1510    /**
1511     * When <tt>true</tt>, objects will be
1512     * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1513     * by the idle object evictor (if any). If an object
1514     * fails to validate, it will be dropped from the pool.
1515     *
1516     * @see #setTestWhileIdle
1517     * @see #getTestWhileIdle
1518     * @see #getTimeBetweenEvictionRunsMillis
1519     * @see #setTimeBetweenEvictionRunsMillis
1520     */

1521    private boolean _testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
1522
1523    /**
1524     * The number of milliseconds to sleep between runs of the
1525     * idle object evictor thread.
1526     * When non-positive, no idle object evictor thread will be
1527     * run.
1528     *
1529     * @see #setTimeBetweenEvictionRunsMillis
1530     * @see #getTimeBetweenEvictionRunsMillis
1531     */

1532    private long _timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
1533
1534    /**
1535     * The number of objects to examine during each run of the
1536     * idle object evictor thread (if any).
1537     * <p>
1538     * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
1539     * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
1540     * idle objects will be tested per run.
1541     *
1542     * @see #setNumTestsPerEvictionRun
1543     * @see #getNumTestsPerEvictionRun
1544     * @see #getTimeBetweenEvictionRunsMillis
1545     * @see #setTimeBetweenEvictionRunsMillis
1546     */

1547    private int _numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
1548
1549    /**
1550     * The minimum amount of time an object may sit idle in the pool
1551     * before it is eligable for eviction by the idle object evictor
1552     * (if any).
1553     * When non-positive, no objects will be evicted from the pool
1554     * due to idle time alone.
1555     *
1556     * @see #setMinEvictableIdleTimeMillis
1557     * @see #getMinEvictableIdleTimeMillis
1558     * @see #getTimeBetweenEvictionRunsMillis
1559     * @see #setTimeBetweenEvictionRunsMillis
1560     */

1561    private long _minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
1562
1563    /** My hash of pools (CursorableLinkedLists). */
1564    private HashMap JavaDoc _poolMap = null;
1565
1566    /**
1567     * A cursorable list of my pools.
1568     * @see GenericKeyedObjectPool.Evictor#run
1569     */

1570    private CursorableLinkedList _poolList = null;
1571
1572    /** Count of active objects, per key. */
1573    private HashMap JavaDoc _activeMap = null;
1574
1575    /** The total number of active instances. */
1576    private int _totalActive = 0;
1577
1578    /** The total number of idle instances. */
1579    private int _totalIdle = 0;
1580
1581    /** My {@link KeyedPoolableObjectFactory}. */
1582    private KeyedPoolableObjectFactory _factory = null;
1583
1584    /**
1585     * My idle object eviction thread, if any.
1586     */

1587    private Evictor _evictor = null;
1588
1589    private CursorableLinkedList.Cursor _evictionCursor = null;
1590    private CursorableLinkedList.Cursor _evictionKeyCursor = null;
1591
1592}
1593
Popular Tags