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 module hunt.pool.impl.BaseGenericObjectPool;
18 
19 import hunt.pool.impl.BaseObjectPoolConfig;
20 import hunt.pool.impl.EvictionPolicy;
21 import hunt.pool.impl.EvictionTimer;
22 
23 import hunt.pool.impl.GenericKeyedObjectPoolConfig;
24 
25 // import java.io.PrintWriter;
26 // import java.io.StringWriter;
27 // import java.io.Writer;
28 // import java.lang.management.ManagementFactory;
29 // import java.lang.ref.WeakReference;
30 // import java.lang.reflect.InvocationTargetException;
31 // import java.util.Arrays;
32 // import java.util.Deque;
33 // import java.util.Iterator;
34 // import java.util.TimerTask;
35 import hunt.concurrency.Delayed;
36 import hunt.concurrency.Future;
37 import hunt.concurrency.atomic.AtomicHelper;
38 // import java.util.concurrent.TimeUnit;
39 // import java.util.concurrent.atomic.AtomicLong;
40 
41 // import javax.management.InstanceAlreadyExistsException;
42 // import javax.management.InstanceNotFoundException;
43 // import javax.management.MBeanRegistrationException;
44 // import javax.management.MBeanServer;
45 // import javax.management.MalformedObjectNameException;
46 // import javax.management.NotCompliantMBeanException;
47 // import javax.management.ObjectName;
48 
49 import hunt.pool.BaseObject;
50 import hunt.pool.PooledObject;
51 import hunt.pool.PooledObjectState;
52 import hunt.pool.SwallowedExceptionListener;
53 
54 import hunt.collection;
55 import hunt.Exceptions;
56 import hunt.logging.ConsoleLogger;
57 import hunt.util.StringBuilder;
58 import hunt.util.Common;
59 import hunt.util.Runnable;
60 
61 import core.time;
62 import std.conv;
63 import std.range;
64 
65 /**
66  * Base class that provides common functionality for {@link GenericObjectPool}
67  * and {@link GenericKeyedObjectPool}. The primary reason this class exists is
68  * reduce code duplication between the two pool implementations.
69  *
70  * @param <T> Type of element pooled in this pool.
71  *
72  * This class is intended to be thread-safe.
73  *
74  */
75 abstract class BaseGenericObjectPool : BaseObject {
76 
77     // Constants
78     /**
79      * The size of the caches used to store historical data for some attributes
80      * so that rolling means may be calculated.
81      */
82     enum int MEAN_TIMING_STATS_CACHE_SIZE = 100;
83 
84     private enum string EVICTION_POLICY_TYPE_NAME = EvictionPolicy.stringof;
85 
86     // Configuration attributes
87     private shared int maxTotal =
88             GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
89     private shared bool blockWhenExhausted =
90             BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
91     private shared long maxWaitMillis =
92             BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
93     private shared bool lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
94     private bool fairness;
95     private shared bool testOnCreate =
96             BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
97     private shared bool testOnBorrow =
98             BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
99     private shared bool testOnReturn =
100             BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
101     private shared bool testWhileIdle =
102             BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
103     private shared long timeBetweenEvictionRunsMillis =
104             BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
105     private shared int numTestsPerEvictionRun =
106             BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
107     private shared long minEvictableIdleTimeMillis =
108             BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
109     private shared long softMinEvictableIdleTimeMillis =
110             BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
111     private EvictionPolicy evictionPolicy;
112     private shared long evictorShutdownTimeoutMillis =
113             BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
114 
115 
116     // Internal (primarily state) attributes
117     Object closeLock;
118     shared bool closed = false;
119     Object evictionLock;
120     private Evictor evictor = null; // @GuardedBy("evictionLock")
121     EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
122     /*
123      * Class loader for evictor thread to use since, in a JavaEE or similar
124      * environment, the context class loader for the evictor thread may not have
125      * visibility of the correct factory. See POOL-161. Uses a weak reference to
126      * avoid potential memory leaks if the Pool is discarded rather than closed.
127      */
128     // private WeakReference!(ClassLoader) factoryClassLoader;
129 
130 
131     // Monitoring (primarily JMX) attributes
132     // private ObjectName objectName;
133     private string creationStackTrace;
134     private shared long borrowedCount = 0; // new AtomicLong(0);
135     private shared long returnedCount = 0; // new AtomicLong(0);
136     shared long createdCount = 0; // new AtomicLong(0);
137     shared long destroyedCount = 0; // new AtomicLong(0);
138     shared long destroyedByEvictorCount = 0; // new AtomicLong(0);
139     shared long destroyedByBorrowValidationCount = 0; // new AtomicLong(0);
140     private StatsStore activeTimes;
141     private StatsStore idleTimes;
142     private StatsStore waitTimes;
143     private shared long maxBorrowWaitTimeMillis = 0; // new AtomicLong(0L);
144     private SwallowedExceptionListener swallowedExceptionListener = null;
145 
146 
147     /**
148      * Handles JMX registration (if required) and the initialization required for
149      * monitoring.
150      *
151      * @param config        Pool configuration
152      * @param jmxNameBase   The default base JMX name for the new pool unless
153      *                      overridden by the config
154      * @param jmxNamePrefix Prefix to be used for JMX name for the new pool
155      */
156     this(BaseObjectPoolConfig config,
157             string jmxNameBase, string jmxNamePrefix) {
158         
159         evictionLock = new Object();
160         closeLock = new Object();
161         activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
162         idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
163         waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
164 
165 
166         // if (config.getJmxEnabled()) {
167         //     this.objectName = jmxRegister(config, jmxNameBase, jmxNamePrefix);
168         // } else {
169         //     this.objectName = null;
170         // }
171 
172         // Populate the creation stack trace
173         this.creationStackTrace = getStackTrace(new Exception("default"));
174 
175         // save the current TCCL (if any) to be used later by the evictor Thread
176         // ClassLoader cl = Thread.getThis().getContextClassLoader();
177         // if (cl is null) {
178         //     factoryClassLoader = null;
179         // } else {
180         //     factoryClassLoader = new WeakReference<>(cl);
181         // }
182         // implementationMissing(false);
183         // FIXME: Needing refactor or cleanup -@zxp at 7/11/2019, 9:53:27 AM
184         // 
185 
186         fairness = config.getFairness();
187     }
188 
189 
190     /**
191      * Returns the maximum number of objects that can be allocated by the pool
192      * (checked out to clients, or idle awaiting checkout) at a given time. When
193      * negative, there is no limit to the number of objects that can be
194      * managed by the pool at one time.
195      *
196      * @return the cap on the total number of object instances managed by the
197      *         pool.
198      *
199      * @see #setMaxTotal
200      */
201     int getMaxTotal() {
202         return maxTotal;
203     }
204 
205     /**
206      * Sets the cap on the number of objects that can be allocated by the pool
207      * (checked out to clients, or idle awaiting checkout) at a given time. Use
208      * a negative value for no limit.
209      *
210      * @param maxTotal  The cap on the total number of object instances managed
211      *                  by the pool. Negative values mean that there is no limit
212      *                  to the number of objects allocated by the pool.
213      *
214      * @see #getMaxTotal
215      */
216     void setMaxTotal(int maxTotal) {
217         this.maxTotal = maxTotal;
218     }
219 
220     /**
221      * Returns whether to block when the <code>borrowObject()</code> method is
222      * invoked when the pool is exhausted (the maximum number of "active"
223      * objects has been reached).
224      *
225      * @return <code>true</code> if <code>borrowObject()</code> should block
226      *         when the pool is exhausted
227      *
228      * @see #setBlockWhenExhausted
229      */
230     bool getBlockWhenExhausted() {
231         return blockWhenExhausted;
232     }
233 
234     /**
235      * Sets whether to block when the <code>borrowObject()</code> method is
236      * invoked when the pool is exhausted (the maximum number of "active"
237      * objects has been reached).
238      *
239      * @param blockWhenExhausted    <code>true</code> if
240      *                              <code>borrowObject()</code> should block
241      *                              when the pool is exhausted
242      *
243      * @see #getBlockWhenExhausted
244      */
245     void setBlockWhenExhausted(bool blockWhenExhausted) {
246         this.blockWhenExhausted = blockWhenExhausted;
247     }
248 
249     protected void setConfig(BaseObjectPoolConfig conf) {
250         setLifo(conf.getLifo());
251         setMaxWaitMillis(conf.getMaxWaitMillis());
252         setBlockWhenExhausted(conf.getBlockWhenExhausted());
253         setTestOnCreate(conf.getTestOnCreate());
254         setTestOnBorrow(conf.getTestOnBorrow());
255         setTestOnReturn(conf.getTestOnReturn());
256         setTestWhileIdle(conf.getTestWhileIdle());
257         setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun());
258         setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis());
259         setTimeBetweenEvictionRunsMillis(conf.getTimeBetweenEvictionRunsMillis());
260         setSoftMinEvictableIdleTimeMillis(conf.getSoftMinEvictableIdleTimeMillis());
261         // TODO: Tasks pending completion -@zhangxueping at 2020-04-15T10:52:55+08:00
262         // 
263         // EvictionPolicy policy = conf.getEvictionPolicy();
264         // if(policy is null) {
265         //     warning("policy is null");
266         // } else {
267         //     setEvictionPolicy(policy);
268         // }
269         setEvictorShutdownTimeoutMillis(conf.getEvictorShutdownTimeoutMillis());
270     }
271 
272     /**
273      * Returns the maximum amount of time (in milliseconds) the
274      * <code>borrowObject()</code> method should block before throwing an
275      * exception when the pool is exhausted and
276      * {@link #getBlockWhenExhausted} is true. When less than 0, the
277      * <code>borrowObject()</code> method may block indefinitely.
278      *
279      * @return the maximum number of milliseconds <code>borrowObject()</code>
280      *         will block.
281      *
282      * @see #setMaxWaitMillis
283      * @see #setBlockWhenExhausted
284      */
285     long getMaxWaitMillis() {
286         return maxWaitMillis;
287     }
288 
289     /**
290      * Sets the maximum amount of time (in milliseconds) the
291      * <code>borrowObject()</code> method should block before throwing an
292      * exception when the pool is exhausted and
293      * {@link #getBlockWhenExhausted} is true. When less than 0, the
294      * <code>borrowObject()</code> method may block indefinitely.
295      *
296      * @param maxWaitMillis the maximum number of milliseconds
297      *                      <code>borrowObject()</code> will block or negative
298      *                      for indefinitely.
299      *
300      * @see #getMaxWaitMillis
301      * @see #setBlockWhenExhausted
302      */
303     void setMaxWaitMillis(long maxWaitMillis) {
304         this.maxWaitMillis = maxWaitMillis;
305     }
306 
307     /**
308      * Returns whether the pool has LIFO (last in, first out) behaviour with
309      * respect to idle objects - always returning the most recently used object
310      * from the pool, or as a FIFO (first in, first out) queue, where the pool
311      * always returns the oldest object in the idle object pool.
312      *
313      * @return <code>true</code> if the pool is configured with LIFO behaviour
314      *         or <code>false</code> if the pool is configured with FIFO
315      *         behaviour
316      *
317      * @see #setLifo
318      */
319     bool getLifo() {
320         return lifo;
321     }
322 
323     /**
324      * Returns whether or not the pool serves threads waiting to borrow objects fairly.
325      * True means that waiting threads are served as if waiting in a FIFO queue.
326      *
327      * @return <code>true</code> if waiting threads are to be served
328      *             by the pool in arrival order
329      */
330     bool getFairness() {
331         return fairness;
332     }
333 
334     /**
335      * Sets whether the pool has LIFO (last in, first out) behaviour with
336      * respect to idle objects - always returning the most recently used object
337      * from the pool, or as a FIFO (first in, first out) queue, where the pool
338      * always returns the oldest object in the idle object pool.
339      *
340      * @param lifo  <code>true</code> if the pool is to be configured with LIFO
341      *              behaviour or <code>false</code> if the pool is to be
342      *              configured with FIFO behaviour
343      *
344      * @see #getLifo()
345      */
346     void setLifo(bool lifo) {
347         this.lifo = lifo;
348     }
349 
350     /**
351      * Returns whether objects created for the pool will be validated before
352      * being returned from the <code>borrowObject()</code> method. Validation is
353      * performed by the <code>validateObject()</code> method of the factory
354      * associated with the pool. If the object fails to validate, then
355      * <code>borrowObject()</code> will fail.
356      *
357      * @return <code>true</code> if newly created objects are validated before
358      *         being returned from the <code>borrowObject()</code> method
359      *
360      * @see #setTestOnCreate
361      *
362      */
363     bool getTestOnCreate() {
364         return testOnCreate;
365     }
366 
367     /**
368      * Sets whether objects created for the pool will be validated before
369      * being returned from the <code>borrowObject()</code> method. Validation is
370      * performed by the <code>validateObject()</code> method of the factory
371      * associated with the pool. If the object fails to validate, then
372      * <code>borrowObject()</code> will fail.
373      *
374      * @param testOnCreate  <code>true</code> if newly created objects should be
375      *                      validated before being returned from the
376      *                      <code>borrowObject()</code> method
377      *
378      * @see #getTestOnCreate
379      *
380      */
381     void setTestOnCreate(bool testOnCreate) {
382         this.testOnCreate = testOnCreate;
383     }
384 
385     /**
386      * Returns whether objects borrowed from the pool will be validated before
387      * being returned from the <code>borrowObject()</code> method. Validation is
388      * performed by the <code>validateObject()</code> method of the factory
389      * associated with the pool. If the object fails to validate, it will be
390      * removed from the pool and destroyed, and a new attempt will be made to
391      * borrow an object from the pool.
392      *
393      * @return <code>true</code> if objects are validated before being returned
394      *         from the <code>borrowObject()</code> method
395      *
396      * @see #setTestOnBorrow
397      */
398     bool getTestOnBorrow() {
399         return testOnBorrow;
400     }
401 
402     /**
403      * Sets whether objects borrowed from the pool will be validated before
404      * being returned from the <code>borrowObject()</code> method. Validation is
405      * performed by the <code>validateObject()</code> method of the factory
406      * associated with the pool. If the object fails to validate, it will be
407      * removed from the pool and destroyed, and a new attempt will be made to
408      * borrow an object from the pool.
409      *
410      * @param testOnBorrow  <code>true</code> if objects should be validated
411      *                      before being returned from the
412      *                      <code>borrowObject()</code> method
413      *
414      * @see #getTestOnBorrow
415      */
416     void setTestOnBorrow(bool testOnBorrow) {
417         this.testOnBorrow = testOnBorrow;
418     }
419 
420     /**
421      * Returns whether objects borrowed from the pool will be validated when
422      * they are returned to the pool via the <code>returnObject()</code> method.
423      * Validation is performed by the <code>validateObject()</code> method of
424      * the factory associated with the pool. Returning objects that fail validation
425      * are destroyed rather then being returned the pool.
426      *
427      * @return <code>true</code> if objects are validated on return to
428      *         the pool via the <code>returnObject()</code> method
429      *
430      * @see #setTestOnReturn
431      */
432     bool getTestOnReturn() {
433         return testOnReturn;
434     }
435 
436     /**
437      * Sets whether objects borrowed from the pool will be validated when
438      * they are returned to the pool via the <code>returnObject()</code> method.
439      * Validation is performed by the <code>validateObject()</code> method of
440      * the factory associated with the pool. Returning objects that fail validation
441      * are destroyed rather then being returned the pool.
442      *
443      * @param testOnReturn <code>true</code> if objects are validated on
444      *                     return to the pool via the
445      *                     <code>returnObject()</code> method
446      *
447      * @see #getTestOnReturn
448      */
449     void setTestOnReturn(bool testOnReturn) {
450         this.testOnReturn = testOnReturn;
451     }
452 
453     /**
454      * Returns whether objects sitting idle in the pool will be validated by the
455      * idle object evictor (if any - see
456      * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
457      * by the <code>validateObject()</code> method of the factory associated
458      * with the pool. If the object fails to validate, it will be removed from
459      * the pool and destroyed.
460      *
461      * @return <code>true</code> if objects will be validated by the evictor
462      *
463      * @see #setTestWhileIdle
464      * @see #setTimeBetweenEvictionRunsMillis
465      */
466     bool getTestWhileIdle() {
467         return testWhileIdle;
468     }
469 
470     /**
471      * Returns whether objects sitting idle in the pool will be validated by the
472      * idle object evictor (if any - see
473      * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
474      * by the <code>validateObject()</code> method of the factory associated
475      * with the pool. If the object fails to validate, it will be removed from
476      * the pool and destroyed.  Note that setting this property has no effect
477      * unless the idle object evictor is enabled by setting
478      * <code>timeBetweenEvictionRunsMillis</code> to a positive value.
479      *
480      * @param testWhileIdle
481      *            <code>true</code> so objects will be validated by the evictor
482      *
483      * @see #getTestWhileIdle
484      * @see #setTimeBetweenEvictionRunsMillis
485      */
486     void setTestWhileIdle(bool testWhileIdle) {
487         this.testWhileIdle = testWhileIdle;
488     }
489 
490     /**
491      * Returns the number of milliseconds to sleep between runs of the idle
492      * object evictor thread. When non-positive, no idle object evictor thread
493      * will be run.
494      *
495      * @return number of milliseconds to sleep between evictor runs
496      *
497      * @see #setTimeBetweenEvictionRunsMillis
498      */
499     long getTimeBetweenEvictionRunsMillis() {
500         return timeBetweenEvictionRunsMillis;
501     }
502 
503     /**
504      * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
505      * <ul>
506      * <li>When positive, the idle object evictor thread starts.</li>
507      * <li>When non-positive, no idle object evictor thread runs.</li>
508      * </ul>
509      *
510      * @param timeBetweenEvictionRunsMillis
511      *            number of milliseconds to sleep between evictor runs
512      *
513      * @see #getTimeBetweenEvictionRunsMillis
514      */
515     void setTimeBetweenEvictionRunsMillis(
516             long timeBetweenEvictionRunsMillis) {
517         this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
518         startEvictor(timeBetweenEvictionRunsMillis);
519     }
520 
521     /**
522      * Returns the maximum number of objects to examine during each run (if any)
523      * of the idle object evictor thread. When positive, the number of tests
524      * performed for a run will be the minimum of the configured value and the
525      * number of idle instances in the pool. When negative, the number of tests
526      * performed will be <code>ceil({@link #getNumIdle}/
527      * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
528      * value is <code>-n</code> roughly one nth of the idle objects will be
529      * tested per run.
530      *
531      * @return max number of objects to examine during each evictor run
532      *
533      * @see #setNumTestsPerEvictionRun
534      * @see #setTimeBetweenEvictionRunsMillis
535      */
536     int getNumTestsPerEvictionRun() {
537         return numTestsPerEvictionRun;
538     }
539 
540     /**
541      * Sets the maximum number of objects to examine during each run (if any)
542      * of the idle object evictor thread. When positive, the number of tests
543      * performed for a run will be the minimum of the configured value and the
544      * number of idle instances in the pool. When negative, the number of tests
545      * performed will be <code>ceil({@link #getNumIdle}/
546      * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
547      * value is <code>-n</code> roughly one nth of the idle objects will be
548      * tested per run.
549      *
550      * @param numTestsPerEvictionRun
551      *            max number of objects to examine during each evictor run
552      *
553      * @see #getNumTestsPerEvictionRun
554      * @see #setTimeBetweenEvictionRunsMillis
555      */
556     void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
557         this.numTestsPerEvictionRun = numTestsPerEvictionRun;
558     }
559 
560     /**
561      * Returns the minimum amount of time an object may sit idle in the pool
562      * before it is eligible for eviction by the idle object evictor (if any -
563      * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
564      * no objects will be evicted from the pool due to idle time alone.
565      *
566      * @return minimum amount of time an object may sit idle in the pool before
567      *         it is eligible for eviction
568      *
569      * @see #setMinEvictableIdleTimeMillis
570      * @see #setTimeBetweenEvictionRunsMillis
571      */
572     long getMinEvictableIdleTimeMillis() {
573         return minEvictableIdleTimeMillis;
574     }
575 
576     /**
577      * Sets the minimum amount of time an object may sit idle in the pool
578      * before it is eligible for eviction by the idle object evictor (if any -
579      * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
580      * no objects will be evicted from the pool due to idle time alone.
581      *
582      * @param minEvictableIdleTimeMillis
583      *            minimum amount of time an object may sit idle in the pool
584      *            before it is eligible for eviction
585      *
586      * @see #getMinEvictableIdleTimeMillis
587      * @see #setTimeBetweenEvictionRunsMillis
588      */
589     void setMinEvictableIdleTimeMillis(
590             long minEvictableIdleTimeMillis) {
591         this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
592     }
593 
594     /**
595      * Returns the minimum amount of time an object may sit idle in the pool
596      * before it is eligible for eviction by the idle object evictor (if any -
597      * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
598      * with the extra condition that at least <code>minIdle</code> object
599      * instances remain in the pool. This setting is overridden by
600      * {@link #getMinEvictableIdleTimeMillis} (that is, if
601      * {@link #getMinEvictableIdleTimeMillis} is positive, then
602      * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
603      *
604      * @return minimum amount of time an object may sit idle in the pool before
605      *         it is eligible for eviction if minIdle instances are available
606      *
607      * @see #setSoftMinEvictableIdleTimeMillis
608      */
609     long getSoftMinEvictableIdleTimeMillis() {
610         return softMinEvictableIdleTimeMillis;
611     }
612 
613     /**
614      * Sets the minimum amount of time an object may sit idle in the pool
615      * before it is eligible for eviction by the idle object evictor (if any -
616      * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
617      * with the extra condition that at least <code>minIdle</code> object
618      * instances remain in the pool. This setting is overridden by
619      * {@link #getMinEvictableIdleTimeMillis} (that is, if
620      * {@link #getMinEvictableIdleTimeMillis} is positive, then
621      * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
622      *
623      * @param softMinEvictableIdleTimeMillis
624      *            minimum amount of time an object may sit idle in the pool
625      *            before it is eligible for eviction if minIdle instances are
626      *            available
627      *
628      * @see #getSoftMinEvictableIdleTimeMillis
629      */
630     void setSoftMinEvictableIdleTimeMillis(
631             long softMinEvictableIdleTimeMillis) {
632         this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
633     }
634 
635     /**
636      * Returns the name of the {@link EvictionPolicy} implementation that is
637      * used by this pool.
638      *
639      * @return  The fully qualified class name of the {@link EvictionPolicy}
640      *
641      * @see #setEvictionPolicyClassName(string)
642      */
643     string getEvictionPolicyClassName() {
644         return typeid(evictionPolicy).name;
645     }
646 
647     /**
648      * Sets the eviction policy for this pool.
649      *
650      * @param evictionPolicy
651      *            the eviction policy for this pool.
652      */
653     void setEvictionPolicy(EvictionPolicy evictionPolicy) {
654         this.evictionPolicy = evictionPolicy;
655     }
656 
657     /**
658      * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
659      * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
660      * interface.
661      *
662      * @param evictionPolicyClassName
663      *            the fully qualified class name of the new eviction policy
664      * @param classLoader
665      *            the class loader to load the given {@code evictionPolicyClassName}.
666      *
667      * @see #getEvictionPolicyClassName() If loading the class using the given class loader fails, use the class loader for the
668      *        {@link EvictionPolicy} interface.
669      */
670     // void setEvictionPolicyClassName(string evictionPolicyClassName, ClassLoader classLoader) {
671     //     // Getting epClass here and now best matches the caller's environment
672     //     Class<?> epClass = EvictionPolicy.class;
673     //     ClassLoader epClassLoader = epClass.getClassLoader();
674     //     try {
675     //         try {
676     //             setEvictionPolicy(evictionPolicyClassName, classLoader);
677     //         } catch (ClassCastException | ClassNotFoundException e) {
678     //             setEvictionPolicy(evictionPolicyClassName, epClassLoader);
679     //         }
680     //     } catch (ClassCastException e) {
681     //         throw new IllegalArgumentException("Class " ~ evictionPolicyClassName ~ " from class loaders ["
682     //                 + classLoader ~ ", " ~ epClassLoader ~ "] do not implement " ~ EVICTION_POLICY_TYPE_NAME);
683     //     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
684     //             | InvocationTargetException | NoSuchMethodException e) {
685     //         string exMessage = "Unable to create " ~ EVICTION_POLICY_TYPE_NAME ~ " instance of type "
686     //                 + evictionPolicyClassName;
687     //         throw new IllegalArgumentException(exMessage, e);
688     //     }
689     // }
690 
691     // private void setEvictionPolicy(string className, ClassLoader classLoader) {
692     //     Class<?> clazz = Class.forName(className, true, classLoader);
693     //     Object policy = clazz.getConstructor().newInstance();
694     //     this.evictionPolicy = (EvictionPolicy!(T)) policy;
695     // }
696 
697     /**
698      * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
699      * load the class using the thread context class loader. If that fails, the use the class loader for the
700      * {@link EvictionPolicy} interface.
701      *
702      * @param evictionPolicyClassName
703      *            the fully qualified class name of the new eviction policy
704      *ctionPolicyClassName()
705      * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
706      *        {@link EvictionPolicy} interface.
707      */
708     // void setEvictionPolicyClassName(string evictionPolicyClassName) {
709     //     // setEvictionPolicyClassName(evictionPolicyClassName, Thread.getThis().getContextClassLoader());
710     //     implementationMissing(false);
711     // }
712 
713     /**
714      * Gets the timeout that will be used when waiting for the Evictor to
715      * shutdown if this pool is closed and it is the only pool still using the
716      * the value for the Evictor.
717      *
718      * @return  The timeout in milliseconds that will be used while waiting for
719      *          the Evictor to shut down.
720      */
721     long getEvictorShutdownTimeoutMillis() {
722         return evictorShutdownTimeoutMillis;
723     }
724 
725     /**
726      * Sets the timeout that will be used when waiting for the Evictor to
727      * shutdown if this pool is closed and it is the only pool still using the
728      * the value for the Evictor.
729      *
730      * @param evictorShutdownTimeoutMillis  the timeout in milliseconds that
731      *                                      will be used while waiting for the
732      *                                      Evictor to shut down.
733      */
734     void setEvictorShutdownTimeoutMillis(
735             long evictorShutdownTimeoutMillis) {
736         this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
737     }
738 
739     /**
740      * Closes the pool, destroys the remaining idle objects and, if registered
741      * in JMX, deregisters it.
742      */
743     abstract void close();
744 
745     /**
746      * Has this pool instance been closed.
747      * @return <code>true</code> when this pool has been closed.
748      */
749     bool isClosed() {
750         return closed;
751     }
752 
753     /**
754      * <p>Perform <code>numTests</code> idle object eviction tests, evicting
755      * examined objects that meet the criteria for eviction. If
756      * <code>testWhileIdle</code> is true, examined objects are validated
757      * when visited (and removed if invalid); otherwise only objects that
758      * have been idle for more than <code>minEvicableIdleTimeMillis</code>
759      * are removed.</p>
760      *
761      * @throws Exception when there is a problem evicting idle objects.
762      */
763     abstract void evict();
764 
765     /**
766      * Returns the {@link EvictionPolicy} defined for this pool.
767      *
768      * @since 2.6.0 Changed access from protected to public.
769      */
770     EvictionPolicy getEvictionPolicy() {
771         return evictionPolicy;
772     }
773 
774     /**
775      * Verifies that the pool is open.
776      * @throws IllegalStateException if the pool is closed.
777      */
778     void assertOpen(){
779         if (isClosed()) {
780             throw new IllegalStateException("Pool not open");
781         }
782     }
783 
784     /**
785      * <p>Starts the evictor with the given delay. If there is an evictor
786      * running when this method is called, it is stopped and replaced with a
787      * new evictor with the specified delay.</p>
788      *
789      * <p>This method needs to be final, since it is called from a constructor.
790      * See POOL-195.</p>
791      *
792      * @param delay time in milliseconds before start and between eviction runs
793      */
794     void startEvictor(long delay) {
795         synchronized (evictionLock) {
796             EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis.msecs);
797             evictor = null;
798             evictionIterator = null;
799             if (delay > 0) {
800                 evictor = new Evictor();
801                 EvictionTimer.schedule(evictor, delay, delay);
802             }
803         }
804     }
805 
806     /**
807      * Stops the evictor.
808      */
809     void stopEvitor() {
810         startEvictor(-1L);
811     }
812     /**
813      * Tries to ensure that the configured minimum number of idle instances are
814      * available in the pool.
815      * @throws Exception if an error occurs creating idle instances
816      */
817     abstract void ensureMinIdle();
818 
819 
820     // Monitoring (primarily JMX) related methods
821 
822     /**
823      * Provides the name under which the pool has been registered with the
824      * platform MBean server or <code>null</code> if the pool has not been
825      * registered.
826      * @return the JMX name
827      */
828     // ObjectName getJmxName() {
829     //     return objectName;
830     // }
831 
832     /**
833      * Provides the stack trace for the call that created this pool. JMX
834      * registration may trigger a memory leak so it is important that pools are
835      * deregistered when no longer used by calling the {@link #close()} method.
836      * This method is provided to assist with identifying code that creates but
837      * does not close it thereby creating a memory leak.
838      * @return pool creation stack trace
839      */
840     string getCreationStackTrace() {
841         return creationStackTrace;
842     }
843 
844     /**
845      * The total number of objects successfully borrowed from this pool over the
846      * lifetime of the pool.
847      * @return the borrowed object count
848      */
849     long getBorrowedCount() {
850         return borrowedCount;
851     }
852 
853     /**
854      * The total number of objects returned to this pool over the lifetime of
855      * the pool. This excludes attempts to return the same object multiple
856      * times.
857      * @return the returned object count
858      */
859     long getReturnedCount() {
860         return returnedCount;
861     }
862 
863     /**
864      * The total number of objects created for this pool over the lifetime of
865      * the pool.
866      * @return the created object count
867      */
868     long getCreatedCount() {
869         return createdCount;
870     }
871 
872     /**
873      * The total number of objects destroyed by this pool over the lifetime of
874      * the pool.
875      * @return the destroyed object count
876      */
877     long getDestroyedCount() {
878         return destroyedCount;
879     }
880 
881     /**
882      * The total number of objects destroyed by the evictor associated with this
883      * pool over the lifetime of the pool.
884      * @return the evictor destroyed object count
885      */
886     long getDestroyedByEvictorCount() {
887         return destroyedByEvictorCount;
888     }
889 
890     /**
891      * The total number of objects destroyed by this pool as a result of failing
892      * validation during <code>borrowObject()</code> over the lifetime of the
893      * pool.
894      * @return validation destroyed object count
895      */
896     long getDestroyedByBorrowValidationCount() {
897         return destroyedByBorrowValidationCount;
898     }
899 
900     /**
901      * The mean time objects are active for based on the last {@link
902      * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
903      * @return mean time an object has been checked out from the pool among
904      * recently returned objects
905      */
906     long getMeanActiveTimeMillis() {
907         return activeTimes.getMean();
908     }
909 
910     /**
911      * The mean time objects are idle for based on the last {@link
912      * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
913      * @return mean time an object has been idle in the pool among recently
914      * borrowed objects
915      */
916     long getMeanIdleTimeMillis() {
917         return idleTimes.getMean();
918     }
919 
920     /**
921      * The mean time threads wait to borrow an object based on the last {@link
922      * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
923      * @return mean time in milliseconds that a recently served thread has had
924      * to wait to borrow an object from the pool
925      */
926     long getMeanBorrowWaitTimeMillis() {
927         return waitTimes.getMean();
928     }
929 
930     /**
931      * The maximum time a thread has waited to borrow objects from the pool.
932      * @return maximum wait time in milliseconds since the pool was created
933      */
934     long getMaxBorrowWaitTimeMillis() {
935         return maxBorrowWaitTimeMillis;
936     }
937 
938     /**
939      * The number of instances currently idle in this pool.
940      * @return count of instances available for checkout from the pool
941      */
942     abstract int getNumIdle();
943 
944     /**
945      * The listener used (if any) to receive notifications of exceptions
946      * unavoidably swallowed by the pool.
947      *
948      * @return The listener or <code>null</code> for no listener
949      */
950     SwallowedExceptionListener getSwallowedExceptionListener() {
951         return swallowedExceptionListener;
952     }
953 
954     /**
955      * The listener used (if any) to receive notifications of exceptions
956      * unavoidably swallowed by the pool.
957      *
958      * @param swallowedExceptionListener    The listener or <code>null</code>
959      *                                      for no listener
960      */
961     void setSwallowedExceptionListener(
962             SwallowedExceptionListener swallowedExceptionListener) {
963         this.swallowedExceptionListener = swallowedExceptionListener;
964     }
965 
966     /**
967      * Swallows an exception and notifies the configured listener for swallowed
968      * exceptions queue.
969      *
970      * @param swallowException exception to be swallowed
971      */
972     void swallowException(Exception swallowException) {
973         SwallowedExceptionListener listener = getSwallowedExceptionListener();
974 
975         warning(swallowException);
976 
977         if (listener is null) {
978             return;
979         }
980 
981         try {
982             listener.onSwallowException(swallowException);
983         } catch (Throwable t) {
984             // Ignore. Enjoy the irony.
985             warning(t);
986         }
987     }
988 
989     /**
990      * Updates statistics after an object is borrowed from the pool.
991      * @param p object borrowed from the pool
992      * @param waitTime time (in milliseconds) that the borrowing thread had to wait
993      */
994     void updateStatsBorrow(IPooledObject p, long waitTime) {
995         AtomicHelper.increment(borrowedCount);
996         idleTimes.add(p.getIdleTimeMillis());
997         waitTimes.add(waitTime);
998 
999         // lock-free optimistic-locking maximum
1000         long currentMax;
1001         do {
1002             currentMax = maxBorrowWaitTimeMillis;
1003             if (currentMax >= waitTime) {
1004                 break;
1005             }
1006         } while (!AtomicHelper.compareAndSet(maxBorrowWaitTimeMillis, currentMax, waitTime));
1007     }
1008 
1009     /**
1010      * Updates statistics after an object is returned to the pool.
1011      * @param activeTime the amount of time (in milliseconds) that the returning
1012      * object was checked out
1013      */
1014     void updateStatsReturn(long activeTime) {
1015         AtomicHelper.increment(returnedCount);
1016         activeTimes.add(activeTime);
1017     }
1018 
1019     /**
1020      * Marks the object as returning to the pool.
1021      * @param pooledObject instance to return to the keyed pool
1022      */
1023     protected void markReturningState(IPooledObject pooledObject) {
1024         synchronized(pooledObject) {
1025             PooledObjectState state = pooledObject.getState();
1026             if (state != PooledObjectState.ALLOCATED) {
1027                 throw new IllegalStateException(
1028                         "Object has already been returned to this pool or is invalid");
1029             }
1030             pooledObject.markReturning(); // Keep from being marked abandoned
1031         }
1032     }
1033 
1034     /**
1035      * Unregisters this pool's MBean.
1036      */
1037     // void jmxUnregister() {
1038     //     // if (objectName !is null) {
1039     //     //     try {
1040     //     //         ManagementFactory.getPlatformMBeanServer().unregisterMBean(
1041     //     //                 objectName);
1042     //     //     } catch (MBeanRegistrationException | InstanceNotFoundException e) {
1043     //     //         swallowException(e);
1044     //     //     }
1045     //     // }
1046     //     implementationMissing(false);
1047     // }
1048 
1049     /**
1050      * Registers the pool with the platform MBean server.
1051      * The registered name will be
1052      * <code>jmxNameBase + jmxNamePrefix + i</code> where i is the least
1053      * integer greater than or equal to 1 such that the name is not already
1054      * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
1055      * returning null.
1056      *
1057      * @param config Pool configuration
1058      * @param jmxNameBase default base JMX name for this pool
1059      * @param jmxNamePrefix name prefix
1060      * @return registered ObjectName, null if registration fails
1061      */
1062     // private ObjectName jmxRegister(BaseObjectPoolConfig!(T) config,
1063     //         string jmxNameBase, string jmxNamePrefix) {
1064         // ObjectName newObjectName = null;
1065         // MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
1066         // int i = 1;
1067         // bool registered = false;
1068         // string base = config.getJmxNameBase();
1069         // if (base is null) {
1070         //     base = jmxNameBase;
1071         // }
1072         // while (!registered) {
1073         //     try {
1074         //         ObjectName objName;
1075         //         // Skip the numeric suffix for the first pool in case there is
1076         //         // only one so the names are cleaner.
1077         //         if (i == 1) {
1078         //             objName = new ObjectName(base + jmxNamePrefix);
1079         //         } else {
1080         //             objName = new ObjectName(base + jmxNamePrefix + i);
1081         //         }
1082         //         mbs.registerMBean(this, objName);
1083         //         newObjectName = objName;
1084         //         registered = true;
1085         //     } catch (MalformedObjectNameException e) {
1086         //         if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
1087         //                 jmxNamePrefix) && jmxNameBase == base) {
1088         //             // Shouldn't happen. Skip registration if it does.
1089         //             registered = true;
1090         //         } else {
1091         //             // Must be an invalid name. Use the defaults instead.
1092         //             jmxNamePrefix =
1093         //                     BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
1094         //             base = jmxNameBase;
1095         //         }
1096         //     } catch (InstanceAlreadyExistsException e) {
1097         //         // Increment the index and try again
1098         //         i++;
1099         //     } catch (MBeanRegistrationException | NotCompliantMBeanException e) {
1100         //         // Shouldn't happen. Skip registration if it does.
1101         //         registered = true;
1102         //     }
1103         // }
1104         // return newObjectName;
1105     //     implementationMissing(false);
1106     //     return null;
1107     // }
1108 
1109     /**
1110      * Gets the stack trace of an exception as a string.
1111      * @param e exception to trace
1112      * @return exception stack trace as a string
1113      */
1114     private string getStackTrace(Exception e) {
1115         // Need the exception in string form to prevent the retention of
1116         // references to classes in the stack trace that could trigger a memory
1117         // leak in a container environment.
1118         // Writer w = new StringWriter();
1119         // PrintWriter pw = new PrintWriter(w);
1120         // e.printStackTrace(pw);
1121         // return w.toString();
1122         return e.toString();
1123     }
1124 
1125     // Inner classes
1126 
1127     /**
1128      * The idle object evictor {@link TimerTask}.
1129      *
1130      * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
1131      */
1132     class Evictor : Runnable {
1133 
1134         private IFuture scheduledFuture;
1135 
1136         /**
1137          * Run pool maintenance.  Evict objects qualifying for eviction and then
1138          * ensure that the minimum number of idle instances are available.
1139          * Since the Timer that invokes Evictors is shared for all Pools but
1140          * pools may exist in different class loaders, the Evictor ensures that
1141          * any actions taken are under the class loader of the factory
1142          * associated with the pool.
1143          */
1144         override
1145         void run() {
1146             // ClassLoader savedClassLoader =
1147             //         Thread.getThis().getContextClassLoader();
1148             try {
1149                 // if (factoryClassLoader !is null) {
1150                 //     // Set the class loader for the factory
1151                 //     ClassLoader cl = factoryClassLoader.get();
1152                 //     if (cl is null) {
1153                 //         // The pool has been dereferenced and the class loader
1154                 //         // GC'd. Cancel this timer so the pool can be GC'd as
1155                 //         // well.
1156                 //         cancel();
1157                 //         return;
1158                 //     }
1159                 //     Thread.getThis().setContextClassLoader(cl);
1160                 // }
1161 
1162                 // Evict from the pool
1163                 try {
1164                     evict();
1165                 } catch(Exception e) {
1166                     swallowException(e);
1167                 } catch(OutOfMemoryError oome) {
1168                     // Log problem but give evictor thread a chance to continue
1169                     // in case error is recoverable
1170                     // oome.printStackTrace(System.err);
1171                     warning(oome);
1172                 }
1173                 // Re-create idle instances.
1174                 try {
1175                     ensureMinIdle();
1176                 } catch (Exception e) {
1177                     swallowException(e);
1178                 }
1179             } finally {
1180                 // Restore the previous CCL
1181                 // Thread.getThis().setContextClassLoader(savedClassLoader);
1182             }
1183         }
1184 
1185 
1186         void setScheduledFuture(IFuture scheduledFuture) {
1187             this.scheduledFuture = scheduledFuture;
1188         }
1189 
1190 
1191         void cancel() {
1192             scheduledFuture.cancel(false);
1193         }
1194     }
1195 
1196     /**
1197      * Maintains a cache of values for a single metric and reports
1198      * statistics on the cached values.
1199      */
1200     private class StatsStore {
1201 
1202         private long[] values;
1203         private int size;
1204         private int index;
1205 
1206         /**
1207          * Create a StatsStore with the given cache size.
1208          *
1209          * @param size number of values to maintain in the cache.
1210          */
1211         this(int size) {
1212             this.size = size;
1213             values = new long[size];
1214             for (int i = 0; i < size; i++) {
1215                 values[i] = -1;
1216             }
1217         }
1218 
1219         /**
1220          * Adds a value to the cache.  If the cache is full, one of the
1221          * existing values is replaced by the new value.
1222          *
1223          * @param value new value to add to the cache.
1224          */
1225         void add(long value) { 
1226             synchronized(this) {
1227                 values[index] = value;
1228                 index++;
1229                 if (index == size) {
1230                     index = 0;
1231                 }
1232             }
1233         }
1234 
1235         /**
1236          * Returns the mean of the cached values.
1237          *
1238          * @return the mean of the cache, truncated to long
1239          */
1240         long getMean() {
1241             double result = 0;
1242             int counter = 0;
1243             for (int i = 0; i < size; i++) {
1244                 long value = values[i];
1245                 if (value != -1) {
1246                     counter++;
1247                     result = result * ((counter - 1) / cast(double) counter) +
1248                             value/cast(double) counter;
1249                 }
1250             }
1251             return cast(long) result;
1252         }
1253 
1254         override
1255         string toString() {
1256             StringBuilder builder = new StringBuilder();
1257             builder.append("StatsStore [values=");
1258             builder.append(values.to!string());
1259             builder.append(", size=");
1260             builder.append(size);
1261             builder.append(", index=");
1262             builder.append(index);
1263             builder.append("]");
1264             return builder.toString();
1265         }
1266     }
1267 
1268     override
1269     protected void toStringAppendFields(StringBuilder builder) {
1270         builder.append("maxTotal=");
1271         builder.append(maxTotal);
1272         builder.append(", blockWhenExhausted=");
1273         builder.append(blockWhenExhausted);
1274         builder.append(", maxWaitMillis=");
1275         builder.append(maxWaitMillis);
1276         builder.append(", lifo=");
1277         builder.append(lifo);
1278         builder.append(", fairness=");
1279         builder.append(fairness);
1280         builder.append(", testOnCreate=");
1281         builder.append(testOnCreate);
1282         builder.append(", testOnBorrow=");
1283         builder.append(testOnBorrow);
1284         builder.append(", testOnReturn=");
1285         builder.append(testOnReturn);
1286         builder.append(", testWhileIdle=");
1287         builder.append(testWhileIdle);
1288         builder.append(", timeBetweenEvictionRunsMillis=");
1289         builder.append(timeBetweenEvictionRunsMillis);
1290         builder.append(", numTestsPerEvictionRun=");
1291         builder.append(numTestsPerEvictionRun);
1292         builder.append(", minEvictableIdleTimeMillis=");
1293         builder.append(minEvictableIdleTimeMillis);
1294         builder.append(", softMinEvictableIdleTimeMillis=");
1295         builder.append(softMinEvictableIdleTimeMillis);
1296         builder.append(", evictionPolicy=");
1297         builder.append((cast(Object)evictionPolicy).toString());
1298         builder.append(", closeLock=");
1299         builder.append(closeLock);
1300         builder.append(", closed=");
1301         builder.append(closed);
1302         builder.append(", evictionLock=");
1303         builder.append(evictionLock);
1304         builder.append(", evictor=");
1305         builder.append(evictor);
1306         builder.append(", evictionIterator=");
1307         builder.append(evictionIterator);
1308         // builder.append(", factoryClassLoader=");
1309         // builder.append(factoryClassLoader);
1310         // builder.append(", oname=");
1311         // builder.append(objectName);
1312         builder.append(", creationStackTrace=");
1313         builder.append(creationStackTrace);
1314         builder.append(", borrowedCount=");
1315         builder.append(borrowedCount);
1316         builder.append(", returnedCount=");
1317         builder.append(returnedCount);
1318         builder.append(", createdCount=");
1319         builder.append(createdCount);
1320         builder.append(", destroyedCount=");
1321         builder.append(destroyedCount);
1322         builder.append(", destroyedByEvictorCount=");
1323         builder.append(destroyedByEvictorCount);
1324         builder.append(", destroyedByBorrowValidationCount=");
1325         builder.append(destroyedByBorrowValidationCount);
1326         builder.append(", activeTimes=");
1327         builder.append(activeTimes);
1328         builder.append(", idleTimes=");
1329         builder.append(idleTimes);
1330         builder.append(", waitTimes=");
1331         builder.append(waitTimes);
1332         builder.append(", maxBorrowWaitTimeMillis=");
1333         builder.append(maxBorrowWaitTimeMillis);
1334         builder.append(", swallowedExceptionListener=");
1335         builder.append((cast(Object)swallowedExceptionListener).toString());
1336     }
1337 
1338 
1339 }
1340 
1341 
1342 /**
1343  * Wrapper for objects under management by the pool.
1344  *
1345  * GenericObjectPool and GenericKeyedObjectPool maintain references to all
1346  * objects under management using maps keyed on the objects. This wrapper
1347  * class ensures that objects can work as hash keys.
1348  *
1349  * @param <T> type of objects in the pool
1350  */
1351 class IdentityWrapper(T) {
1352     /** Wrapped object */
1353     private T instance;
1354 
1355     /**
1356      * Create a wrapper for an instance.
1357      *
1358      * @param instance object to wrap
1359      */
1360     this(T instance) {
1361         this.instance = instance;
1362     }
1363 
1364     override
1365     size_t toHash() @trusted nothrow {
1366         return (cast(Object)instance).toHash();
1367     }
1368 
1369     override
1370     bool opEquals(Object other) {
1371         IdentityWrapper iw = cast(IdentityWrapper)other;
1372         if(iw is null) return false;
1373 
1374         return iw.instance == instance;
1375     }
1376 
1377     /**
1378      * @return the wrapped object
1379      */
1380     T getObject() {
1381         return instance;
1382     }
1383 
1384     override
1385     string toString() {
1386         StringBuilder builder = new StringBuilder();
1387         builder.append("IdentityWrapper [instance=");
1388         builder.append(cast(Object)instance);
1389         builder.append("]");
1390         return builder.toString();
1391     }
1392 }
1393 
1394 
1395 
1396 
1397 /**
1398  * The idle object eviction iterator. Holds a reference to the idle objects.
1399  */
1400 class EvictionIterator : InputRange!(IPooledObject) {
1401 
1402     private Deque!(IPooledObject) idleObjects;
1403     private InputRange!(IPooledObject) idleObjectIterator;
1404 
1405     /**
1406      * Create an EvictionIterator for the provided idle instance deque.
1407      * @param idleObjects underlying deque
1408      */
1409     this(Deque!(IPooledObject) idleObjects, bool isLifo) {
1410         this.idleObjects = idleObjects;
1411 
1412         if (isLifo) {
1413             idleObjectIterator = idleObjects.descendingIterator();
1414         } else {
1415             idleObjectIterator = idleObjects.iterator();
1416         }
1417     }
1418 
1419     /**
1420      * Returns the idle object deque referenced by this iterator.
1421      * @return the idle object deque
1422      */
1423     Deque!(IPooledObject) getIdleObjects() {
1424         return idleObjects;
1425     }
1426 
1427     /** {@inheritDoc} */
1428     // override
1429     bool empty() @property {
1430         return idleObjectIterator.empty();
1431     }
1432 
1433     /** {@inheritDoc} */
1434     // override
1435     IPooledObject front() @property {
1436         return idleObjectIterator.front();
1437     }
1438 
1439     void popFront() {
1440         idleObjectIterator.popFront();
1441     }
1442 
1443     IPooledObject moveFront() { return idleObjectIterator.moveFront(); }
1444 
1445     int opApply(scope int delegate(IPooledObject) dg) {
1446         return idleObjectIterator.opApply(dg);
1447     }
1448 
1449     /// Ditto
1450     int opApply(scope int delegate(size_t, IPooledObject) dg) {
1451         return idleObjectIterator.opApply(dg);
1452     }
1453 
1454 }