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