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.SoftReferenceObjectPool;
18 
19 // import java.lang.ref.Reference;
20 // import java.lang.ref.ReferenceQueue;
21 // import java.lang.ref.SoftReference;
22 // import java.util.ArrayList;
23 // import java.util.Iterator;
24 // import java.util.NoSuchElementException;
25 
26 import hunt.Exceptions;
27 
28 import hunt.pool.BaseObjectPool;
29 import hunt.pool.ObjectPool;
30 import hunt.pool.PoolUtils;
31 import hunt.pool.PooledObjectFactory;
32 
33 /**
34  * A {@link java.lang.ref.SoftReference SoftReference} based {@link ObjectPool}.
35  * <p>
36  * This class is intended to be thread-safe.
37  *
38  * @param <T>
39  *            Type of element pooled in this pool.
40  *
41  */
42 // class SoftReferenceObjectPool(T) : BaseObjectPool!(T) {
43 
44 //     /** Factory to source pooled objects */
45 //     private PooledObjectFactory!(T) factory;
46 
47 //     /**
48 //      * Queue of broken references that might be able to be removed from
49 //      * <code>_pool</code>. This is used to help {@link #getNumIdle()} be more
50 //      * accurate with minimal performance overhead.
51 //      */
52 //     private ReferenceQueue!(T) refQueue = new ReferenceQueue<>();
53 
54 //     /** Count of instances that have been checkout out to pool clients */
55 //     private int numActive = 0; // @GuardedBy("this")
56 
57 //     /** Total number of instances that have been destroyed */
58 //     private long destroyCount = 0; // @GuardedBy("this")
59 
60 
61 //     /** Total number of instances that have been created */
62 //     private long createCount = 0; // @GuardedBy("this")
63 
64 //     /** Idle references - waiting to be borrowed */
65 //     private LinkedBlockingDeque!(PooledSoftReference!(T)) idleReferences =
66 //         new LinkedBlockingDeque<>();
67 
68 //     /** All references - checked out or waiting to be borrowed. */
69 //     private ArrayList!(PooledSoftReference!(T)) allReferences =
70 //         new ArrayList<>();
71 
72 //     /**
73 //      * Create a <code>SoftReferenceObjectPool</code> with the specified factory.
74 //      *
75 //      * @param factory object factory to use.
76 //      */
77 //     this(PooledObjectFactory!(T) factory) {
78 //         this.factory = factory;
79 //     }
80 
81 //     /**
82 //      * Borrows an object from the pool. If there are no idle instances available
83 //      * in the pool, the configured factory's
84 //      * {@link PooledObjectFactory#makeObject()} method is invoked to create a
85 //      * new instance.
86 //      * <p>
87 //      * All instances are {@link PooledObjectFactory#activateObject(
88 //      * hunt.pool.PooledObject) activated}
89 //      * and {@link PooledObjectFactory#validateObject(
90 //      * hunt.pool.PooledObject)
91 //      * validated} before being returned by this method. If validation fails or
92 //      * an exception occurs activating or validating an idle instance, the
93 //      * failing instance is {@link PooledObjectFactory#destroyObject(
94 //      * hunt.pool.PooledObject)
95 //      * destroyed} and another instance is retrieved from the pool, validated and
96 //      * activated. This process continues until either the pool is empty or an
97 //      * instance passes validation. If the pool is empty on activation or it does
98 //      * not contain any valid instances, the factory's <code>makeObject</code>
99 //      * method is used to create a new instance. If the created instance either
100 //      * raises an exception on activation or fails validation,
101 //      * <code>NoSuchElementException</code> is thrown. Exceptions thrown by
102 //      * <code>MakeObject</code> are propagated to the caller; but other than
103 //      * <code>ThreadDeath</code> or <code>VirtualMachineError</code>, exceptions
104 //      * generated by activation, validation or destroy methods are swallowed
105 //      * silently.
106 //      *
107 //      * @throws NoSuchElementException
108 //      *             if a valid object cannot be provided
109 //      * @throws IllegalStateException
110 //      *             if invoked on a {@link #close() closed} pool
111 //      * @throws Exception
112 //      *             if an exception occurs creating a new instance
113 //      * @return a valid, activated object instance
114 //      */
115 //     override
116 //     T borrowObject() { // synchronized
117 //         assertOpen();
118 //         T obj = null;
119 //         bool newlyCreated = false;
120 //         PooledSoftReference!(T) ref = null;
121 //         // while (null == obj) {
122 //         //     if (idleReferences.isEmpty()) {
123 //         //         if (null == factory) {
124 //         //             throw new NoSuchElementException();
125 //         //         }
126 //         //         newlyCreated = true;
127 //         //         obj = factory.makeObject().getObject();
128 //         //         createCount++;
129 //         //         // Do not register with the queue
130 //         //         ref = new PooledSoftReference<>(new SoftReference<>(obj));
131 //         //         allReferences.add(ref);
132 //         //     } else {
133 //         //         ref = idleReferences.pollFirst();
134 //         //         obj = ref.getObject();
135 //         //         // Clear the reference so it will not be queued, but replace with a
136 //         //         // a new, non-registered reference so we can still track this object
137 //         //         // in allReferences
138 //         //         ref.getReference().clear();
139 //         //         ref.setReference(new SoftReference<>(obj));
140 //         //     }
141 //         //     if (null != factory && null != obj) {
142 //         //         try {
143 //         //             factory.activateObject(ref);
144 //         //             if (!factory.validateObject(ref)) {
145 //         //                 throw new Exception("ValidateObject failed");
146 //         //             }
147 //         //         } catch (Throwable t) {
148 //         //             PoolUtils.checkRethrow(t);
149 //         //             try {
150 //         //                 destroy(ref);
151 //         //             } catch (Throwable t2) {
152 //         //                 PoolUtils.checkRethrow(t2);
153 //         //                 // Swallowed
154 //         //             } finally {
155 //         //                 obj = null;
156 //         //             }
157 //         //             if (newlyCreated) {
158 //         //                 throw new NoSuchElementException(
159 //         //                         "Could not create a validated object, cause: " ~
160 //         //                                 t.getMessage());
161 //         //             }
162 //         //         }
163 //         //     }
164 //         // }
165 //         // numActive++;
166 //         // ref.allocate();
167 //         implementationMissing(false);
168 //         return obj;
169 //     }
170 
171 //     /**
172 //      * Returns an instance to the pool after successful validation and
173 //      * passivation. The returning instance is destroyed if any of the following
174 //      * are true:
175 //      * <ul>
176 //      * <li>the pool is closed</li>
177 //      * <li>{@link PooledObjectFactory#validateObject(
178 //      * hunt.pool.PooledObject) validation} fails
179 //      * </li>
180 //      * <li>{@link PooledObjectFactory#passivateObject(
181 //      * hunt.pool.PooledObject) passivation}
182 //      *exception</li>
183 //      * </ul>
184 //      * Exceptions passivating or destroying instances are silently swallowed.
185 //      * Exceptions validating instances are propagated to the client.
186 //      *
187 //      * @param obj
188 //      *            instance to return to the pool
189 //      */
190 //     override
191 //     synchronized void returnObject(T obj){
192 //         bool success = !isClosed();
193 //         PooledSoftReference!(T) ref = findReference(obj);
194 //         if (ref is null) {
195 //             throw new IllegalStateException(
196 //                 "Returned object not currently part of this pool");
197 //         }
198 //         if (factory !is null) {
199 //             if (!factory.validateObject(ref)) {
200 //                 success = false;
201 //             } else {
202 //                 try {
203 //                     factory.passivateObject(ref);
204 //                 } catch (Exception e) {
205 //                     success = false;
206 //                 }
207 //             }
208 //         }
209 
210 //         bool shouldDestroy = !success;
211 //         numActive--;
212 //         if (success) {
213 
214 //             // Deallocate and add to the idle instance pool
215 //             ref.deallocate();
216 //             idleReferences.add(ref);
217 //         }
218 //         notifyAll(); // numActive has changed
219 
220 //         if (shouldDestroy && factory !is null) {
221 //             try {
222 //                 destroy(ref);
223 //             } catch (Exception e) {
224 //                 // ignored
225 //             }
226 //         }
227 //     }
228 
229 //     /**
230 //      * {@inheritDoc}
231 //      */
232 //     override
233 //     synchronized void invalidateObject(T obj){
234 //         PooledSoftReference!(T) ref = findReference(obj);
235 //         if (ref is null) {
236 //             throw new IllegalStateException(
237 //                 "Object to invalidate is not currently part of this pool");
238 //         }
239 //         if (factory !is null) {
240 //             destroy(ref);
241 //         }
242 //         numActive--;
243 //         notifyAll(); // numActive has changed
244 //     }
245 
246 //     /**
247 //      * Creates an object, and places it into the pool. addObject() is useful for
248 //      * "pre-loading" a pool with idle objects.
249 //      * <p>
250 //      * Before being added to the pool, the newly created instance is
251 //      * {@link PooledObjectFactory#validateObject(
252 //      * hunt.pool.PooledObject) validated} and
253 //      * {@link PooledObjectFactory#passivateObject(
254 //      * hunt.pool.PooledObject) passivated}. If
255 //      * validation fails, the new instance is
256 //      * {@link PooledObjectFactory#destroyObject(
257 //      * hunt.pool.PooledObject) destroyed}. Exceptions
258 //      * generated by the factory <code>makeObject</code> or
259 //      * <code>passivate</code> are propagated to the caller. Exceptions
260 //      * destroying instances are silently swallowed.
261 //      *
262 //      * @throws IllegalStateException
263 //      *             if invoked on a {@link #close() closed} pool
264 //      * @throws Exception
265 //      *             when the {@link #getFactory() factory} has a problem creating
266 //      *             or passivating an object.
267 //      */
268 //     override
269 //     synchronized void addObject(){
270 //         assertOpen();
271 //         if (factory is null) {
272 //             throw new IllegalStateException(
273 //                     "Cannot add objects without a factory.");
274 //         }
275 //         T obj = factory.makeObject().getObject();
276 //         createCount++;
277 //         // Create and register with the queue
278 //         PooledSoftReference!(T) ref = new PooledSoftReference<>(
279 //                 new SoftReference<>(obj, refQueue));
280 //         allReferences.add(ref);
281 
282 //         bool success = true;
283 //         if (!factory.validateObject(ref)) {
284 //             success = false;
285 //         } else {
286 //             factory.passivateObject(ref);
287 //         }
288 
289 //         bool shouldDestroy = !success;
290 //         if (success) {
291 //             idleReferences.add(ref);
292 //             notifyAll(); // numActive has changed
293 //         }
294 
295 //         if (shouldDestroy) {
296 //             try {
297 //                 destroy(ref);
298 //             } catch (Exception e) {
299 //                 // ignored
300 //             }
301 //         }
302 //     }
303 
304 //     /**
305 //      * Returns an approximation not less than the of the number of idle
306 //      * instances in the pool.
307 //      *
308 //      * @return estimated number of idle instances in the pool
309 //      */
310 //     override
311 //     synchronized int getNumIdle() {
312 //         pruneClearedReferences();
313 //         return idleReferences.size();
314 //     }
315 
316 //     /**
317 //      * Returns the number of instances currently borrowed from this pool.
318 //      *
319 //      * @return the number of instances currently borrowed from this pool
320 //      */
321 //     override
322 //     synchronized int getNumActive() {
323 //         return numActive;
324 //     }
325 
326 //     /**
327 //      * Clears any objects sitting idle in the pool.
328 //      */
329 //     override
330 //     synchronized void clear() {
331 //         if (null != factory) {
332 //             Iterator!(PooledSoftReference!(T)) iter = idleReferences.iterator();
333 //             while (iter.hasNext()) {
334 //                 try {
335 //                     PooledSoftReference!(T) ref = iter.next();
336 //                     if (null != ref.getObject()) {
337 //                         factory.destroyObject(ref);
338 //                     }
339 //                 } catch (Exception e) {
340 //                     // ignore error, keep destroying the rest
341 //                 }
342 //             }
343 //         }
344 //         idleReferences.clear();
345 //         pruneClearedReferences();
346 //     }
347 
348 //     /**
349 //      * Closes this pool, and frees any resources associated with it. Invokes
350 //      * {@link #clear()} to destroy and remove instances in the pool.
351 //      * <p>
352 //      * Calling {@link #addObject} or {@link #borrowObject} after invoking this
353 //      * method on a pool will cause them to throw an
354 //      * {@link IllegalStateException}.
355 //      */
356 //     override
357 //     void close() {
358 //         super.close();
359 //         clear();
360 //     }
361 
362 //     /**
363 //      * Returns the {@link PooledObjectFactory} used by this pool to create and
364 //      * manage object instances.
365 //      *
366 //      * @return the factory
367 //      */
368 //     synchronized PooledObjectFactory!(T) getFactory() {
369 //         return factory;
370 //     }
371 
372 //     /**
373 //      * If any idle objects were garbage collected, remove their
374 //      * {@link Reference} wrappers from the idle object pool.
375 //      */
376 //     private void pruneClearedReferences() {
377 //         // Remove wrappers for enqueued references from idle and allReferences lists
378 //         removeClearedReferences(idleReferences.iterator());
379 //         removeClearedReferences(allReferences.iterator());
380 //         while (refQueue.poll() !is null) {
381 //             // empty
382 //         }
383 //     }
384 
385 //     /**
386 //      * Finds the PooledSoftReference in allReferences that points to obj.
387 //      *
388 //      * @param obj returning object
389 //      * @return PooledSoftReference wrapping a soft reference to obj
390 //      */
391 //     private PooledSoftReference!(T) findReference(T obj) {
392 //         Iterator!(PooledSoftReference!(T)) iterator = allReferences.iterator();
393 //         while (iterator.hasNext()) {
394 //             PooledSoftReference!(T) reference = iterator.next();
395 //             if (reference.getObject() !is null && reference.getObject() == obj) {
396 //                 return reference;
397 //             }
398 //         }
399 //         return null;
400 //     }
401 
402 //     /**
403 //      * Destroys a {@code PooledSoftReference} and removes it from the idle and all
404 //      * references pools.
405 //      *
406 //      * @param toDestroy PooledSoftReference to destroy
407 //      *
408 //      * @throws Exception If an error occurs while trying to destroy the object
409 //      */
410 //     private void destroy(PooledSoftReference!(T) toDestroy){
411 //         toDestroy.invalidate();
412 //         idleReferences.remove(toDestroy);
413 //         allReferences.remove(toDestroy);
414 //         try {
415 //             factory.destroyObject(toDestroy);
416 //         } finally {
417 //             destroyCount++;
418 //             toDestroy.getReference().clear();
419 //         }
420 //     }
421 
422 //     /**
423 //      * Clears cleared references from iterator's collection
424 //      * @param iterator iterator over idle/allReferences
425 //      */
426 //     private void removeClearedReferences(Iterator!(PooledSoftReference!(T)) iterator) {
427 //         PooledSoftReference!(T) ref;
428 //         while (iterator.hasNext()) {
429 //             ref = iterator.next();
430 //             if (ref.getReference() is null || ref.getReference().isEnqueued()) {
431 //                 iterator.remove();
432 //             }
433 //         }
434 //     }
435 
436 //     override
437 //     protected void toStringAppendFields(StringBuilder builder) {
438 //         super.toStringAppendFields(builder);
439 //         builder.append(", factory=");
440 //         builder.append(factory);
441 //         builder.append(", refQueue=");
442 //         builder.append(refQueue);
443 //         builder.append(", numActive=");
444 //         builder.append(numActive);
445 //         builder.append(", destroyCount=");
446 //         builder.append(destroyCount);
447 //         builder.append(", createCount=");
448 //         builder.append(createCount);
449 //         builder.append(", idleReferences=");
450 //         builder.append(idleReferences);
451 //         builder.append(", allReferences=");
452 //         builder.append(allReferences);
453 //     }
454 // }