2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
28 package org.onap.aaf.cadi.util;
30 import java.util.Iterator;
31 import java.util.LinkedList;
33 import org.onap.aaf.cadi.CadiException;
36 * This Class pools on an As-Needed-Basis any particular kind of class, which is
37 * quite suitable for expensive operations.
39 * The user calls "get" on a Pool, and if a waiting resource (T) is available,
40 * it will be returned. Otherwise, one will be created with the "Creator" class
41 * (must be defined for (T)).
43 * You can Prime the instances to avoid huge startup costs
45 * The returned "Pooled" object simply has to call "done()" and the object is
46 * returned to the pool. If the developer does not return the object, a memory
47 * leak does not occur. There are no references to the object once "get" is
48 * called. However, the developer who does not return the object when done
49 * obviates the point of the pool, as new Objects are created in place of the
50 * Object not returned when another call to "get" is made.
52 * There is a cushion of extra objects, currently defaulted to MAX_RANGE. If the
53 * items returned become higher than the MAX_RANGE, the object is allowed to go
54 * out of scope, and be cleaned up. the default can be changed on a per-pool
57 * Class revamped for CadiExceptions and Access logging 10/4/2017
63 public class Pool<T> {
65 * This is a constant which specified the default maximum number of unused
66 * objects to be held at any given time.
68 public static final int MAX_RANGE = 6; // safety
71 * Maximum objects, in use or waiting
73 public static final int MAX_OBJECTS = 20; // assumption for thread
76 * only Simple List needed.
78 * NOTE TO MAINTAINERS: THIS OBJECT DOES IT'S OWN SYNCHRONIZATION. All
79 * changes that touch list must account for correctly synchronizing list.
81 private LinkedList<Pooled<T>> list;
84 * keep track of how many elements are currently available to use, to avoid asking list.
89 * how many objects have been asked for, but not returned or tossed
94 * Actual MAX number of spares allowed to hang around. Can be set to
95 * something besides the default MAX_RANGE.
97 private int max_range = MAX_RANGE;
100 * Actual MAX number of Objects both in use, or waiting.
101 * This does not actually affect the Pool, because the objects, once they leave the pool, are not known until
102 * they are put back with done (offer). It only affects the "overLimit()" function.
104 * Important... this information is only valid if PooledObjects call "done()" or "toss()".
106 private int max_objects = MAX_OBJECTS;
109 * The Creator for this particular pool. It must work for type T.
111 private Creator<T> creator;
116 * Create a new Pool, given the implementation of Creator<T>, which must be
117 * able to create/destroy T objects at will.
121 public Pool(Creator<T> creator) {
123 this.creator = creator;
124 list = new LinkedList<>();
129 * Attach Pool Logging activities to any other Logging Mechanism.
132 public void setLogger(Log logger) {
133 this.logger = logger;
134 // Also reset existing Pooled objects
135 for(Pooled<?> p : list) {
136 if(p.content instanceof LogAware) {
137 ((LogAware)p.content).setLog(logger);
144 public void log(Log.Type type, Object ...objects) {
145 logger.log(type,objects);
149 * Preallocate a certain number of T Objects. Useful for services so that
150 * the first transactions don't get hit with all the Object creation costs
152 * It is assumed that priming also means that it is the minimum desired available resources. Therefore,
153 * max_range is set to prime, if less than current max_range, if it is default.
157 * @throws CadiException
159 public Pool<T> prime(int prime) throws CadiException {
160 if(max_range == MAX_RANGE && prime<max_range) {
163 for (int i = 0; i < prime; ++i) {
164 Pooled<T> pt = new Pooled<T>(creator.create(), this);
165 synchronized (list) {
175 * Destroy and remove all remaining objects. This is valuable for closing
176 * down all Allocated objects cleanly for exiting. It is also a good method
177 * for removing objects when, for instance, all Objects are invalid because
178 * of broken connections, etc.
180 * Use in conjunction with setMaxRange to no longer store objects, i.e.
182 * pool.setMaxRange(0).drain();
184 public synchronized void drain() {
185 while(list.size()>0) {
186 Pooled<T> pt = list.remove();
188 String name = pt.content.toString();
189 creator.destroy(pt.content);
190 logger.log(Log.Type.debug,"Pool destroyed", name);
196 * This is the essential function for Pool. Get an Object "T" inside a
197 * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
198 * create and pass back.
200 * This one uses a Null LogTarget
202 * IMPORTANT: When the use of this object is done (and the object is still
203 * in a valid state), then "done()" should be called immediately to allow
204 * the object to be reused. That is the point of the Pool...
206 * If the Object is in an invalid state, then "toss()" should be used so the
207 * Pool doesn't pass on invalid objects to others.
211 * @throws CadiException
213 public Pooled<T> get() throws CadiException {
215 synchronized (list) {
216 pt = list.pollLast();
219 pt = new Pooled<T>(creator.create(), this);
223 creator.reuse(pt.content);
229 * This function will validate whether the Objects are still in a usable
230 * state. If not, they are tossed from the Pool. This is valuable to have
231 * when Remote Connections go down, and there is a question on whether the
232 * Pooled Objects are still functional.
236 public boolean validate() {
238 synchronized (list) {
239 for (Iterator<Pooled<T>> iter = list.iterator(); iter.hasNext();) {
240 Pooled<T> t = iter.next();
241 if (!creator.isValid(t.content)) {
252 * This is an internal method, used only by the Internal Pooled<T> class.
254 * The Pooled<T> class "offers" it's Object back after use. It is an
255 * "offer", because Pool will simply destroy and remove the object if it has
256 * more than enough spares.
262 // Used only by Pooled<T>
263 private boolean offer(Pooled<T> usedP) {
264 if (count < max_range) {
265 synchronized (list) {
266 list.addFirst(usedP);
269 logger.log(Log.Type.trace,"Pool recovered ", creator);
271 destroy(usedP.content);
277 * Destroy, using Creator's specific semantics, the Object, and decrement "used"
281 private void destroy(T t) {
283 synchronized (list) {
286 logger.log(Log.Type.debug,"Pool destroyed ", creator);
290 * The Creator Interface give the Pool the ability to Create, Destroy and
291 * Validate the Objects it is maintaining. Thus, it is a specially written
292 * Implementation for each type.
298 public interface Creator<T> {
299 public T create() throws CadiException;
301 public void destroy(T t);
303 public boolean isValid(T t);
305 public void reuse(T t);
309 * Pooled Classes can be "Log Aware", which means they can tie into the same
310 * Logging element that the Pool is using. To do this, the Object must implement "LogAware"
315 public interface LogAware {
316 public void setLog(Log log);
320 * The "Pooled<T>" class is the transient class that wraps the actual Object
321 * T for API use/ It gives the ability to return ("done()", or "toss()") the
322 * Object to the Pool when processing is finished.
324 * For Safety, i.e. to avoid memory leaks and invalid Object States, there
325 * is a "finalize" method. It is strictly for when coder forgets to return
326 * the object, or perhaps hasn't covered the case during Exceptions or
327 * Runtime Exceptions with finally (preferred). This should not be
328 * considered normal procedure, as finalize() is called at an undetermined
329 * time during garbage collection, and is thus rather useless for a Pool.
330 * However, we don't want Coding Mistakes to put the whole program in an
331 * invalid state, so if something happened such that "done()" or "toss()"
332 * were not called, the resource is still cleaned up as well as possible.
338 public static class Pooled<T> {
339 public final T content;
340 private Pool<T> pool;
343 * Create the Wrapping Object Pooled<T>.
349 public Pooled(T t, Pool<T> pool) {
351 if(t instanceof LogAware) {
352 ((LogAware)t).setLog(pool.logger);
358 * This is the key API for the Pool, as calling "done()" offers this
359 * object back to the Pool for reuse.
361 * Do not use the Pooled<T> object again after calling "done()".
370 * The user of the Object may discover that the Object t is no longer in
371 * a valid state. Don't put Garbage back in the Refrigerator... Toss it,
372 * if it's no longer valid.
374 * toss() is also used for draining the Pool, etc.
376 * toss() will attempt to destroy the Object by using the Creator
382 pool.destroy(content);
384 // Don't allow finalize to put it back in.
389 * Just in case someone neglected to offer back object... Do not rely on
390 * this, as there is no specific time when finalize is called, which
391 * rather defeats the purpose of a Pool.
394 protected void finalize() throws Throwable {
402 public String toString() {
403 return content.toString();
408 * Set a Max Range for numbers of spare objects waiting to be used.
410 * No negative numbers are allowed
412 * Use in conjunction with drain to no longer store objects, i.e.
414 * pool.setMaxRange(0).drain();
418 public Pool<T> setMaxRange(int max_range) {
419 // Do not allow negative numbers
420 this.max_range = Math.max(0, max_range);
425 * Set a Max Range for numbers of spare objects waiting to be used.
427 * No negative numbers are allowed
431 public Pool<T> setMaxObjects(int max_objects) {
432 // Do not allow negative numbers
433 this.max_objects = Math.max(0, max_objects);
438 * return whether objects in use or waiting are beyond max allowed
440 * Pool does not actually stop new creations, but allows this to be used by
441 * other entities to limit number of creations of expensive Objects, like
445 public boolean tooManyObjects() {
446 return used > max_objects;
449 public String toString() {
450 return String.format("Pool: count(%d), used(%d), max_range(%d), max_objects(%d)",
451 count, used,max_range,max_objects);