2 * ============LICENSE_START====================================================
\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
11 * http://www.apache.org/licenses/LICENSE-2.0
\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
28 package org.onap.aaf.misc.env.util;
\r
30 import java.util.LinkedList;
\r
32 import org.onap.aaf.misc.env.APIException;
\r
33 import org.onap.aaf.misc.env.LogTarget;
\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
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
43 * You can Prime the instances to avoid huge startup costs
\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
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
62 public class Pool<T> {
\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
67 private static final int MAX_RANGE = 6; // safety
\r
70 * only Simple List needed.
\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
75 private LinkedList<Pooled<T>> list;
\r
78 * keep track of how many elements exist, to avoid asking list.
\r
83 * Spares are those Object that are primed and ready to go.
\r
88 * Actual MAX number of spares allowed to hang around. Can be set to
\r
89 * something besides the default MAX_RANGE.
\r
91 private int max_range = MAX_RANGE;
\r
94 * The Creator for this particular pool. It must work for type T.
\r
96 private Creator<T> creator;
\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
104 public Pool(Creator<T> creator) {
\r
105 count = spares = 0;
\r
106 this.creator = creator;
\r
107 list = new LinkedList<>();
\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
116 * @throws APIException
\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
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
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
142 count = spares = 0;
\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
152 * This one uses a Null LogTarget
\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
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
163 * @throws APIException
\r
165 public Pooled<T> get() throws APIException {
\r
167 synchronized (list) {
\r
168 if (list.isEmpty()) {
\r
171 pt = list.removeLast();
\r
173 creator.reuse(pt.content);
\r
177 if (spares < max_range)
\r
179 pt = new Pooled<T>(creator.create(), this, LogTarget.NULL);
\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
192 * If you don't have access to a LogTarget from Env, use LogTarget.NULL
\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
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
203 * @throws APIException
\r
205 public Pooled<T> get(LogTarget lt) throws APIException {
\r
207 synchronized (list) {
\r
208 if (list.isEmpty()) {
\r
211 pt = list.remove();
\r
213 creator.reuse(pt.content);
\r
217 if (spares < max_range)
\r
219 pt = new Pooled<T>(creator.create(), this, lt);
\r
220 lt.log("Pool created ", creator.toString());
\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
236 public boolean validate() {
\r
238 synchronized (list) {
\r
239 for (Pooled<T> t : list) {
\r
240 if (!creator.isValid(t.content)) {
\r
251 * This is an internal method, used only by the Internal Pooled<T> class.
\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
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
268 lt.log("Pool recovered ", creator.toString());
\r
270 lt.log("Pool destroyed ", creator.toString());
\r
271 creator.destroy(used.content);
\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
285 public interface Creator<T> {
\r
286 public T create() throws APIException;
\r
288 public void destroy(T t);
\r
290 public boolean isValid(T t);
\r
292 public void reuse(T t);
\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
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
314 public static class Pooled<T> {
\r
315 public final T content;
\r
316 private Pool<T> pool;
\r
317 protected LogTarget logTarget;
\r
320 * Create the Wrapping Object Pooled<T>.
\r
326 public Pooled(T t, Pool<T> pool, LogTarget logTarget) {
\r
329 this.logTarget = logTarget;
\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
336 * Do not use the Pooled<T> object again after calling "done()".
\r
338 public void done() {
\r
339 if (pool != null) {
\r
340 pool.offer(logTarget, this);
\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
349 * toss() is also used for draining the Pool, etc.
\r
351 * toss() will attempt to destroy the Object by using the Creator
\r
355 public void toss() {
\r
356 if (pool != null) {
\r
357 pool.creator.destroy(content);
\r
359 // Don't allow finalize to put it back in.
\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
369 protected void finalize() throws Throwable {
\r
370 if (pool != null) {
\r
378 * Get the maximum number of spare objects allowed at any moment
\r
382 public int getMaxRange() {
\r
387 * Set a Max Range for numbers of spare objects waiting to be used.
\r
389 * No negative numbers are allowed
\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