1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | ||
18 | package org.apache.commons.pool; | |
19 | ||
20 | import java.util.Collection; | |
21 | import java.util.HashMap; | |
22 | import java.util.Iterator; | |
23 | import java.util.Map; | |
24 | import java.util.NoSuchElementException; | |
25 | import java.util.Timer; | |
26 | import java.util.TimerTask; | |
27 | import java.util.Collections; | |
28 | ||
29 | /** | |
30 | * This class consists exclusively of static methods that operate on or return ObjectPool | |
31 | * or KeyedObjectPool related interfaces. | |
32 | * | |
33 | * @author Sandy McArthur | |
34 | * @version $Revision: 1206485 $ $Date: 2011-11-26 09:39:32 -0700 (Sat, 26 Nov 2011) $ | |
35 | * @since Pool 1.3 | |
36 | */ | |
37 | public final class PoolUtils { | |
38 | ||
39 | /** | |
40 | * Timer used to periodically check pools idle object count. | |
41 | * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated. | |
42 | */ | |
43 | private static Timer MIN_IDLE_TIMER; //@GuardedBy("this") | |
44 | ||
45 | /** | |
46 | * PoolUtils instances should NOT be constructed in standard programming. | |
47 | * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);. | |
48 | * This constructor is public to permit tools that require a JavaBean instance to operate. | |
49 | */ | |
50 | 0 | public PoolUtils() { |
51 | 0 | } |
52 | ||
53 | /** | |
54 | * Should the supplied Throwable be re-thrown (eg if it is an instance of | |
55 | * one of the Throwables that should never be swallowed). Used by the pool | |
56 | * error handling for operations that throw exceptions that normally need to | |
57 | * be ignored. | |
58 | * @param t The Throwable to check | |
59 | * @throws ThreadDeath if that is passed in | |
60 | * @throws VirtualMachineError if that is passed in | |
61 | * @since Pool 1.5.5 | |
62 | */ | |
63 | public static void checkRethrow(Throwable t) { | |
64 | 0 | if (t instanceof ThreadDeath) { |
65 | 0 | throw (ThreadDeath) t; |
66 | } | |
67 | 0 | if (t instanceof VirtualMachineError) { |
68 | 0 | throw (VirtualMachineError) t; |
69 | } | |
70 | // All other instances of Throwable will be silently swallowed | |
71 | 0 | } |
72 | ||
73 | /** | |
74 | * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is | |
75 | * needed. This method is the equivalent of calling | |
76 | * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}. | |
77 | * | |
78 | * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to. | |
79 | * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key. | |
80 | * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>. | |
81 | * @see #adapt(KeyedPoolableObjectFactory, Object) | |
82 | * @since Pool 1.3 | |
83 | */ | |
84 | public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { | |
85 | 0 | return adapt(keyedFactory, new Object()); |
86 | } | |
87 | ||
88 | /** | |
89 | * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is | |
90 | * needed using the specified <code>key</code> when delegating. | |
91 | * | |
92 | * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to. | |
93 | * @param key the key to use when delegating. | |
94 | * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key. | |
95 | * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>. | |
96 | * @see #adapt(KeyedPoolableObjectFactory) | |
97 | * @since Pool 1.3 | |
98 | */ | |
99 | public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException { | |
100 | 0 | return new PoolableObjectFactoryAdaptor(keyedFactory, key); |
101 | } | |
102 | ||
103 | /** | |
104 | * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is | |
105 | * needed. The key is ignored. | |
106 | * | |
107 | * @param factory the {@link PoolableObjectFactory} to delegate to. | |
108 | * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key. | |
109 | * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>. | |
110 | * @since Pool 1.3 | |
111 | */ | |
112 | public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException { | |
113 | 0 | return new KeyedPoolableObjectFactoryAdaptor(factory); |
114 | } | |
115 | ||
116 | /** | |
117 | * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the | |
118 | * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}. | |
119 | * | |
120 | * @param keyedPool the {@link KeyedObjectPool} to delegate to. | |
121 | * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key. | |
122 | * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>. | |
123 | * @see #adapt(KeyedObjectPool, Object) | |
124 | * @since Pool 1.3 | |
125 | */ | |
126 | public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException { | |
127 | 0 | return adapt(keyedPool, new Object()); |
128 | } | |
129 | ||
130 | /** | |
131 | * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the | |
132 | * specified <code>key</code> when delegating. | |
133 | * | |
134 | * @param keyedPool the {@link KeyedObjectPool} to delegate to. | |
135 | * @param key the key to use when delegating. | |
136 | * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key. | |
137 | * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. | |
138 | * @see #adapt(KeyedObjectPool) | |
139 | * @since Pool 1.3 | |
140 | */ | |
141 | public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException { | |
142 | 0 | return new ObjectPoolAdaptor(keyedPool, key); |
143 | } | |
144 | ||
145 | /** | |
146 | * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed. | |
147 | * The key is ignored. | |
148 | * | |
149 | * @param pool the {@link ObjectPool} to delegate to. | |
150 | * @return a {@link KeyedObjectPool} that delegates to <code>pool</code> ignoring the key. | |
151 | * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. | |
152 | * @since Pool 1.3 | |
153 | */ | |
154 | public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException { | |
155 | 0 | return new KeyedObjectPoolAdaptor(pool); |
156 | } | |
157 | ||
158 | /** | |
159 | * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the pool. | |
160 | * If an object is passed to the pool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown. | |
161 | * | |
162 | * @param pool the pool to enforce type safety on | |
163 | * @param type the class type to enforce. | |
164 | * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code> | |
165 | * @since Pool 1.3 | |
166 | */ | |
167 | public static ObjectPool checkedPool(final ObjectPool pool, final Class type) { | |
168 | 0 | if (pool == null) { |
169 | 0 | throw new IllegalArgumentException("pool must not be null."); |
170 | } | |
171 | 0 | if (type == null) { |
172 | 0 | throw new IllegalArgumentException("type must not be null."); |
173 | } | |
174 | 0 | return new CheckedObjectPool(pool, type); |
175 | } | |
176 | ||
177 | /** | |
178 | * Wraps a <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool. | |
179 | * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown. | |
180 | * | |
181 | * @param keyedPool the keyedPool to enforce type safety on | |
182 | * @param type the class type to enforce. | |
183 | * @return a <code>KeyedObjectPool</code> that will only allow objects of <code>type</code> | |
184 | * @since Pool 1.3 | |
185 | */ | |
186 | public static KeyedObjectPool checkedPool(final KeyedObjectPool keyedPool, final Class type) { | |
187 | 0 | if (keyedPool == null) { |
188 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
189 | } | |
190 | 0 | if (type == null) { |
191 | 0 | throw new IllegalArgumentException("type must not be null."); |
192 | } | |
193 | 0 | return new CheckedKeyedObjectPool(keyedPool, type); |
194 | } | |
195 | ||
196 | /** | |
197 | * Periodically check the idle object count for the pool. At most one idle object will be added per period. | |
198 | * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed. | |
199 | * | |
200 | * @param pool the pool to check periodically. | |
201 | * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object. | |
202 | * @param period the frequency to check the number of idle objects in a pool, see | |
203 | * {@link Timer#schedule(TimerTask, long, long)}. | |
204 | * @return the {@link TimerTask} that will periodically check the pools idle object count. | |
205 | * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or | |
206 | * when <code>minIdle</code> is negative or when <code>period</code> isn't | |
207 | * valid for {@link Timer#schedule(TimerTask, long, long)}. | |
208 | * @since Pool 1.3 | |
209 | */ | |
210 | public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException { | |
211 | 0 | if (pool == null) { |
212 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
213 | } | |
214 | 0 | if (minIdle < 0) { |
215 | 0 | throw new IllegalArgumentException("minIdle must be non-negative."); |
216 | } | |
217 | 0 | final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle); |
218 | 0 | getMinIdleTimer().schedule(task, 0L, period); |
219 | 0 | return task; |
220 | } | |
221 | ||
222 | /** | |
223 | * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period. | |
224 | * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key | |
225 | * will be performed. | |
226 | * | |
227 | * @param keyedPool the keyedPool to check periodically. | |
228 | * @param key the key to check the idle count of. | |
229 | * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. | |
230 | * @param period the frequency to check the number of idle objects in a keyedPool, see | |
231 | * {@link Timer#schedule(TimerTask, long, long)}. | |
232 | * @return the {@link TimerTask} that will periodically check the pools idle object count. | |
233 | * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or | |
234 | * when <code>minIdle</code> is negative or when <code>period</code> isn't | |
235 | * valid for {@link Timer#schedule(TimerTask, long, long)}. | |
236 | * @since Pool 1.3 | |
237 | */ | |
238 | public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException { | |
239 | 0 | if (keyedPool == null) { |
240 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
241 | } | |
242 | 0 | if (key == null) { |
243 | 0 | throw new IllegalArgumentException("key must not be null."); |
244 | } | |
245 | 0 | if (minIdle < 0) { |
246 | 0 | throw new IllegalArgumentException("minIdle must be non-negative."); |
247 | } | |
248 | 0 | final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle); |
249 | 0 | getMinIdleTimer().schedule(task, 0L, period); |
250 | 0 | return task; |
251 | } | |
252 | ||
253 | /** | |
254 | * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool. | |
255 | * At most one idle object will be added per period. | |
256 | * | |
257 | * @param keyedPool the keyedPool to check periodically. | |
258 | * @param keys a collection of keys to check the idle object count. | |
259 | * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. | |
260 | * @param period the frequency to check the number of idle objects in a keyedPool, see | |
261 | * {@link Timer#schedule(TimerTask, long, long)}. | |
262 | * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count. | |
263 | * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the | |
264 | * collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't | |
265 | * valid for {@link Timer#schedule(TimerTask, long, long)}. | |
266 | * @see #checkMinIdle(KeyedObjectPool, Object, int, long) | |
267 | * @since Pool 1.3 | |
268 | */ | |
269 | public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException { | |
270 | 0 | if (keys == null) { |
271 | 0 | throw new IllegalArgumentException("keys must not be null."); |
272 | } | |
273 | 0 | final Map tasks = new HashMap(keys.size()); |
274 | 0 | final Iterator iter = keys.iterator(); |
275 | 0 | while (iter.hasNext()) { |
276 | 0 | final Object key = iter.next(); |
277 | 0 | final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period); |
278 | 0 | tasks.put(key, task); |
279 | 0 | } |
280 | 0 | return tasks; |
281 | } | |
282 | ||
283 | /** | |
284 | * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times. | |
285 | * | |
286 | * @param pool the pool to prefill. | |
287 | * @param count the number of idle objects to add. | |
288 | * @throws Exception when {@link ObjectPool#addObject()} fails. | |
289 | * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. | |
290 | * @since Pool 1.3 | |
291 | */ | |
292 | public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException { | |
293 | 0 | if (pool == null) { |
294 | 0 | throw new IllegalArgumentException("pool must not be null."); |
295 | } | |
296 | 0 | for (int i = 0; i < count; i++) { |
297 | 0 | pool.addObject(); |
298 | } | |
299 | 0 | } |
300 | ||
301 | /** | |
302 | * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code> | |
303 | * number of times. | |
304 | * | |
305 | * @param keyedPool the keyedPool to prefill. | |
306 | * @param key the key to add objects for. | |
307 | * @param count the number of idle objects to add for <code>key</code>. | |
308 | * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails. | |
309 | * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. | |
310 | * @since Pool 1.3 | |
311 | */ | |
312 | public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException { | |
313 | 0 | if (keyedPool == null) { |
314 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
315 | } | |
316 | 0 | if (key == null) { |
317 | 0 | throw new IllegalArgumentException("key must not be null."); |
318 | } | |
319 | 0 | for (int i = 0; i < count; i++) { |
320 | 0 | keyedPool.addObject(key); |
321 | } | |
322 | 0 | } |
323 | ||
324 | /** | |
325 | * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for | |
326 | * <code>count</code> number of times. This has the same effect as calling | |
327 | * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection. | |
328 | * | |
329 | * @param keyedPool the keyedPool to prefill. | |
330 | * @param keys {@link Collection} of keys to add objects for. | |
331 | * @param count the number of idle objects to add for each <code>key</code>. | |
332 | * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails. | |
333 | * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or | |
334 | * any value in <code>keys</code> is <code>null</code>. | |
335 | * @see #prefill(KeyedObjectPool, Object, int) | |
336 | * @since Pool 1.3 | |
337 | */ | |
338 | public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException { | |
339 | 0 | if (keys == null) { |
340 | 0 | throw new IllegalArgumentException("keys must not be null."); |
341 | } | |
342 | 0 | final Iterator iter = keys.iterator(); |
343 | 0 | while (iter.hasNext()) { |
344 | 0 | prefill(keyedPool, iter.next(), count); |
345 | } | |
346 | 0 | } |
347 | ||
348 | /** | |
349 | * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. | |
350 | * | |
351 | * <p><b>Note:</b> | |
352 | * This should not be used on pool implementations that already provide proper synchronization | |
353 | * such as the pools provided in the Commons Pool library. Wrapping a pool that | |
354 | * {@link #wait() waits} for poolable objects to be returned before allowing another one to be | |
355 | * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. | |
356 | * </p> | |
357 | * | |
358 | * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. | |
359 | * @return a synchronized view of the specified ObjectPool. | |
360 | * @since Pool 1.3 | |
361 | */ | |
362 | public static ObjectPool synchronizedPool(final ObjectPool pool) { | |
363 | 0 | if (pool == null) { |
364 | 0 | throw new IllegalArgumentException("pool must not be null."); |
365 | } | |
366 | /* | |
367 | assert !(pool instanceof GenericObjectPool) | |
368 | : "GenericObjectPool is already thread-safe"; | |
369 | assert !(pool instanceof SoftReferenceObjectPool) | |
370 | : "SoftReferenceObjectPool is already thread-safe"; | |
371 | assert !(pool instanceof StackObjectPool) | |
372 | : "StackObjectPool is already thread-safe"; | |
373 | assert !"org.apache.commons.pool.composite.CompositeObjectPool".equals(pool.getClass().getName()) | |
374 | : "CompositeObjectPools are already thread-safe"; | |
375 | */ | |
376 | 0 | return new SynchronizedObjectPool(pool); |
377 | } | |
378 | ||
379 | /** | |
380 | * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. | |
381 | * | |
382 | * <p><b>Note:</b> | |
383 | * This should not be used on pool implementations that already provide proper synchronization | |
384 | * such as the pools provided in the Commons Pool library. Wrapping a pool that | |
385 | * {@link #wait() waits} for poolable objects to be returned before allowing another one to be | |
386 | * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. | |
387 | * </p> | |
388 | * | |
389 | * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool. | |
390 | * @return a synchronized view of the specified KeyedObjectPool. | |
391 | * @since Pool 1.3 | |
392 | */ | |
393 | public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) { | |
394 | 0 | if (keyedPool == null) { |
395 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
396 | } | |
397 | /* | |
398 | assert !(keyedPool instanceof GenericKeyedObjectPool) | |
399 | : "GenericKeyedObjectPool is already thread-safe"; | |
400 | assert !(keyedPool instanceof StackKeyedObjectPool) | |
401 | : "StackKeyedObjectPool is already thread-safe"; | |
402 | assert !"org.apache.commons.pool.composite.CompositeKeyedObjectPool".equals(keyedPool.getClass().getName()) | |
403 | : "CompositeKeyedObjectPools are already thread-safe"; | |
404 | */ | |
405 | 0 | return new SynchronizedKeyedObjectPool(keyedPool); |
406 | } | |
407 | ||
408 | /** | |
409 | * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory. | |
410 | * | |
411 | * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory. | |
412 | * @return a synchronized view of the specified PoolableObjectFactory. | |
413 | * @since Pool 1.3 | |
414 | */ | |
415 | public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) { | |
416 | 0 | return new SynchronizedPoolableObjectFactory(factory); |
417 | } | |
418 | ||
419 | /** | |
420 | * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory. | |
421 | * | |
422 | * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory. | |
423 | * @return a synchronized view of the specified KeyedPoolableObjectFactory. | |
424 | * @since Pool 1.3 | |
425 | */ | |
426 | public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) { | |
427 | 0 | return new SynchronizedKeyedPoolableObjectFactory(keyedFactory); |
428 | } | |
429 | ||
430 | /** | |
431 | * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. | |
432 | * This is intended as an always thread-safe alternative to using an idle object evictor | |
433 | * provided by many pool implementations. This is also an effective way to shrink FIFO ordered | |
434 | * pools that experience load spikes. | |
435 | * | |
436 | * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. | |
437 | * @return a pool that adaptively decreases it's size when idle objects are no longer needed. | |
438 | * @see #erodingPool(ObjectPool, float) | |
439 | * @since Pool 1.4 | |
440 | */ | |
441 | public static ObjectPool erodingPool(final ObjectPool pool) { | |
442 | 0 | return erodingPool(pool, 1f); |
443 | } | |
444 | ||
445 | /** | |
446 | * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. | |
447 | * This is intended as an always thread-safe alternative to using an idle object evictor | |
448 | * provided by many pool implementations. This is also an effective way to shrink FIFO ordered | |
449 | * pools that experience load spikes. | |
450 | * | |
451 | * <p> | |
452 | * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink | |
453 | * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. | |
454 | * Values greater than 1 cause the pool to less frequently try to shrink it's size. | |
455 | * </p> | |
456 | * | |
457 | * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. | |
458 | * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. | |
459 | * If 0 < factor < 1 then the pool shrinks more aggressively. | |
460 | * If 1 < factor then the pool shrinks less aggressively. | |
461 | * @return a pool that adaptively decreases it's size when idle objects are no longer needed. | |
462 | * @see #erodingPool(ObjectPool) | |
463 | * @since Pool 1.4 | |
464 | */ | |
465 | public static ObjectPool erodingPool(final ObjectPool pool, final float factor) { | |
466 | 0 | if (pool == null) { |
467 | 0 | throw new IllegalArgumentException("pool must not be null."); |
468 | } | |
469 | 0 | if (factor <= 0f) { |
470 | 0 | throw new IllegalArgumentException("factor must be positive."); |
471 | } | |
472 | 0 | return new ErodingObjectPool(pool, factor); |
473 | } | |
474 | ||
475 | /** | |
476 | * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. | |
477 | * This is intended as an always thread-safe alternative to using an idle object evictor | |
478 | * provided by many pool implementations. This is also an effective way to shrink FIFO ordered | |
479 | * pools that experience load spikes. | |
480 | * | |
481 | * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when | |
482 | * possible. | |
483 | * @return a pool that adaptively decreases it's size when idle objects are no longer needed. | |
484 | * @see #erodingPool(KeyedObjectPool, float) | |
485 | * @see #erodingPool(KeyedObjectPool, float, boolean) | |
486 | * @since Pool 1.4 | |
487 | */ | |
488 | public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool) { | |
489 | 0 | return erodingPool(keyedPool, 1f); |
490 | } | |
491 | ||
492 | /** | |
493 | * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. | |
494 | * This is intended as an always thread-safe alternative to using an idle object evictor | |
495 | * provided by many pool implementations. This is also an effective way to shrink FIFO ordered | |
496 | * pools that experience load spikes. | |
497 | * | |
498 | * <p> | |
499 | * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink | |
500 | * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. | |
501 | * Values greater than 1 cause the pool to less frequently try to shrink it's size. | |
502 | * </p> | |
503 | * | |
504 | * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when | |
505 | * possible. | |
506 | * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. | |
507 | * If 0 < factor < 1 then the pool shrinks more aggressively. | |
508 | * If 1 < factor then the pool shrinks less aggressively. | |
509 | * @return a pool that adaptively decreases it's size when idle objects are no longer needed. | |
510 | * @see #erodingPool(KeyedObjectPool, float, boolean) | |
511 | * @since Pool 1.4 | |
512 | */ | |
513 | public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor) { | |
514 | 0 | return erodingPool(keyedPool, factor, false); |
515 | } | |
516 | ||
517 | /** | |
518 | * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. | |
519 | * This is intended as an always thread-safe alternative to using an idle object evictor | |
520 | * provided by many pool implementations. This is also an effective way to shrink FIFO ordered | |
521 | * pools that experience load spikes. | |
522 | * | |
523 | * <p> | |
524 | * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink | |
525 | * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. | |
526 | * Values greater than 1 cause the pool to less frequently try to shrink it's size. | |
527 | * </p> | |
528 | * | |
529 | * <p> | |
530 | * The perKey parameter determines if the pool shrinks on a whole pool basis or a per key basis. | |
531 | * When perKey is false, the keys do not have an effect on the rate at which the pool tries to | |
532 | * shrink it's size. When perKey is true, each key is shrunk independently. | |
533 | * </p> | |
534 | * | |
535 | * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when | |
536 | * possible. | |
537 | * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. | |
538 | * If 0 < factor < 1 then the pool shrinks more aggressively. | |
539 | * If 1 < factor then the pool shrinks less aggressively. | |
540 | * @param perKey when true, each key is treated independently. | |
541 | * @return a pool that adaptively decreases it's size when idle objects are no longer needed. | |
542 | * @see #erodingPool(KeyedObjectPool) | |
543 | * @see #erodingPool(KeyedObjectPool, float) | |
544 | * @since Pool 1.4 | |
545 | */ | |
546 | public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor, final boolean perKey) { | |
547 | 0 | if (keyedPool == null) { |
548 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
549 | } | |
550 | 0 | if (factor <= 0f) { |
551 | 0 | throw new IllegalArgumentException("factor must be positive."); |
552 | } | |
553 | 0 | if (perKey) { |
554 | 0 | return new ErodingPerKeyKeyedObjectPool(keyedPool, factor); |
555 | } else { | |
556 | 0 | return new ErodingKeyedObjectPool(keyedPool, factor); |
557 | } | |
558 | } | |
559 | ||
560 | /** | |
561 | * Get the <code>Timer</code> for checking keyedPool's idle count. Lazily create the {@link Timer} as needed. | |
562 | * | |
563 | * @return the {@link Timer} for checking keyedPool's idle count. | |
564 | * @since Pool 1.3 | |
565 | */ | |
566 | private static synchronized Timer getMinIdleTimer() { | |
567 | 0 | if (MIN_IDLE_TIMER == null) { |
568 | 0 | MIN_IDLE_TIMER = new Timer(true); |
569 | } | |
570 | 0 | return MIN_IDLE_TIMER; |
571 | } | |
572 | ||
573 | /** | |
574 | * Adaptor class that wraps and converts a KeyedPoolableObjectFactory with a fixed | |
575 | * key to a PoolableObjectFactory. | |
576 | */ | |
577 | private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory { | |
578 | /** Fixed key */ | |
579 | private final Object key; | |
580 | ||
581 | /** Wrapped factory */ | |
582 | private final KeyedPoolableObjectFactory keyedFactory; | |
583 | ||
584 | /** | |
585 | * Create a PoolableObjectFactoryAdaptor wrapping the provided KeyedPoolableObjectFactory with the | |
586 | * given fixed key. | |
587 | * | |
588 | * @param keyedFactory KeyedPoolableObjectFactory that will manage objects | |
589 | * @param key fixed key | |
590 | * @throws IllegalArgumentException if either of the parameters is null | |
591 | */ | |
592 | PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key) | |
593 | 0 | throws IllegalArgumentException { |
594 | 0 | if (keyedFactory == null) { |
595 | 0 | throw new IllegalArgumentException("keyedFactory must not be null."); |
596 | } | |
597 | 0 | if (key == null) { |
598 | 0 | throw new IllegalArgumentException("key must not be null."); |
599 | } | |
600 | 0 | this.keyedFactory = keyedFactory; |
601 | 0 | this.key = key; |
602 | 0 | } |
603 | ||
604 | /** | |
605 | * Create an object instance using the configured factory and key. | |
606 | * | |
607 | * @return new object instance | |
608 | */ | |
609 | public Object makeObject() throws Exception { | |
610 | 0 | return keyedFactory.makeObject(key); |
611 | } | |
612 | ||
613 | /** | |
614 | * Destroy the object, passing the fixed key to the factory. | |
615 | * | |
616 | * @param obj object to destroy | |
617 | */ | |
618 | public void destroyObject(final Object obj) throws Exception { | |
619 | 0 | keyedFactory.destroyObject(key, obj); |
620 | 0 | } |
621 | ||
622 | /** | |
623 | * Validate the object, passing the fixed key to the factory. | |
624 | * | |
625 | * @param obj object to validate | |
626 | * @return true if validation is successful | |
627 | */ | |
628 | public boolean validateObject(final Object obj) { | |
629 | 0 | return keyedFactory.validateObject(key, obj); |
630 | } | |
631 | ||
632 | /** | |
633 | * Activate the object, passing the fixed key to the factory. | |
634 | * | |
635 | * @param obj object to activate | |
636 | */ | |
637 | public void activateObject(final Object obj) throws Exception { | |
638 | 0 | keyedFactory.activateObject(key, obj); |
639 | 0 | } |
640 | ||
641 | /** | |
642 | * Passivate the object, passing the fixed key to the factory. | |
643 | * | |
644 | * @param obj object to passivate | |
645 | */ | |
646 | public void passivateObject(final Object obj) throws Exception { | |
647 | 0 | keyedFactory.passivateObject(key, obj); |
648 | 0 | } |
649 | ||
650 | /** | |
651 | * {@inheritDoc} | |
652 | */ | |
653 | public String toString() { | |
654 | 0 | final StringBuffer sb = new StringBuffer(); |
655 | 0 | sb.append("PoolableObjectFactoryAdaptor"); |
656 | 0 | sb.append("{key=").append(key); |
657 | 0 | sb.append(", keyedFactory=").append(keyedFactory); |
658 | 0 | sb.append('}'); |
659 | 0 | return sb.toString(); |
660 | } | |
661 | } | |
662 | ||
663 | /** | |
664 | * Adaptor class that turns a PoolableObjectFactory into a KeyedPoolableObjectFactory by | |
665 | * ignoring keys. | |
666 | */ | |
667 | private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory { | |
668 | ||
669 | /** Underlying PoolableObjectFactory */ | |
670 | private final PoolableObjectFactory factory; | |
671 | ||
672 | /** | |
673 | * Create a new KeyedPoolableObjectFactoryAdaptor using the given PoolableObjectFactory to | |
674 | * manage objects. | |
675 | * | |
676 | * @param factory wrapped PoolableObjectFactory | |
677 | * @throws IllegalArgumentException if the factory is null | |
678 | */ | |
679 | 0 | KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException { |
680 | 0 | if (factory == null) { |
681 | 0 | throw new IllegalArgumentException("factory must not be null."); |
682 | } | |
683 | 0 | this.factory = factory; |
684 | 0 | } |
685 | ||
686 | /** | |
687 | * Create a new object instance, ignoring the key | |
688 | * | |
689 | * @param key ignored | |
690 | * @return newly created object instance | |
691 | */ | |
692 | public Object makeObject(final Object key) throws Exception { | |
693 | 0 | return factory.makeObject(); |
694 | } | |
695 | ||
696 | /** | |
697 | * Destroy the object, ignoring the key. | |
698 | * | |
699 | * @param key ignored | |
700 | * @param obj instance to destroy | |
701 | */ | |
702 | public void destroyObject(final Object key, final Object obj) throws Exception { | |
703 | 0 | factory.destroyObject(obj); |
704 | 0 | } |
705 | ||
706 | /** | |
707 | * Validate the object, ignoring the key | |
708 | * | |
709 | * @param key ignored | |
710 | * @param obj object to validate | |
711 | * @return true if validation is successful | |
712 | */ | |
713 | public boolean validateObject(final Object key, final Object obj) { | |
714 | 0 | return factory.validateObject(obj); |
715 | } | |
716 | ||
717 | /** | |
718 | * Activate the object, ignoring the key. | |
719 | * | |
720 | * @param key ignored | |
721 | * @param obj object to be activated | |
722 | */ | |
723 | public void activateObject(final Object key, final Object obj) throws Exception { | |
724 | 0 | factory.activateObject(obj); |
725 | 0 | } |
726 | ||
727 | /** | |
728 | * Passivate the object, ignoring the key. | |
729 | * | |
730 | * @param key ignored | |
731 | * @param obj object to passivate | |
732 | */ | |
733 | public void passivateObject(final Object key, final Object obj) throws Exception { | |
734 | 0 | factory.passivateObject(obj); |
735 | 0 | } |
736 | ||
737 | /** | |
738 | * {@inheritDoc} | |
739 | */ | |
740 | public String toString() { | |
741 | 0 | final StringBuffer sb = new StringBuffer(); |
742 | 0 | sb.append("KeyedPoolableObjectFactoryAdaptor"); |
743 | 0 | sb.append("{factory=").append(factory); |
744 | 0 | sb.append('}'); |
745 | 0 | return sb.toString(); |
746 | } | |
747 | } | |
748 | ||
749 | /** | |
750 | * Adapts a KeyedObjectPool to make it an ObjectPool by fixing restricting to | |
751 | * a fixed key. | |
752 | */ | |
753 | private static class ObjectPoolAdaptor implements ObjectPool { | |
754 | ||
755 | /** Fixed key */ | |
756 | private final Object key; | |
757 | ||
758 | /** Underlying KeyedObjectPool */ | |
759 | private final KeyedObjectPool keyedPool; | |
760 | ||
761 | /** | |
762 | * Create a new ObjectPoolAdaptor using the provided KeyedObjectPool and fixed key. | |
763 | * | |
764 | * @param keyedPool underlying KeyedObjectPool | |
765 | * @param key fixed key | |
766 | * @throws IllegalArgumentException if either of the parameters is null | |
767 | */ | |
768 | 0 | ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException { |
769 | 0 | if (keyedPool == null) { |
770 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
771 | } | |
772 | 0 | if (key == null) { |
773 | 0 | throw new IllegalArgumentException("key must not be null."); |
774 | } | |
775 | 0 | this.keyedPool = keyedPool; |
776 | 0 | this.key = key; |
777 | 0 | } |
778 | ||
779 | /** | |
780 | * {@inheritDoc} | |
781 | */ | |
782 | public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { | |
783 | 0 | return keyedPool.borrowObject(key); |
784 | } | |
785 | ||
786 | /** | |
787 | * {@inheritDoc} | |
788 | */ | |
789 | public void returnObject(final Object obj) { | |
790 | try { | |
791 | 0 | keyedPool.returnObject(key, obj); |
792 | 0 | } catch (Exception e) { |
793 | // swallowed as of Pool 2 | |
794 | 0 | } |
795 | 0 | } |
796 | ||
797 | /** | |
798 | * {@inheritDoc} | |
799 | */ | |
800 | public void invalidateObject(final Object obj) { | |
801 | try { | |
802 | 0 | keyedPool.invalidateObject(key, obj); |
803 | 0 | } catch (Exception e) { |
804 | // swallowed as of Pool 2 | |
805 | 0 | } |
806 | 0 | } |
807 | ||
808 | /** | |
809 | * {@inheritDoc} | |
810 | */ | |
811 | public void addObject() throws Exception, IllegalStateException { | |
812 | 0 | keyedPool.addObject(key); |
813 | 0 | } |
814 | ||
815 | /** | |
816 | * {@inheritDoc} | |
817 | */ | |
818 | public int getNumIdle() throws UnsupportedOperationException { | |
819 | 0 | return keyedPool.getNumIdle(key); |
820 | } | |
821 | ||
822 | /** | |
823 | * {@inheritDoc} | |
824 | */ | |
825 | public int getNumActive() throws UnsupportedOperationException { | |
826 | 0 | return keyedPool.getNumActive(key); |
827 | } | |
828 | ||
829 | /** | |
830 | * {@inheritDoc} | |
831 | */ | |
832 | public void clear() throws Exception, UnsupportedOperationException { | |
833 | 0 | keyedPool.clear(); |
834 | 0 | } |
835 | ||
836 | /** | |
837 | * {@inheritDoc} | |
838 | */ | |
839 | public void close() { | |
840 | try { | |
841 | 0 | keyedPool.close(); |
842 | 0 | } catch (Exception e) { |
843 | // swallowed as of Pool 2 | |
844 | 0 | } |
845 | 0 | } |
846 | ||
847 | /** | |
848 | * Sets the PoolableObjectFactory for the pool. | |
849 | * | |
850 | * @param factory new PoolableObjectFactory | |
851 | * @deprecated to be removed in version 2.0 | |
852 | */ | |
853 | public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
854 | 0 | keyedPool.setFactory(adapt(factory)); |
855 | 0 | } |
856 | ||
857 | /** | |
858 | * {@inheritDoc} | |
859 | */ | |
860 | public String toString() { | |
861 | 0 | final StringBuffer sb = new StringBuffer(); |
862 | 0 | sb.append("ObjectPoolAdaptor"); |
863 | 0 | sb.append("{key=").append(key); |
864 | 0 | sb.append(", keyedPool=").append(keyedPool); |
865 | 0 | sb.append('}'); |
866 | 0 | return sb.toString(); |
867 | } | |
868 | } | |
869 | ||
870 | /** | |
871 | * Adapts an ObjectPool to implement KeyedObjectPool by ignoring key arguments. | |
872 | */ | |
873 | private static class KeyedObjectPoolAdaptor implements KeyedObjectPool { | |
874 | ||
875 | /** Underlying pool */ | |
876 | private final ObjectPool pool; | |
877 | ||
878 | /** | |
879 | * Create a new KeyedObjectPoolAdaptor wrapping the given ObjectPool | |
880 | * | |
881 | * @param pool underlying object pool | |
882 | * @throws IllegalArgumentException if pool is null | |
883 | */ | |
884 | 0 | KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException { |
885 | 0 | if (pool == null) { |
886 | 0 | throw new IllegalArgumentException("pool must not be null."); |
887 | } | |
888 | 0 | this.pool = pool; |
889 | 0 | } |
890 | ||
891 | /** | |
892 | * Borrow and object from the pool, ignoring the key | |
893 | * | |
894 | * @param key ignored | |
895 | * @return newly created object instance | |
896 | */ | |
897 | public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { | |
898 | 0 | return pool.borrowObject(); |
899 | } | |
900 | ||
901 | /** | |
902 | * Return and object to the pool, ignoring the key | |
903 | * | |
904 | * @param key ignored | |
905 | * @param obj object to return | |
906 | */ | |
907 | public void returnObject(final Object key, final Object obj) { | |
908 | try { | |
909 | 0 | pool.returnObject(obj); |
910 | 0 | } catch (Exception e) { |
911 | // swallowed as of Pool 2 | |
912 | 0 | } |
913 | 0 | } |
914 | ||
915 | /** | |
916 | * Invalidate and object, ignoring the key | |
917 | * | |
918 | * @param obj object to invalidate | |
919 | * @param key ignored | |
920 | */ | |
921 | public void invalidateObject(final Object key, final Object obj) { | |
922 | try { | |
923 | 0 | pool.invalidateObject(obj); |
924 | 0 | } catch (Exception e) { |
925 | // swallowed as of Pool 2 | |
926 | 0 | } |
927 | 0 | } |
928 | ||
929 | /** | |
930 | * Add an object to the pool, ignoring the key | |
931 | * | |
932 | * @param key ignored | |
933 | */ | |
934 | public void addObject(final Object key) throws Exception, IllegalStateException { | |
935 | 0 | pool.addObject(); |
936 | 0 | } |
937 | ||
938 | /** | |
939 | * Return the number of objects idle in the pool, ignoring the key. | |
940 | * | |
941 | * @param key ignored | |
942 | * @return idle instance count | |
943 | */ | |
944 | public int getNumIdle(final Object key) throws UnsupportedOperationException { | |
945 | 0 | return pool.getNumIdle(); |
946 | } | |
947 | ||
948 | /** | |
949 | * Return the number of objects checked out from the pool, ignoring the key. | |
950 | * | |
951 | * @param key ignored | |
952 | * @return active instance count | |
953 | */ | |
954 | public int getNumActive(final Object key) throws UnsupportedOperationException { | |
955 | 0 | return pool.getNumActive(); |
956 | } | |
957 | ||
958 | /** | |
959 | * {@inheritDoc} | |
960 | */ | |
961 | public int getNumIdle() throws UnsupportedOperationException { | |
962 | 0 | return pool.getNumIdle(); |
963 | } | |
964 | ||
965 | /** | |
966 | * {@inheritDoc} | |
967 | */ | |
968 | public int getNumActive() throws UnsupportedOperationException { | |
969 | 0 | return pool.getNumActive(); |
970 | } | |
971 | ||
972 | /** | |
973 | * {@inheritDoc} | |
974 | */ | |
975 | public void clear() throws Exception, UnsupportedOperationException { | |
976 | 0 | pool.clear(); |
977 | 0 | } |
978 | ||
979 | /** | |
980 | * Clear the pool, ignoring the key (has same effect as {@link #clear()}. | |
981 | * | |
982 | * @param key ignored. | |
983 | */ | |
984 | public void clear(final Object key) throws Exception, UnsupportedOperationException { | |
985 | 0 | pool.clear(); |
986 | 0 | } |
987 | ||
988 | /** | |
989 | * {@inheritDoc} | |
990 | */ | |
991 | public void close() { | |
992 | try { | |
993 | 0 | pool.close(); |
994 | 0 | } catch (Exception e) { |
995 | // swallowed as of Pool 2 | |
996 | 0 | } |
997 | 0 | } |
998 | ||
999 | /** | |
1000 | * Sets the factory used to manage objects. | |
1001 | * | |
1002 | * @param factory new factory to use managing object instances | |
1003 | * @deprecated to be removed in version 2.0 | |
1004 | */ | |
1005 | public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
1006 | 0 | pool.setFactory(adapt(factory)); |
1007 | 0 | } |
1008 | ||
1009 | /** | |
1010 | * {@inheritDoc} | |
1011 | */ | |
1012 | public String toString() { | |
1013 | 0 | final StringBuffer sb = new StringBuffer(); |
1014 | 0 | sb.append("KeyedObjectPoolAdaptor"); |
1015 | 0 | sb.append("{pool=").append(pool); |
1016 | 0 | sb.append('}'); |
1017 | 0 | return sb.toString(); |
1018 | } | |
1019 | } | |
1020 | ||
1021 | /** | |
1022 | * An object pool that performs type checking on objects passed | |
1023 | * to pool methods. | |
1024 | * | |
1025 | */ | |
1026 | private static class CheckedObjectPool implements ObjectPool { | |
1027 | /** | |
1028 | * Type of objects allowed in the pool. This should be a subtype of the return type of | |
1029 | * the underlying pool's associated object factory. | |
1030 | */ | |
1031 | private final Class type; | |
1032 | ||
1033 | /** Underlying object pool */ | |
1034 | private final ObjectPool pool; | |
1035 | ||
1036 | /** | |
1037 | * Create a CheckedObjectPool accepting objects of the given type using | |
1038 | * the given pool. | |
1039 | * | |
1040 | * @param pool underlying object pool | |
1041 | * @param type expected pooled object type | |
1042 | * @throws IllegalArgumentException if either parameter is null | |
1043 | */ | |
1044 | 0 | CheckedObjectPool(final ObjectPool pool, final Class type) { |
1045 | 0 | if (pool == null) { |
1046 | 0 | throw new IllegalArgumentException("pool must not be null."); |
1047 | } | |
1048 | 0 | if (type == null) { |
1049 | 0 | throw new IllegalArgumentException("type must not be null."); |
1050 | } | |
1051 | 0 | this.pool = pool; |
1052 | 0 | this.type = type; |
1053 | 0 | } |
1054 | ||
1055 | /** | |
1056 | * Borrow an object from the pool, checking its type. | |
1057 | * | |
1058 | * @return a type-checked object from the pool | |
1059 | * @throws ClassCastException if the object returned by the pool is not of the expected type | |
1060 | */ | |
1061 | public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { | |
1062 | 0 | final Object obj = pool.borrowObject(); |
1063 | 0 | if (type.isInstance(obj)) { |
1064 | 0 | return obj; |
1065 | } else { | |
1066 | 0 | throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj); |
1067 | } | |
1068 | } | |
1069 | ||
1070 | /** | |
1071 | * Return an object to the pool, verifying that it is of the correct type. | |
1072 | * | |
1073 | * @param obj object to return | |
1074 | * @throws ClassCastException if obj is not of the expected type | |
1075 | */ | |
1076 | public void returnObject(final Object obj) { | |
1077 | 0 | if (type.isInstance(obj)) { |
1078 | try { | |
1079 | 0 | pool.returnObject(obj); |
1080 | 0 | } catch (Exception e) { |
1081 | // swallowed as of Pool 2 | |
1082 | 0 | } |
1083 | } else { | |
1084 | 0 | throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj); |
1085 | } | |
1086 | 0 | } |
1087 | ||
1088 | /** | |
1089 | * Invalidates an object from the pool, verifying that it is of the expected type. | |
1090 | * | |
1091 | * @param obj object to invalidate | |
1092 | * @throws ClassCastException if obj is not of the expected type | |
1093 | */ | |
1094 | public void invalidateObject(final Object obj) { | |
1095 | 0 | if (type.isInstance(obj)) { |
1096 | try { | |
1097 | 0 | pool.invalidateObject(obj); |
1098 | 0 | } catch (Exception e) { |
1099 | // swallowed as of Pool 2 | |
1100 | 0 | } |
1101 | } else { | |
1102 | 0 | throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj); |
1103 | } | |
1104 | 0 | } |
1105 | ||
1106 | /** | |
1107 | * {@inheritDoc} | |
1108 | */ | |
1109 | public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { | |
1110 | 0 | pool.addObject(); |
1111 | 0 | } |
1112 | ||
1113 | /** | |
1114 | * {@inheritDoc} | |
1115 | */ | |
1116 | public int getNumIdle() throws UnsupportedOperationException { | |
1117 | 0 | return pool.getNumIdle(); |
1118 | } | |
1119 | ||
1120 | /** | |
1121 | * {@inheritDoc} | |
1122 | */ | |
1123 | public int getNumActive() throws UnsupportedOperationException { | |
1124 | 0 | return pool.getNumActive(); |
1125 | } | |
1126 | ||
1127 | /** | |
1128 | * {@inheritDoc} | |
1129 | */ | |
1130 | public void clear() throws Exception, UnsupportedOperationException { | |
1131 | 0 | pool.clear(); |
1132 | 0 | } |
1133 | ||
1134 | /** | |
1135 | * {@inheritDoc} | |
1136 | */ | |
1137 | public void close() { | |
1138 | try { | |
1139 | 0 | pool.close(); |
1140 | 0 | } catch (Exception e) { |
1141 | // swallowed as of Pool 2 | |
1142 | 0 | } |
1143 | 0 | } |
1144 | ||
1145 | /** | |
1146 | * Sets the object factory associated with the pool | |
1147 | * | |
1148 | * @param factory object factory | |
1149 | * @deprecated to be removed in version 2.0 | |
1150 | */ | |
1151 | public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
1152 | 0 | pool.setFactory(factory); |
1153 | 0 | } |
1154 | ||
1155 | /** | |
1156 | * {@inheritDoc} | |
1157 | */ | |
1158 | public String toString() { | |
1159 | 0 | final StringBuffer sb = new StringBuffer(); |
1160 | 0 | sb.append("CheckedObjectPool"); |
1161 | 0 | sb.append("{type=").append(type); |
1162 | 0 | sb.append(", pool=").append(pool); |
1163 | 0 | sb.append('}'); |
1164 | 0 | return sb.toString(); |
1165 | } | |
1166 | } | |
1167 | ||
1168 | /** | |
1169 | * A keyed object pool that performs type checking on objects passed | |
1170 | * to pool methods. | |
1171 | * | |
1172 | */ | |
1173 | private static class CheckedKeyedObjectPool implements KeyedObjectPool { | |
1174 | /** | |
1175 | * Expected type of objects managed by the pool. This should be | |
1176 | * a subtype of the return type of the object factory used by the pool. | |
1177 | */ | |
1178 | private final Class type; | |
1179 | ||
1180 | /** Underlying pool */ | |
1181 | private final KeyedObjectPool keyedPool; | |
1182 | ||
1183 | /** | |
1184 | * Create a new CheckedKeyedObjectPool from the given pool with given expected object type. | |
1185 | * | |
1186 | * @param keyedPool underlying pool | |
1187 | * @param type expected object type | |
1188 | * @throws IllegalArgumentException if either parameter is null | |
1189 | */ | |
1190 | 0 | CheckedKeyedObjectPool(final KeyedObjectPool keyedPool, final Class type) { |
1191 | 0 | if (keyedPool == null) { |
1192 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
1193 | } | |
1194 | 0 | if (type == null) { |
1195 | 0 | throw new IllegalArgumentException("type must not be null."); |
1196 | } | |
1197 | 0 | this.keyedPool = keyedPool; |
1198 | 0 | this.type = type; |
1199 | 0 | } |
1200 | ||
1201 | /** | |
1202 | * Borrow an object from the pool, verifying correct return type. | |
1203 | * | |
1204 | * @param key pool key | |
1205 | * @return type-checked object from the pool under the given key | |
1206 | * @throws ClassCastException if the object returned by the pool is not of the expected type | |
1207 | */ | |
1208 | public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { | |
1209 | 0 | Object obj = keyedPool.borrowObject(key); |
1210 | 0 | if (type.isInstance(obj)) { |
1211 | 0 | return obj; |
1212 | } else { | |
1213 | 0 | throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); |
1214 | } | |
1215 | } | |
1216 | ||
1217 | /** | |
1218 | * Return an object to the pool, checking its type. | |
1219 | * | |
1220 | * @param key the associated key (not type-checked) | |
1221 | * @param obj the object to return (type-checked) | |
1222 | * @throws ClassCastException if obj is not of the expected type | |
1223 | */ | |
1224 | public void returnObject(final Object key, final Object obj) { | |
1225 | 0 | if (type.isInstance(obj)) { |
1226 | try { | |
1227 | 0 | keyedPool.returnObject(key, obj); |
1228 | 0 | } catch (Exception e) { |
1229 | // swallowed as of Pool 2 | |
1230 | 0 | } |
1231 | } else { | |
1232 | 0 | throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); |
1233 | } | |
1234 | 0 | } |
1235 | ||
1236 | /** | |
1237 | * Invalidate an object to the pool, checking its type. | |
1238 | * | |
1239 | * @param key the associated key (not type-checked) | |
1240 | * @param obj the object to return (type-checked) | |
1241 | * @throws ClassCastException if obj is not of the expected type | |
1242 | */ | |
1243 | public void invalidateObject(final Object key, final Object obj) { | |
1244 | 0 | if (type.isInstance(obj)) { |
1245 | try { | |
1246 | 0 | keyedPool.invalidateObject(key, obj); |
1247 | 0 | } catch (Exception e) { |
1248 | // swallowed as of Pool 2 | |
1249 | 0 | } |
1250 | } else { | |
1251 | 0 | throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); |
1252 | } | |
1253 | 0 | } |
1254 | ||
1255 | /** | |
1256 | * {@inheritDoc} | |
1257 | */ | |
1258 | public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { | |
1259 | 0 | keyedPool.addObject(key); |
1260 | 0 | } |
1261 | ||
1262 | /** | |
1263 | * {@inheritDoc} | |
1264 | */ | |
1265 | public int getNumIdle(final Object key) throws UnsupportedOperationException { | |
1266 | 0 | return keyedPool.getNumIdle(key); |
1267 | } | |
1268 | ||
1269 | /** | |
1270 | * {@inheritDoc} | |
1271 | */ | |
1272 | public int getNumActive(final Object key) throws UnsupportedOperationException { | |
1273 | 0 | return keyedPool.getNumActive(key); |
1274 | } | |
1275 | ||
1276 | /** | |
1277 | * {@inheritDoc} | |
1278 | */ | |
1279 | public int getNumIdle() throws UnsupportedOperationException { | |
1280 | 0 | return keyedPool.getNumIdle(); |
1281 | } | |
1282 | ||
1283 | /** | |
1284 | * {@inheritDoc} | |
1285 | */ | |
1286 | public int getNumActive() throws UnsupportedOperationException { | |
1287 | 0 | return keyedPool.getNumActive(); |
1288 | } | |
1289 | ||
1290 | /** | |
1291 | * {@inheritDoc} | |
1292 | */ | |
1293 | public void clear() throws Exception, UnsupportedOperationException { | |
1294 | 0 | keyedPool.clear(); |
1295 | 0 | } |
1296 | ||
1297 | /** | |
1298 | * {@inheritDoc} | |
1299 | */ | |
1300 | public void clear(final Object key) throws Exception, UnsupportedOperationException { | |
1301 | 0 | keyedPool.clear(key); |
1302 | 0 | } |
1303 | ||
1304 | /** | |
1305 | * {@inheritDoc} | |
1306 | */ | |
1307 | public void close() { | |
1308 | try { | |
1309 | 0 | keyedPool.close(); |
1310 | 0 | } catch (Exception e) { |
1311 | // swallowed as of Pool 2 | |
1312 | 0 | } |
1313 | 0 | } |
1314 | ||
1315 | /** | |
1316 | * Sets the object factory associated with the pool | |
1317 | * | |
1318 | * @param factory object factory | |
1319 | * @deprecated to be removed in version 2.0 | |
1320 | */ | |
1321 | public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
1322 | 0 | keyedPool.setFactory(factory); |
1323 | 0 | } |
1324 | ||
1325 | /** | |
1326 | * {@inheritDoc} | |
1327 | */ | |
1328 | public String toString() { | |
1329 | 0 | final StringBuffer sb = new StringBuffer(); |
1330 | 0 | sb.append("CheckedKeyedObjectPool"); |
1331 | 0 | sb.append("{type=").append(type); |
1332 | 0 | sb.append(", keyedPool=").append(keyedPool); |
1333 | 0 | sb.append('}'); |
1334 | 0 | return sb.toString(); |
1335 | } | |
1336 | } | |
1337 | ||
1338 | /** | |
1339 | * Timer task that adds objects to the pool until the number of idle | |
1340 | * instances reaches the configured minIdle. Note that this is not the | |
1341 | * same as the pool's minIdle setting. | |
1342 | * | |
1343 | */ | |
1344 | private static class ObjectPoolMinIdleTimerTask extends TimerTask { | |
1345 | ||
1346 | /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ | |
1347 | private final int minIdle; | |
1348 | ||
1349 | /** Object pool */ | |
1350 | private final ObjectPool pool; | |
1351 | ||
1352 | /** | |
1353 | * Create a new ObjectPoolMinIdleTimerTask for the given pool with the given minIdle setting. | |
1354 | * | |
1355 | * @param pool object pool | |
1356 | * @param minIdle number of idle instances to maintain | |
1357 | * @throws IllegalArgumentException if the pool is null | |
1358 | */ | |
1359 | 0 | ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException { |
1360 | 0 | if (pool == null) { |
1361 | 0 | throw new IllegalArgumentException("pool must not be null."); |
1362 | } | |
1363 | 0 | this.pool = pool; |
1364 | 0 | this.minIdle = minIdle; |
1365 | 0 | } |
1366 | ||
1367 | /** | |
1368 | * {@inheritDoc} | |
1369 | */ | |
1370 | public void run() { | |
1371 | 0 | boolean success = false; |
1372 | try { | |
1373 | 0 | if (pool.getNumIdle() < minIdle) { |
1374 | 0 | pool.addObject(); |
1375 | } | |
1376 | 0 | success = true; |
1377 | ||
1378 | 0 | } catch (Exception e) { |
1379 | 0 | cancel(); |
1380 | ||
1381 | } finally { | |
1382 | // detect other types of Throwable and cancel this Timer | |
1383 | 0 | if (!success) { |
1384 | 0 | cancel(); |
1385 | } | |
1386 | } | |
1387 | 0 | } |
1388 | ||
1389 | /** | |
1390 | * {@inheritDoc} | |
1391 | */ | |
1392 | public String toString() { | |
1393 | 0 | final StringBuffer sb = new StringBuffer(); |
1394 | 0 | sb.append("ObjectPoolMinIdleTimerTask"); |
1395 | 0 | sb.append("{minIdle=").append(minIdle); |
1396 | 0 | sb.append(", pool=").append(pool); |
1397 | 0 | sb.append('}'); |
1398 | 0 | return sb.toString(); |
1399 | } | |
1400 | } | |
1401 | ||
1402 | /** | |
1403 | * Timer task that adds objects to the pool until the number of idle | |
1404 | * instances for the given key reaches the configured minIdle. Note that this is not the | |
1405 | * same as the pool's minIdle setting. | |
1406 | * | |
1407 | */ | |
1408 | private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask { | |
1409 | /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ | |
1410 | private final int minIdle; | |
1411 | ||
1412 | /** Key to ensure minIdle for */ | |
1413 | private final Object key; | |
1414 | ||
1415 | /** Keyed object pool */ | |
1416 | private final KeyedObjectPool keyedPool; | |
1417 | ||
1418 | /** | |
1419 | * Create a new KeyedObjecPoolMinIdleTimerTask. | |
1420 | * | |
1421 | * @param keyedPool keyed object pool | |
1422 | * @param key key to ensure minimum number of idle instances | |
1423 | * @param minIdle minimum number of idle instances | |
1424 | * @throws IllegalArgumentException if the key is null | |
1425 | */ | |
1426 | 0 | KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, final Object key, final int minIdle) throws IllegalArgumentException { |
1427 | 0 | if (keyedPool == null) { |
1428 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
1429 | } | |
1430 | 0 | this.keyedPool = keyedPool; |
1431 | 0 | this.key = key; |
1432 | 0 | this.minIdle = minIdle; |
1433 | 0 | } |
1434 | ||
1435 | /** | |
1436 | * {@inheritDoc} | |
1437 | */ | |
1438 | public void run() { | |
1439 | 0 | boolean success = false; |
1440 | try { | |
1441 | 0 | if (keyedPool.getNumIdle(key) < minIdle) { |
1442 | 0 | keyedPool.addObject(key); |
1443 | } | |
1444 | 0 | success = true; |
1445 | ||
1446 | 0 | } catch (Exception e) { |
1447 | 0 | cancel(); |
1448 | ||
1449 | } finally { | |
1450 | // detect other types of Throwable and cancel this Timer | |
1451 | 0 | if (!success) { |
1452 | 0 | cancel(); |
1453 | } | |
1454 | } | |
1455 | 0 | } |
1456 | ||
1457 | /** | |
1458 | * {@inheritDoc} | |
1459 | */ | |
1460 | public String toString() { | |
1461 | 0 | final StringBuffer sb = new StringBuffer(); |
1462 | 0 | sb.append("KeyedObjectPoolMinIdleTimerTask"); |
1463 | 0 | sb.append("{minIdle=").append(minIdle); |
1464 | 0 | sb.append(", key=").append(key); |
1465 | 0 | sb.append(", keyedPool=").append(keyedPool); |
1466 | 0 | sb.append('}'); |
1467 | 0 | return sb.toString(); |
1468 | } | |
1469 | } | |
1470 | ||
1471 | /** | |
1472 | * A synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. | |
1473 | * | |
1474 | * <p><b>Note:</b> | |
1475 | * This should not be used on pool implementations that already provide proper synchronization | |
1476 | * such as the pools provided in the Commons Pool library. Wrapping a pool that | |
1477 | * {@link #wait() waits} for poolable objects to be returned before allowing another one to be | |
1478 | * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. | |
1479 | * </p> | |
1480 | */ | |
1481 | private static class SynchronizedObjectPool implements ObjectPool { | |
1482 | ||
1483 | /** Object whose monitor is used to synchronize methods on the wrapped pool. */ | |
1484 | private final Object lock; | |
1485 | ||
1486 | /** the underlying object pool */ | |
1487 | private final ObjectPool pool; | |
1488 | ||
1489 | /** | |
1490 | * Create a new SynchronizedObjectPool wrapping the given pool. | |
1491 | * | |
1492 | * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. | |
1493 | * @throws IllegalArgumentException if the pool is null | |
1494 | */ | |
1495 | 0 | SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException { |
1496 | 0 | if (pool == null) { |
1497 | 0 | throw new IllegalArgumentException("pool must not be null."); |
1498 | } | |
1499 | 0 | this.pool = pool; |
1500 | 0 | lock = new Object(); |
1501 | 0 | } |
1502 | ||
1503 | /** | |
1504 | * {@inheritDoc} | |
1505 | */ | |
1506 | public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { | |
1507 | 0 | synchronized (lock) { |
1508 | 0 | return pool.borrowObject(); |
1509 | 0 | } |
1510 | } | |
1511 | ||
1512 | /** | |
1513 | * {@inheritDoc} | |
1514 | */ | |
1515 | public void returnObject(final Object obj) { | |
1516 | 0 | synchronized (lock) { |
1517 | try { | |
1518 | 0 | pool.returnObject(obj); |
1519 | 0 | } catch (Exception e) { |
1520 | // swallowed as of Pool 2 | |
1521 | 0 | } |
1522 | 0 | } |
1523 | 0 | } |
1524 | ||
1525 | /** | |
1526 | * {@inheritDoc} | |
1527 | */ | |
1528 | public void invalidateObject(final Object obj) { | |
1529 | 0 | synchronized (lock) { |
1530 | try { | |
1531 | 0 | pool.invalidateObject(obj); |
1532 | 0 | } catch (Exception e) { |
1533 | // swallowed as of Pool 2 | |
1534 | 0 | } |
1535 | 0 | } |
1536 | 0 | } |
1537 | ||
1538 | /** | |
1539 | * {@inheritDoc} | |
1540 | */ | |
1541 | public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { | |
1542 | 0 | synchronized (lock) { |
1543 | 0 | pool.addObject(); |
1544 | 0 | } |
1545 | 0 | } |
1546 | ||
1547 | /** | |
1548 | * {@inheritDoc} | |
1549 | */ | |
1550 | public int getNumIdle() throws UnsupportedOperationException { | |
1551 | 0 | synchronized (lock) { |
1552 | 0 | return pool.getNumIdle(); |
1553 | 0 | } |
1554 | } | |
1555 | ||
1556 | /** | |
1557 | * {@inheritDoc} | |
1558 | */ | |
1559 | public int getNumActive() throws UnsupportedOperationException { | |
1560 | 0 | synchronized (lock) { |
1561 | 0 | return pool.getNumActive(); |
1562 | 0 | } |
1563 | } | |
1564 | ||
1565 | /** | |
1566 | * {@inheritDoc} | |
1567 | */ | |
1568 | public void clear() throws Exception, UnsupportedOperationException { | |
1569 | 0 | synchronized (lock) { |
1570 | 0 | pool.clear(); |
1571 | 0 | } |
1572 | 0 | } |
1573 | ||
1574 | /** | |
1575 | * {@inheritDoc} | |
1576 | */ | |
1577 | public void close() { | |
1578 | try { | |
1579 | 0 | synchronized (lock) { |
1580 | 0 | pool.close(); |
1581 | 0 | } |
1582 | 0 | } catch (Exception e) { |
1583 | // swallowed as of Pool 2 | |
1584 | 0 | } |
1585 | 0 | } |
1586 | ||
1587 | /** | |
1588 | * Sets the factory used by the pool. | |
1589 | * | |
1590 | * @param factory new PoolableObjectFactory | |
1591 | * @deprecated to be removed in pool 2.0 | |
1592 | */ | |
1593 | public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
1594 | 0 | synchronized (lock) { |
1595 | 0 | pool.setFactory(factory); |
1596 | 0 | } |
1597 | 0 | } |
1598 | ||
1599 | /** | |
1600 | * {@inheritDoc} | |
1601 | */ | |
1602 | public String toString() { | |
1603 | 0 | final StringBuffer sb = new StringBuffer(); |
1604 | 0 | sb.append("SynchronizedObjectPool"); |
1605 | 0 | sb.append("{pool=").append(pool); |
1606 | 0 | sb.append('}'); |
1607 | 0 | return sb.toString(); |
1608 | } | |
1609 | } | |
1610 | ||
1611 | /** | |
1612 | * A synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. | |
1613 | * | |
1614 | * <p><b>Note:</b> | |
1615 | * This should not be used on pool implementations that already provide proper synchronization | |
1616 | * such as the pools provided in the Commons Pool library. Wrapping a pool that | |
1617 | * {@link #wait() waits} for poolable objects to be returned before allowing another one to be | |
1618 | * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. | |
1619 | * </p> | |
1620 | */ | |
1621 | private static class SynchronizedKeyedObjectPool implements KeyedObjectPool { | |
1622 | ||
1623 | /** Object whose monitor is used to synchronize methods on the wrapped pool. */ | |
1624 | private final Object lock; | |
1625 | ||
1626 | /** Underlying object pool */ | |
1627 | private final KeyedObjectPool keyedPool; | |
1628 | ||
1629 | /** | |
1630 | * Create a new SynchronizedKeyedObjectPool wrapping the given pool | |
1631 | * | |
1632 | * @param keyedPool KeyedObjectPool to wrap | |
1633 | * @throws IllegalArgumentException if keyedPool is null | |
1634 | */ | |
1635 | 0 | SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException { |
1636 | 0 | if (keyedPool == null) { |
1637 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
1638 | } | |
1639 | 0 | this.keyedPool = keyedPool; |
1640 | 0 | lock = new Object(); |
1641 | 0 | } |
1642 | ||
1643 | /** | |
1644 | * {@inheritDoc} | |
1645 | */ | |
1646 | public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { | |
1647 | 0 | synchronized (lock) { |
1648 | 0 | return keyedPool.borrowObject(key); |
1649 | 0 | } |
1650 | } | |
1651 | ||
1652 | /** | |
1653 | * {@inheritDoc} | |
1654 | */ | |
1655 | public void returnObject(final Object key, final Object obj) { | |
1656 | 0 | synchronized (lock) { |
1657 | try { | |
1658 | 0 | keyedPool.returnObject(key, obj); |
1659 | 0 | } catch (Exception e) { |
1660 | // swallowed | |
1661 | 0 | } |
1662 | 0 | } |
1663 | 0 | } |
1664 | ||
1665 | /** | |
1666 | * {@inheritDoc} | |
1667 | */ | |
1668 | public void invalidateObject(final Object key, final Object obj) { | |
1669 | 0 | synchronized (lock) { |
1670 | try { | |
1671 | 0 | keyedPool.invalidateObject(key, obj); |
1672 | 0 | } catch (Exception e) { |
1673 | // swallowed as of Pool 2 | |
1674 | 0 | } |
1675 | 0 | } |
1676 | 0 | } |
1677 | ||
1678 | /** | |
1679 | * {@inheritDoc} | |
1680 | */ | |
1681 | public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { | |
1682 | 0 | synchronized (lock) { |
1683 | 0 | keyedPool.addObject(key); |
1684 | 0 | } |
1685 | 0 | } |
1686 | ||
1687 | /** | |
1688 | * {@inheritDoc} | |
1689 | */ | |
1690 | public int getNumIdle(final Object key) throws UnsupportedOperationException { | |
1691 | 0 | synchronized (lock) { |
1692 | 0 | return keyedPool.getNumIdle(key); |
1693 | 0 | } |
1694 | } | |
1695 | ||
1696 | /** | |
1697 | * {@inheritDoc} | |
1698 | */ | |
1699 | public int getNumActive(final Object key) throws UnsupportedOperationException { | |
1700 | 0 | synchronized (lock) { |
1701 | 0 | return keyedPool.getNumActive(key); |
1702 | 0 | } |
1703 | } | |
1704 | ||
1705 | /** | |
1706 | * {@inheritDoc} | |
1707 | */ | |
1708 | public int getNumIdle() throws UnsupportedOperationException { | |
1709 | 0 | synchronized (lock) { |
1710 | 0 | return keyedPool.getNumIdle(); |
1711 | 0 | } |
1712 | } | |
1713 | ||
1714 | /** | |
1715 | * {@inheritDoc} | |
1716 | */ | |
1717 | public int getNumActive() throws UnsupportedOperationException { | |
1718 | 0 | synchronized (lock) { |
1719 | 0 | return keyedPool.getNumActive(); |
1720 | 0 | } |
1721 | } | |
1722 | ||
1723 | /** | |
1724 | * {@inheritDoc} | |
1725 | */ | |
1726 | public void clear() throws Exception, UnsupportedOperationException { | |
1727 | 0 | synchronized (lock) { |
1728 | 0 | keyedPool.clear(); |
1729 | 0 | } |
1730 | 0 | } |
1731 | ||
1732 | /** | |
1733 | * {@inheritDoc} | |
1734 | */ | |
1735 | public void clear(final Object key) throws Exception, UnsupportedOperationException { | |
1736 | 0 | synchronized (lock) { |
1737 | 0 | keyedPool.clear(key); |
1738 | 0 | } |
1739 | 0 | } |
1740 | ||
1741 | /** | |
1742 | * {@inheritDoc} | |
1743 | */ | |
1744 | public void close() { | |
1745 | try { | |
1746 | 0 | synchronized (lock) { |
1747 | 0 | keyedPool.close(); |
1748 | 0 | } |
1749 | 0 | } catch (Exception e) { |
1750 | // swallowed as of Pool 2 | |
1751 | 0 | } |
1752 | 0 | } |
1753 | ||
1754 | /** | |
1755 | * Sets the object factory used by the pool. | |
1756 | * | |
1757 | * @param factory KeyedPoolableObjectFactory used by the pool | |
1758 | * @deprecated to be removed in pool 2.0 | |
1759 | */ | |
1760 | public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
1761 | 0 | synchronized (lock) { |
1762 | 0 | keyedPool.setFactory(factory); |
1763 | 0 | } |
1764 | 0 | } |
1765 | ||
1766 | /** | |
1767 | * {@inheritDoc} | |
1768 | */ | |
1769 | public String toString() { | |
1770 | 0 | final StringBuffer sb = new StringBuffer(); |
1771 | 0 | sb.append("SynchronizedKeyedObjectPool"); |
1772 | 0 | sb.append("{keyedPool=").append(keyedPool); |
1773 | 0 | sb.append('}'); |
1774 | 0 | return sb.toString(); |
1775 | } | |
1776 | } | |
1777 | ||
1778 | /** | |
1779 | * A fully synchronized PoolableObjectFactory that wraps a PoolableObjectFactory and synchronizes | |
1780 | * access to the wrapped factory methods. | |
1781 | * | |
1782 | * <p><b>Note:</b> | |
1783 | * This should not be used on pool implementations that already provide proper synchronization | |
1784 | * such as the pools provided in the Commons Pool library. </p> | |
1785 | */ | |
1786 | private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory { | |
1787 | /** Synchronization lock */ | |
1788 | private final Object lock; | |
1789 | ||
1790 | /** Wrapped factory */ | |
1791 | private final PoolableObjectFactory factory; | |
1792 | ||
1793 | /** | |
1794 | * Create a SynchronizedPoolableObjectFactory wrapping the given factory. | |
1795 | * | |
1796 | * @param factory underlying factory to wrap | |
1797 | * @throws IllegalArgumentException if the factory is null | |
1798 | */ | |
1799 | 0 | SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException { |
1800 | 0 | if (factory == null) { |
1801 | 0 | throw new IllegalArgumentException("factory must not be null."); |
1802 | } | |
1803 | 0 | this.factory = factory; |
1804 | 0 | lock = new Object(); |
1805 | 0 | } |
1806 | ||
1807 | /** | |
1808 | * {@inheritDoc} | |
1809 | */ | |
1810 | public Object makeObject() throws Exception { | |
1811 | 0 | synchronized (lock) { |
1812 | 0 | return factory.makeObject(); |
1813 | 0 | } |
1814 | } | |
1815 | ||
1816 | /** | |
1817 | * {@inheritDoc} | |
1818 | */ | |
1819 | public void destroyObject(final Object obj) throws Exception { | |
1820 | 0 | synchronized (lock) { |
1821 | 0 | factory.destroyObject(obj); |
1822 | 0 | } |
1823 | 0 | } |
1824 | ||
1825 | /** | |
1826 | * {@inheritDoc} | |
1827 | */ | |
1828 | public boolean validateObject(final Object obj) { | |
1829 | 0 | synchronized (lock) { |
1830 | 0 | return factory.validateObject(obj); |
1831 | 0 | } |
1832 | } | |
1833 | ||
1834 | /** | |
1835 | * {@inheritDoc} | |
1836 | */ | |
1837 | public void activateObject(final Object obj) throws Exception { | |
1838 | 0 | synchronized (lock) { |
1839 | 0 | factory.activateObject(obj); |
1840 | 0 | } |
1841 | 0 | } |
1842 | ||
1843 | /** | |
1844 | * {@inheritDoc} | |
1845 | */ | |
1846 | public void passivateObject(final Object obj) throws Exception { | |
1847 | 0 | synchronized (lock) { |
1848 | 0 | factory.passivateObject(obj); |
1849 | 0 | } |
1850 | 0 | } |
1851 | ||
1852 | /** | |
1853 | * {@inheritDoc} | |
1854 | */ | |
1855 | public String toString() { | |
1856 | 0 | final StringBuffer sb = new StringBuffer(); |
1857 | 0 | sb.append("SynchronizedPoolableObjectFactory"); |
1858 | 0 | sb.append("{factory=").append(factory); |
1859 | 0 | sb.append('}'); |
1860 | 0 | return sb.toString(); |
1861 | } | |
1862 | } | |
1863 | ||
1864 | /** | |
1865 | * A fully synchronized KeyedPoolableObjectFactory that wraps a KeyedPoolableObjectFactory and synchronizes | |
1866 | * access to the wrapped factory methods. | |
1867 | * | |
1868 | * <p><b>Note:</b> | |
1869 | * This should not be used on pool implementations that already provide proper synchronization | |
1870 | * such as the pools provided in the Commons Pool library. </p> | |
1871 | */ | |
1872 | private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory { | |
1873 | /** Synchronization lock */ | |
1874 | private final Object lock; | |
1875 | ||
1876 | /** Wrapped factory */ | |
1877 | private final KeyedPoolableObjectFactory keyedFactory; | |
1878 | ||
1879 | /** | |
1880 | * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given factory. | |
1881 | * | |
1882 | * @param keyedFactory underlying factory to wrap | |
1883 | * @throws IllegalArgumentException if the factory is null | |
1884 | */ | |
1885 | 0 | SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { |
1886 | 0 | if (keyedFactory == null) { |
1887 | 0 | throw new IllegalArgumentException("keyedFactory must not be null."); |
1888 | } | |
1889 | 0 | this.keyedFactory = keyedFactory; |
1890 | 0 | lock = new Object(); |
1891 | 0 | } |
1892 | ||
1893 | /** | |
1894 | * {@inheritDoc} | |
1895 | */ | |
1896 | public Object makeObject(final Object key) throws Exception { | |
1897 | 0 | synchronized (lock) { |
1898 | 0 | return keyedFactory.makeObject(key); |
1899 | 0 | } |
1900 | } | |
1901 | ||
1902 | /** | |
1903 | * {@inheritDoc} | |
1904 | */ | |
1905 | public void destroyObject(final Object key, final Object obj) throws Exception { | |
1906 | 0 | synchronized (lock) { |
1907 | 0 | keyedFactory.destroyObject(key, obj); |
1908 | 0 | } |
1909 | 0 | } |
1910 | ||
1911 | /** | |
1912 | * {@inheritDoc} | |
1913 | */ | |
1914 | public boolean validateObject(final Object key, final Object obj) { | |
1915 | 0 | synchronized (lock) { |
1916 | 0 | return keyedFactory.validateObject(key, obj); |
1917 | 0 | } |
1918 | } | |
1919 | ||
1920 | /** | |
1921 | * {@inheritDoc} | |
1922 | */ | |
1923 | public void activateObject(final Object key, final Object obj) throws Exception { | |
1924 | 0 | synchronized (lock) { |
1925 | 0 | keyedFactory.activateObject(key, obj); |
1926 | 0 | } |
1927 | 0 | } |
1928 | ||
1929 | /** | |
1930 | * {@inheritDoc} | |
1931 | */ | |
1932 | public void passivateObject(final Object key, final Object obj) throws Exception { | |
1933 | 0 | synchronized (lock) { |
1934 | 0 | keyedFactory.passivateObject(key, obj); |
1935 | 0 | } |
1936 | 0 | } |
1937 | ||
1938 | /** | |
1939 | * {@inheritDoc} | |
1940 | */ | |
1941 | public String toString() { | |
1942 | 0 | final StringBuffer sb = new StringBuffer(); |
1943 | 0 | sb.append("SynchronizedKeyedPoolableObjectFactory"); |
1944 | 0 | sb.append("{keyedFactory=").append(keyedFactory); |
1945 | 0 | sb.append('}'); |
1946 | 0 | return sb.toString(); |
1947 | } | |
1948 | } | |
1949 | ||
1950 | /** | |
1951 | * Encapsulate the logic for when the next poolable object should be discarded. | |
1952 | * Each time update is called, the next time to shrink is recomputed, based on | |
1953 | * the float factor, number of idle instances in the pool and high water mark. | |
1954 | * Float factor is assumed to be between 0 and 1. Values closer to 1 cause | |
1955 | * less frequent erosion events. Erosion event timing also depends on numIdle. | |
1956 | * When this value is relatively high (close to previously established high water | |
1957 | * mark), erosion occurs more frequently. | |
1958 | */ | |
1959 | private static class ErodingFactor { | |
1960 | /** Determines frequency of "erosion" events */ | |
1961 | private final float factor; | |
1962 | ||
1963 | /** Time of next shrink event */ | |
1964 | private transient volatile long nextShrink; | |
1965 | ||
1966 | /** High water mark - largest numIdle encountered */ | |
1967 | private transient volatile int idleHighWaterMark; | |
1968 | ||
1969 | /** | |
1970 | * Create a new ErodingFactor with the given erosion factor. | |
1971 | * | |
1972 | * @param factor erosion factor | |
1973 | */ | |
1974 | 0 | public ErodingFactor(final float factor) { |
1975 | 0 | this.factor = factor; |
1976 | 0 | nextShrink = System.currentTimeMillis() + (long)(900000 * factor); // now + 15 min * factor |
1977 | 0 | idleHighWaterMark = 1; |
1978 | 0 | } |
1979 | ||
1980 | /** | |
1981 | * Updates internal state based on numIdle and the current time. | |
1982 | * | |
1983 | * @param numIdle number of idle elements in the pool | |
1984 | */ | |
1985 | public void update(final int numIdle) { | |
1986 | 0 | update(System.currentTimeMillis(), numIdle); |
1987 | 0 | } |
1988 | ||
1989 | /** | |
1990 | * Updates internal state using the supplied time and numIdle. | |
1991 | * | |
1992 | * @param now current time | |
1993 | * @param numIdle number of idle elements in the pool | |
1994 | */ | |
1995 | public void update(final long now, final int numIdle) { | |
1996 | 0 | final int idle = Math.max(0, numIdle); |
1997 | 0 | idleHighWaterMark = Math.max(idle, idleHighWaterMark); |
1998 | 0 | final float maxInterval = 15f; |
1999 | 0 | final float minutes = maxInterval + ((1f-maxInterval)/idleHighWaterMark) * idle; |
2000 | 0 | nextShrink = now + (long)(minutes * 60000f * factor); |
2001 | 0 | } |
2002 | ||
2003 | /** | |
2004 | * Returns the time of the next erosion event. | |
2005 | * | |
2006 | * @return next shrink time | |
2007 | */ | |
2008 | public long getNextShrink() { | |
2009 | 0 | return nextShrink; |
2010 | } | |
2011 | ||
2012 | /** | |
2013 | * {@inheritDoc} | |
2014 | */ | |
2015 | public String toString() { | |
2016 | 0 | return "ErodingFactor{" + |
2017 | "factor=" + factor + | |
2018 | ", idleHighWaterMark=" + idleHighWaterMark + | |
2019 | '}'; | |
2020 | } | |
2021 | } | |
2022 | ||
2023 | /** | |
2024 | * Decorates an object pool, adding "eroding" behavior. Based on the | |
2025 | * configured {@link #factor erosion factor}, objects returning to the pool | |
2026 | * may be invalidated instead of being added to idle capacity. | |
2027 | * | |
2028 | */ | |
2029 | private static class ErodingObjectPool implements ObjectPool { | |
2030 | /** Underlying object pool */ | |
2031 | private final ObjectPool pool; | |
2032 | ||
2033 | /** Erosion factor */ | |
2034 | private final ErodingFactor factor; | |
2035 | ||
2036 | /** | |
2037 | * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. | |
2038 | * | |
2039 | * @param pool underlying pool | |
2040 | * @param factor erosion factor - determines the frequency of erosion events | |
2041 | * @see #factor | |
2042 | */ | |
2043 | 0 | public ErodingObjectPool(final ObjectPool pool, final float factor) { |
2044 | 0 | this.pool = pool; |
2045 | 0 | this.factor = new ErodingFactor(factor); |
2046 | 0 | } |
2047 | ||
2048 | /** | |
2049 | * {@inheritDoc} | |
2050 | */ | |
2051 | public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { | |
2052 | 0 | return pool.borrowObject(); |
2053 | } | |
2054 | ||
2055 | /** | |
2056 | * Returns obj to the pool, unless erosion is triggered, in which | |
2057 | * case obj is invalidated. Erosion is triggered when there are idle instances in | |
2058 | * the pool and more than the {@link #factor erosion factor}-determined time has elapsed | |
2059 | * since the last returnObject activation. | |
2060 | * | |
2061 | * @param obj object to return or invalidate | |
2062 | * @see #factor | |
2063 | */ | |
2064 | public void returnObject(final Object obj) { | |
2065 | 0 | boolean discard = false; |
2066 | 0 | final long now = System.currentTimeMillis(); |
2067 | 0 | synchronized (pool) { |
2068 | 0 | if (factor.getNextShrink() < now) { // XXX: Pool 3: move test out of sync block |
2069 | 0 | final int numIdle = pool.getNumIdle(); |
2070 | 0 | if (numIdle > 0) { |
2071 | 0 | discard = true; |
2072 | } | |
2073 | ||
2074 | 0 | factor.update(now, numIdle); |
2075 | } | |
2076 | 0 | } |
2077 | try { | |
2078 | 0 | if (discard) { |
2079 | 0 | pool.invalidateObject(obj); |
2080 | } else { | |
2081 | 0 | pool.returnObject(obj); |
2082 | } | |
2083 | 0 | } catch (Exception e) { |
2084 | // swallowed | |
2085 | 0 | } |
2086 | 0 | } |
2087 | ||
2088 | /** | |
2089 | * {@inheritDoc} | |
2090 | */ | |
2091 | public void invalidateObject(final Object obj) { | |
2092 | try { | |
2093 | 0 | pool.invalidateObject(obj); |
2094 | 0 | } catch (Exception e) { |
2095 | // swallowed | |
2096 | 0 | } |
2097 | 0 | } |
2098 | ||
2099 | /** | |
2100 | * {@inheritDoc} | |
2101 | */ | |
2102 | public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { | |
2103 | 0 | pool.addObject(); |
2104 | 0 | } |
2105 | ||
2106 | /** | |
2107 | * {@inheritDoc} | |
2108 | */ | |
2109 | public int getNumIdle() throws UnsupportedOperationException { | |
2110 | 0 | return pool.getNumIdle(); |
2111 | } | |
2112 | ||
2113 | /** | |
2114 | * {@inheritDoc} | |
2115 | */ | |
2116 | public int getNumActive() throws UnsupportedOperationException { | |
2117 | 0 | return pool.getNumActive(); |
2118 | } | |
2119 | ||
2120 | /** | |
2121 | * {@inheritDoc} | |
2122 | */ | |
2123 | public void clear() throws Exception, UnsupportedOperationException { | |
2124 | 0 | pool.clear(); |
2125 | 0 | } |
2126 | ||
2127 | /** | |
2128 | * {@inheritDoc} | |
2129 | */ | |
2130 | public void close() { | |
2131 | try { | |
2132 | 0 | pool.close(); |
2133 | 0 | } catch (Exception e) { |
2134 | // swallowed | |
2135 | 0 | } |
2136 | 0 | } |
2137 | ||
2138 | /** | |
2139 | * {@inheritDoc} | |
2140 | * @deprecated to be removed in pool 2.0 | |
2141 | */ | |
2142 | public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
2143 | 0 | pool.setFactory(factory); |
2144 | 0 | } |
2145 | ||
2146 | /** | |
2147 | * {@inheritDoc} | |
2148 | */ | |
2149 | public String toString() { | |
2150 | 0 | return "ErodingObjectPool{" + |
2151 | "factor=" + factor + | |
2152 | ", pool=" + pool + | |
2153 | '}'; | |
2154 | } | |
2155 | } | |
2156 | ||
2157 | /** | |
2158 | * Decorates a keyed object pool, adding "eroding" behavior. Based on the | |
2159 | * configured {@link #factor erosion factor}, objects returning to the pool | |
2160 | * may be invalidated instead of being added to idle capacity. | |
2161 | * | |
2162 | */ | |
2163 | private static class ErodingKeyedObjectPool implements KeyedObjectPool { | |
2164 | /** Underlying pool */ | |
2165 | private final KeyedObjectPool keyedPool; | |
2166 | ||
2167 | /** Erosion factor */ | |
2168 | private final ErodingFactor erodingFactor; | |
2169 | ||
2170 | /** | |
2171 | * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. | |
2172 | * | |
2173 | * @param keyedPool underlying pool | |
2174 | * @param factor erosion factor - determines the frequency of erosion events | |
2175 | * @see #erodingFactor | |
2176 | */ | |
2177 | public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { | |
2178 | 0 | this(keyedPool, new ErodingFactor(factor)); |
2179 | 0 | } |
2180 | ||
2181 | /** | |
2182 | * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. | |
2183 | * | |
2184 | * @param keyedPool underlying pool - must not be null | |
2185 | * @param erodingFactor erosion factor - determines the frequency of erosion events | |
2186 | * @see #factor | |
2187 | */ | |
2188 | 0 | protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final ErodingFactor erodingFactor) { |
2189 | 0 | if (keyedPool == null) { |
2190 | 0 | throw new IllegalArgumentException("keyedPool must not be null."); |
2191 | } | |
2192 | 0 | this.keyedPool = keyedPool; |
2193 | 0 | this.erodingFactor = erodingFactor; |
2194 | 0 | } |
2195 | ||
2196 | /** | |
2197 | * {@inheritDoc} | |
2198 | */ | |
2199 | public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { | |
2200 | 0 | return keyedPool.borrowObject(key); |
2201 | } | |
2202 | ||
2203 | /** | |
2204 | * Returns obj to the pool, unless erosion is triggered, in which | |
2205 | * case obj is invalidated. Erosion is triggered when there are idle instances in | |
2206 | * the pool associated with the given key and more than the configured {@link #erodingFactor erosion factor} | |
2207 | * time has elapsed since the last returnObject activation. | |
2208 | * | |
2209 | * @param obj object to return or invalidate | |
2210 | * @param key key | |
2211 | * @see #erodingFactor | |
2212 | */ | |
2213 | public void returnObject(final Object key, final Object obj) throws Exception { | |
2214 | 0 | boolean discard = false; |
2215 | 0 | final long now = System.currentTimeMillis(); |
2216 | 0 | final ErodingFactor factor = getErodingFactor(key); |
2217 | 0 | synchronized (keyedPool) { |
2218 | 0 | if (factor.getNextShrink() < now) { |
2219 | 0 | final int numIdle = numIdle(key); |
2220 | 0 | if (numIdle > 0) { |
2221 | 0 | discard = true; |
2222 | } | |
2223 | ||
2224 | 0 | factor.update(now, numIdle); |
2225 | } | |
2226 | 0 | } |
2227 | try { | |
2228 | 0 | if (discard) { |
2229 | 0 | keyedPool.invalidateObject(key, obj); |
2230 | } else { | |
2231 | 0 | keyedPool.returnObject(key, obj); |
2232 | } | |
2233 | 0 | } catch (Exception e) { |
2234 | // swallowed | |
2235 | 0 | } |
2236 | 0 | } |
2237 | ||
2238 | protected int numIdle(final Object key) { | |
2239 | 0 | return getKeyedPool().getNumIdle(); |
2240 | } | |
2241 | ||
2242 | /** | |
2243 | * Returns the eroding factor for the given key | |
2244 | * @param key key | |
2245 | * @return eroding factor for the given keyed pool | |
2246 | */ | |
2247 | protected ErodingFactor getErodingFactor(final Object key) { | |
2248 | 0 | return erodingFactor; |
2249 | } | |
2250 | ||
2251 | /** | |
2252 | * {@inheritDoc} | |
2253 | */ | |
2254 | public void invalidateObject(final Object key, final Object obj) { | |
2255 | try { | |
2256 | 0 | keyedPool.invalidateObject(key, obj); |
2257 | 0 | } catch (Exception e) { |
2258 | // swallowed | |
2259 | 0 | } |
2260 | 0 | } |
2261 | ||
2262 | /** | |
2263 | * {@inheritDoc} | |
2264 | */ | |
2265 | public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { | |
2266 | 0 | keyedPool.addObject(key); |
2267 | 0 | } |
2268 | ||
2269 | /** | |
2270 | * {@inheritDoc} | |
2271 | */ | |
2272 | public int getNumIdle() throws UnsupportedOperationException { | |
2273 | 0 | return keyedPool.getNumIdle(); |
2274 | } | |
2275 | ||
2276 | /** | |
2277 | * {@inheritDoc} | |
2278 | */ | |
2279 | public int getNumIdle(final Object key) throws UnsupportedOperationException { | |
2280 | 0 | return keyedPool.getNumIdle(key); |
2281 | } | |
2282 | ||
2283 | /** | |
2284 | * {@inheritDoc} | |
2285 | */ | |
2286 | public int getNumActive() throws UnsupportedOperationException { | |
2287 | 0 | return keyedPool.getNumActive(); |
2288 | } | |
2289 | ||
2290 | /** | |
2291 | * {@inheritDoc} | |
2292 | */ | |
2293 | public int getNumActive(final Object key) throws UnsupportedOperationException { | |
2294 | 0 | return keyedPool.getNumActive(key); |
2295 | } | |
2296 | ||
2297 | /** | |
2298 | * {@inheritDoc} | |
2299 | */ | |
2300 | public void clear() throws Exception, UnsupportedOperationException { | |
2301 | 0 | keyedPool.clear(); |
2302 | 0 | } |
2303 | ||
2304 | /** | |
2305 | * {@inheritDoc} | |
2306 | */ | |
2307 | public void clear(final Object key) throws Exception, UnsupportedOperationException { | |
2308 | 0 | keyedPool.clear(key); |
2309 | 0 | } |
2310 | ||
2311 | /** | |
2312 | * {@inheritDoc} | |
2313 | */ | |
2314 | public void close() { | |
2315 | try { | |
2316 | 0 | keyedPool.close(); |
2317 | 0 | } catch (Exception e) { |
2318 | // swallowed | |
2319 | 0 | } |
2320 | 0 | } |
2321 | ||
2322 | /** | |
2323 | * {@inheritDoc} | |
2324 | * @deprecated to be removed in pool 2.0 | |
2325 | */ | |
2326 | public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { | |
2327 | 0 | keyedPool.setFactory(factory); |
2328 | 0 | } |
2329 | ||
2330 | /** | |
2331 | * Returns the underlying pool | |
2332 | * | |
2333 | * @return the keyed pool that this ErodingKeyedObjectPool wraps | |
2334 | */ | |
2335 | protected KeyedObjectPool getKeyedPool() { | |
2336 | 0 | return keyedPool; |
2337 | } | |
2338 | ||
2339 | /** | |
2340 | * {@inheritDoc} | |
2341 | */ | |
2342 | public String toString() { | |
2343 | 0 | return "ErodingKeyedObjectPool{" + |
2344 | "erodingFactor=" + erodingFactor + | |
2345 | ", keyedPool=" + keyedPool + | |
2346 | '}'; | |
2347 | } | |
2348 | } | |
2349 | ||
2350 | /** | |
2351 | * Extends ErodingKeyedObjectPool to allow erosion to take place on a per-key | |
2352 | * basis. Timing of erosion events is tracked separately for separate keyed pools. | |
2353 | */ | |
2354 | private static class ErodingPerKeyKeyedObjectPool extends ErodingKeyedObjectPool { | |
2355 | /** Erosion factor - same for all pools */ | |
2356 | private final float factor; | |
2357 | ||
2358 | /** Map of ErodingFactor instances keyed on pool keys */ | |
2359 | 0 | private final Map factors = Collections.synchronizedMap(new HashMap()); |
2360 | ||
2361 | /** | |
2362 | * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed pool with | |
2363 | * the specified erosion factor. | |
2364 | * @param keyedPool underlying keyed pool | |
2365 | * @param factor erosion factor | |
2366 | */ | |
2367 | public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { | |
2368 | 0 | super(keyedPool, null); |
2369 | 0 | this.factor = factor; |
2370 | 0 | } |
2371 | ||
2372 | /** | |
2373 | * {@inheritDoc} | |
2374 | */ | |
2375 | protected int numIdle(final Object key) { | |
2376 | 0 | return getKeyedPool().getNumIdle(key); |
2377 | } | |
2378 | ||
2379 | /** | |
2380 | * {@inheritDoc} | |
2381 | */ | |
2382 | protected ErodingFactor getErodingFactor(final Object key) { | |
2383 | 0 | ErodingFactor factor = (ErodingFactor)factors.get(key); |
2384 | // this may result in two ErodingFactors being created for a key | |
2385 | // since they are small and cheap this is okay. | |
2386 | 0 | if (factor == null) { |
2387 | 0 | factor = new ErodingFactor(this.factor); |
2388 | 0 | factors.put(key, factor); |
2389 | } | |
2390 | 0 | return factor; |
2391 | } | |
2392 | ||
2393 | /** | |
2394 | * {@inheritDoc} | |
2395 | */ | |
2396 | public String toString() { | |
2397 | 0 | return "ErodingPerKeyKeyedObjectPool{" + |
2398 | "factor=" + factor + | |
2399 | ", keyedPool=" + getKeyedPool() + | |
2400 | '}'; | |
2401 | } | |
2402 | } | |
2403 | } |