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