d61aee21d9c07b2e43b548f798812e5726d2d8e2
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / util / Pool.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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====================================================
19  *
20  */
21
22 /*
23  * Pool
24  * 
25  * Author: Jonathan
26  * 5/27/2011
27  */
28 package org.onap.aaf.cadi.util;
29
30 import java.util.LinkedList;
31
32 import org.onap.aaf.cadi.CadiException;
33
34 /**
35  * This Class pools on an As-Needed-Basis any particular kind of class, which is
36  * quite suitable for expensive operations.
37  * 
38  * The user calls "get" on a Pool, and if a waiting resource (T) is available,
39  * it will be returned. Otherwise, one will be created with the "Creator" class
40  * (must be defined for (T)).
41  * 
42  * You can Prime the instances to avoid huge startup costs
43  * 
44  * The returned "Pooled" object simply has to call "done()" and the object is
45  * returned to the pool. If the developer does not return the object, a memory
46  * leak does not occur. There are no references to the object once "get" is
47  * called. However, the developer who does not return the object when done
48  * obviates the point of the pool, as new Objects are created in place of the
49  * Object not returned when another call to "get" is made.
50  * 
51  * There is a cushion of extra objects, currently defaulted to MAX_RANGE. If the
52  * items returned become higher than the MAX_RANGE, the object is allowed to go
53  * out of scope, and be cleaned up. the default can be changed on a per-pool
54  * basis.
55  * 
56  * Class revamped for CadiExceptions and Access logging 10/4/2017
57  * 
58  * @author Jonathan
59  * 
60  * @param <T>
61  */
62 public class Pool<T> {
63         /**
64          * This is a constant which specified the default maximum number of unused
65          * objects to be held at any given time.
66          */
67         private static final int MAX_RANGE = 6; // safety
68
69         /**
70          * only Simple List needed.
71          * 
72          * NOTE TO MAINTAINERS: THIS OBJECT DOES IT'S OWN SYNCHRONIZATION. All
73          * changes that touch list must account for correctly synchronizing list.
74          */
75         private LinkedList<Pooled<T>> list;
76
77         /**
78          * keep track of how many elements exist, to avoid asking list.
79          */
80         private int count;
81
82         /**
83          * Spares are those Object that are primed and ready to go.
84          */
85         private int spares;
86
87         /**
88          * Actual MAX number of spares allowed to hang around. Can be set to
89          * something besides the default MAX_RANGE.
90          */
91         private int max_range = MAX_RANGE;
92
93         /**
94          * The Creator for this particular pool. It must work for type T.
95          */
96         private Creator<T> creator;
97
98         private Log logger;
99
100         /**
101          * Create a new Pool, given the implementation of Creator<T>, which must be
102          * able to create/destroy T objects at will.
103          * 
104          * @param creator
105          */
106         public Pool(Creator<T> creator) {
107                 count = spares = 0;
108                 this.creator = creator;
109                 list = new LinkedList<Pooled<T>>();
110                 logger = Log.NULL;
111         }
112         
113         /**
114          * Attach Pool Logging activities to any other Logging Mechanism.
115          * @param logger
116          */
117         public void setLogger(Log logger) {
118                 this.logger = logger;
119         }
120         
121         public void log(Object ...objects) {
122                 logger.log(objects);
123         }
124
125         /**
126          * Preallocate a certain number of T Objects. Useful for services so that
127          * the first transactions don't get hit with all the Object creation costs
128          * 
129          * @param lt
130          * @param prime
131          * @throws CadiException 
132          */
133         public void prime(int prime) throws CadiException  {
134                 for (int i = 0; i < prime; ++i) {
135                         Pooled<T> pt = new Pooled<T>(creator.create(), this);
136                         synchronized (list) {
137                                 list.addFirst(pt);
138                                 ++count;
139                         }
140                 }
141
142         }
143
144         /**
145          * Destroy and remove all remaining objects. This is valuable for closing
146          * down all Allocated objects cleanly for exiting. It is also a good method
147          * for removing objects when, for instance, all Objects are invalid because
148          * of broken connections, etc.
149          */
150         public void drain() {
151                 synchronized (list) {
152                         for (int i = 0; i < list.size(); ++i) {
153                                 Pooled<T> pt = list.remove();
154                                 creator.destroy(pt.content);
155                                 logger.log("Pool drained ", creator.toString());
156                         }
157                         count = spares = 0;
158                 }
159
160         }
161
162         /**
163          * This is the essential function for Pool. Get an Object "T" inside a
164          * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
165          * create and pass back.
166          * 
167          * This one uses a Null LogTarget
168          * 
169          * IMPORTANT: When the use of this object is done (and the object is still
170          * in a valid state), then "done()" should be called immediately to allow
171          * the object to be reused. That is the point of the Pool...
172          * 
173          * If the Object is in an invalid state, then "toss()" should be used so the
174          * Pool doesn't pass on invalid objects to others.
175          * 
176          * @param lt
177          * @return
178          * @throws CadiException
179          */
180         public Pooled<T> get() throws CadiException {
181                 Pooled<T> pt;
182                 synchronized (list) {
183                         if (list.isEmpty()) {
184                                 pt = null;
185                         } else {
186                                 pt = list.removeLast();
187                                 --count;
188                                 creator.reuse(pt.content);
189                         }
190                 }
191                 if (pt == null) {
192                         if (spares < max_range)
193                                 ++spares;
194                         pt = new Pooled<T>(creator.create(), this);
195                 } else {
196                         if (spares > 1)
197                                 --spares;
198                 }
199                 return pt;
200         }
201
202         /**
203          * This function will validate whether the Objects are still in a usable
204          * state. If not, they are tossed from the Pool. This is valuable to have
205          * when Remote Connections go down, and there is a question on whether the
206          * Pooled Objects are still functional.
207          * 
208          * @return
209          */
210         public boolean validate() {
211                 boolean rv = true;
212                 synchronized (list) {
213                         for (Pooled<T> t : list) {
214                                 if (!creator.isValid(t.content)) {
215                                         rv = false;
216                                         t.toss();
217                                         list.remove(t);
218                                 }
219                         }
220                 }
221                 return rv;
222         }
223
224         /**
225          * This is an internal method, used only by the Internal Pooled<T> class.
226          * 
227          * The Pooled<T> class "offers" it's Object back after use. It is an
228          * "offer", because Pool will simply destroy and remove the object if it has
229          * more than enough spares.
230          * 
231          * @param lt
232          * @param used
233          * @return
234          */
235         // Used only by Pooled<T>
236         private boolean offer(Pooled<T> used) {
237                 if (count < spares) {
238                         synchronized (list) {
239                                 list.addFirst(used);
240                                 ++count;
241                         }
242                         logger.log("Pool recovered ", creator);
243                 } else {
244                         logger.log("Pool destroyed ", creator);
245                         creator.destroy(used.content);
246                 }
247                 return false;
248         }
249
250         /**
251          * The Creator Interface give the Pool the ability to Create, Destroy and
252          * Validate the Objects it is maintaining. Thus, it is a specially written
253          * Implementation for each type.
254          * 
255          * @author Jonathan
256          * 
257          * @param <T>
258          */
259         public interface Creator<T> {
260                 public T create() throws CadiException;
261
262                 public void destroy(T t);
263
264                 public boolean isValid(T t);
265
266                 public void reuse(T t);
267         }
268
269         public interface Log {
270                 public void log(Object ... o);
271                 
272                 public final static Log NULL = new Log() {
273                         @Override
274                         public void log(Object ... o) {
275                         }
276                 };
277         }
278         /**
279          * The "Pooled<T>" class is the transient class that wraps the actual Object
280          * T for API use/ It gives the ability to return ("done()", or "toss()") the
281          * Object to the Pool when processing is finished.
282          * 
283          * For Safety, i.e. to avoid memory leaks and invalid Object States, there
284          * is a "finalize" method. It is strictly for when coder forgets to return
285          * the object, or perhaps hasn't covered the case during Exceptions or
286          * Runtime Exceptions with finally (preferred). This should not be
287          * considered normal procedure, as finalize() is called at an undetermined
288          * time during garbage collection, and is thus rather useless for a Pool.
289          * However, we don't want Coding Mistakes to put the whole program in an
290          * invalid state, so if something happened such that "done()" or "toss()"
291          * were not called, the resource is still cleaned up as well as possible.
292          * 
293          * @author Jonathan
294          * 
295          * @param <T>
296          */
297         public static class Pooled<T> {
298                 public final T content;
299                 private Pool<T> pool;
300
301                 /**
302                  * Create the Wrapping Object Pooled<T>.
303                  * 
304                  * @param t
305                  * @param pool
306                  * @param logTarget
307                  */
308                 public Pooled(T t, Pool<T> pool) {
309                         content = t;
310                         this.pool = pool;
311
312                 }
313
314                 /**
315                  * This is the key API for the Pool, as calling "done()" offers this
316                  * object back to the Pool for reuse.
317                  * 
318                  * Do not use the Pooled<T> object again after calling "done()".
319                  */
320                 public void done() {
321                         if (pool != null) {
322                                 pool.offer(this);
323                         }
324                 }
325
326                 /**
327                  * The user of the Object may discover that the Object t is no longer in
328                  * a valid state. Don't put Garbage back in the Refrigerator... Toss it,
329                  * if it's no longer valid.
330                  * 
331                  * toss() is also used for draining the Pool, etc.
332                  * 
333                  * toss() will attempt to destroy the Object by using the Creator
334                  * Interface.
335                  * 
336                  */
337                 public void toss() {
338                         if (pool != null) {
339                                 pool.creator.destroy(content);
340                         }
341                         // Don't allow finalize to put it back in.
342                         pool = null;
343                 }
344
345                 /**
346                  * Just in case someone neglected to offer back object... Do not rely on
347                  * this, as there is no specific time when finalize is called, which
348                  * rather defeats the purpose of a Pool.
349                  */
350                 @Override
351                 protected void finalize() throws Throwable {
352                         if (pool != null) {
353                                 done();
354                                 pool = null;
355                         }
356                 }
357         }
358
359         /**
360          * Get the maximum number of spare objects allowed at any moment
361          * 
362          * @return
363          */
364         public int getMaxRange() {
365                 return max_range;
366         }
367
368         /**
369          * Set a Max Range for numbers of spare objects waiting to be used.
370          * 
371          * No negative numbers are allowed
372          * 
373          * @return
374          */
375         public void setMaxRange(int max_range) {
376                 // Do not allow negative numbers
377                 this.max_range = Math.max(0, max_range);
378         }
379
380 }