Collection syntax change because of Sonar
[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