AT&T 2.0.19 Code drop, stage 1
[aaf/authz.git] / misc / env / src / main / java / org / onap / aaf / misc / env / 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.misc.env.util;
29
30 import java.util.LinkedList;
31
32 import org.onap.aaf.misc.env.APIException;
33 import org.onap.aaf.misc.env.LogTarget;
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  * 
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         /**
99          * Create a new Pool, given the implementation of Creator<T>, which must be
100          * able to create/destroy T objects at will.
101          * 
102          * @param creator
103          */
104         public Pool(Creator<T> creator) {
105                 count = spares = 0;
106                 this.creator = creator;
107                 list = new LinkedList<Pooled<T>>();
108         }
109
110         /**
111          * Preallocate a certain number of T Objects. Useful for services so that
112          * the first transactions don't get hit with all the Object creation costs
113          * 
114          * @param lt
115          * @param prime
116          * @throws APIException
117          */
118         public void prime(LogTarget lt, int prime) throws APIException {
119                 for (int i = 0; i < prime; ++i) {
120                         Pooled<T> pt = new Pooled<T>(creator.create(), this, lt);
121                         synchronized (list) {
122                                 list.addFirst(pt);
123                                 ++count;
124                         }
125                 }
126
127         }
128
129         /**
130          * Destroy and remove all remaining objects. This is valuable for closing
131          * down all Allocated objects cleanly for exiting. It is also a good method
132          * for removing objects when, for instance, all Objects are invalid because
133          * of broken connections, etc.
134          */
135         public void drain() {
136                 synchronized (list) {
137                         for (int i = 0; i < list.size(); ++i) {
138                                 Pooled<T> pt = list.remove();
139                                 creator.destroy(pt.content);
140                                 pt.logTarget.log("Pool drained ", creator.toString());
141                         }
142                         count = spares = 0;
143                 }
144
145         }
146
147         /**
148          * This is the essential function for Pool. Get an Object "T" inside a
149          * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
150          * create and pass back.
151          * 
152          * This one uses a Null LogTarget
153          * 
154          * IMPORTANT: When the use of this object is done (and the object is still
155          * in a valid state), then "done()" should be called immediately to allow
156          * the object to be reused. That is the point of the Pool...
157          * 
158          * If the Object is in an invalid state, then "toss()" should be used so the
159          * Pool doesn't pass on invalid objects to others.
160          * 
161          * @param lt
162          * @return
163          * @throws APIException
164          */
165         public Pooled<T> get() throws APIException {
166                 Pooled<T> pt;
167                 synchronized (list) {
168                         if (list.isEmpty()) {
169                                 pt = null;
170                         } else {
171                                 pt = list.removeLast();
172                                 --count;
173                                 creator.reuse(pt.content);
174                         }
175                 }
176                 if (pt == null) {
177                         if (spares < max_range)
178                                 ++spares;
179                         pt = new Pooled<T>(creator.create(), this, LogTarget.NULL);
180                 } else {
181                         if (spares > 1)
182                                 --spares;
183                 }
184                 return pt;
185         }
186
187         /**
188          * This is the essential function for Pool. Get an Object "T" inside a
189          * "Pooled<T>" object. If there is a spare Object, then use it. If not, then
190          * create and pass back.
191          * 
192          * If you don't have access to a LogTarget from Env, use LogTarget.NULL
193          * 
194          * IMPORTANT: When the use of this object is done (and the object is still
195          * in a valid state), then "done()" should be called immediately to allow
196          * the object to be reused. That is the point of the Pool...
197          * 
198          * If the Object is in an invalid state, then "toss()" should be used so the
199          * Pool doesn't pass on invalid objects to others.
200          * 
201          * @param lt
202          * @return
203          * @throws APIException
204          */
205         public Pooled<T> get(LogTarget lt) throws APIException {
206                 Pooled<T> pt;
207                 synchronized (list) {
208                         if (list.isEmpty()) {
209                                 pt = null;
210                         } else {
211                                 pt = list.remove();
212                                 --count;
213                                 creator.reuse(pt.content);
214                         }
215                 }
216                 if (pt == null) {
217                         if (spares < max_range)
218                                 ++spares;
219                         pt = new Pooled<T>(creator.create(), this, lt);
220                         lt.log("Pool created ", creator.toString());
221                 } else {
222                         if (spares > 1)
223                                 --spares;
224                 }
225                 return pt;
226         }
227
228         /**
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.
233          * 
234          * @return
235          */
236         public boolean validate() {
237                 boolean rv = true;
238                 synchronized (list) {
239                         for (Pooled<T> t : list) {
240                                 if (!creator.isValid(t.content)) {
241                                         rv = false;
242                                         t.toss();
243                                         list.remove(t);
244                                 }
245                         }
246                 }
247                 return rv;
248         }
249
250         /**
251          * This is an internal method, used only by the Internal Pooled<T> class.
252          * 
253          * The Pooled<T> class "offers" it's Object back after use. It is an
254          * "offer", because Pool will simply destroy and remove the object if it has
255          * more than enough spares.
256          * 
257          * @param lt
258          * @param used
259          * @return
260          */
261         // Used only by Pooled<T>
262         private boolean offer(LogTarget lt, Pooled<T> used) {
263                 if (count < spares) {
264                         synchronized (list) {
265                                 list.addFirst(used);
266                                 ++count;
267                         }
268                         lt.log("Pool recovered ", creator.toString());
269                 } else {
270                         lt.log("Pool destroyed ", creator.toString());
271                         creator.destroy(used.content);
272                 }
273                 return false;
274         }
275
276         /**
277          * The Creator Interface give the Pool the ability to Create, Destroy and
278          * Validate the Objects it is maintaining. Thus, it is a specially written
279          * Implementation for each type.
280          * 
281          * @author Jonathan
282          * 
283          * @param <T>
284          */
285         public interface Creator<T> {
286                 public T create() throws APIException;
287
288                 public void destroy(T t);
289
290                 public boolean isValid(T t);
291
292                 public void reuse(T t);
293         }
294
295         /**
296          * The "Pooled<T>" class is the transient class that wraps the actual Object
297          * T for API use/ It gives the ability to return ("done()", or "toss()") the
298          * Object to the Pool when processing is finished.
299          * 
300          * For Safety, i.e. to avoid memory leaks and invalid Object States, there
301          * is a "finalize" method. It is strictly for when coder forgets to return
302          * the object, or perhaps hasn't covered the case during Exceptions or
303          * Runtime Exceptions with finally (preferred). This should not be
304          * considered normal procedure, as finalize() is called at an undetermined
305          * time during garbage collection, and is thus rather useless for a Pool.
306          * However, we don't want Coding Mistakes to put the whole program in an
307          * invalid state, so if something happened such that "done()" or "toss()"
308          * were not called, the resource is still cleaned up as well as possible.
309          * 
310          * @author Jonathan
311          * 
312          * @param <T>
313          */
314         public static class Pooled<T> {
315                 public final T content;
316                 private Pool<T> pool;
317                 protected LogTarget logTarget;
318
319                 /**
320                  * Create the Wrapping Object Pooled<T>.
321                  * 
322                  * @param t
323                  * @param pool
324                  * @param logTarget
325                  */
326                 public Pooled(T t, Pool<T> pool, LogTarget logTarget) {
327                         content = t;
328                         this.pool = pool;
329                         this.logTarget = logTarget;
330                 }
331
332                 /**
333                  * This is the key API for the Pool, as calling "done()" offers this
334                  * object back to the Pool for reuse.
335                  * 
336                  * Do not use the Pooled<T> object again after calling "done()".
337                  */
338                 public void done() {
339                         if (pool != null) {
340                                 pool.offer(logTarget, this);
341                         }
342                 }
343
344                 /**
345                  * The user of the Object may discover that the Object t is no longer in
346                  * a valid state. Don't put Garbage back in the Refrigerator... Toss it,
347                  * if it's no longer valid.
348                  * 
349                  * toss() is also used for draining the Pool, etc.
350                  * 
351                  * toss() will attempt to destroy the Object by using the Creator
352                  * Interface.
353                  * 
354                  */
355                 public void toss() {
356                         if (pool != null) {
357                                 pool.creator.destroy(content);
358                         }
359                         // Don't allow finalize to put it back in.
360                         pool = null;
361                 }
362
363                 /**
364                  * Just in case someone neglected to offer back object... Do not rely on
365                  * this, as there is no specific time when finalize is called, which
366                  * rather defeats the purpose of a Pool.
367                  */
368                 @Override
369                 protected void finalize() throws Throwable {
370                         if (pool != null) {
371                                 done();
372                                 pool = null;
373                         }
374                 }
375         }
376
377         /**
378          * Get the maximum number of spare objects allowed at any moment
379          * 
380          * @return
381          */
382         public int getMaxRange() {
383                 return max_range;
384         }
385
386         /**
387          * Set a Max Range for numbers of spare objects waiting to be used.
388          * 
389          * No negative numbers are allowed
390          * 
391          * @return
392          */
393         public void setMaxRange(int max_range) {
394                 // Do not allow negative numbers
395                 this.max_range = Math.max(0, max_range);
396         }
397
398 }