KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > easybeans > pool > JPool


1 /**
2  * EasyBeans
3  * Copyright (C) 2006 Bull S.A.S.
4  * Contact: easybeans@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: JPool.java 1133 2006-10-04 14:30:41Z benoitf $
23  * --------------------------------------------------------------------------
24  */

25
26 package org.objectweb.easybeans.pool;
27
28 import java.util.ArrayList JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import org.objectweb.easybeans.api.pool.Pool;
34 import org.objectweb.easybeans.api.pool.PoolAttributes;
35 import org.objectweb.easybeans.api.pool.PoolException;
36 import org.objectweb.easybeans.log.JLog;
37 import org.objectweb.easybeans.log.JLogFactory;
38
39
40 /**
41  * Abstract pool.<br>
42  * Need to be extended to set-up the correct generic types used for BeanType and
43  * Hint.<br>
44  * @param <InstanceType> the type of the object that are managed by the pool
45  * (could be EasyBeansSLSB, etc.)
46  * @param <Clue> a clue to retrieve a specific instance in the pool
47  * @author Florent Benoit
48  */

49 public class JPool<InstanceType, Clue> implements Pool<InstanceType, Clue>, PoolAttributes {
50
51     /**
52      * Default timeout (10s) in ms.
53      */

54     private static final long DEFAULT_TIMEOUT = 10000;
55
56     /**
57      * Default maximum of waiters (1000).
58      */

59     private static final int DEFAULT_MAX_WAITERS = 1000;
60
61     /**
62      * High Value for no limit for the connection pool.
63      */

64     private static final int NO_LIMIT = -1;
65
66     /**
67      * Logger used.
68      */

69     private JLog logger = JLogFactory.getLog(JPool.class);
70
71     /**
72      * Factory used for delegate creating, matching, removing actions.
73      */

74     private PoolFactory<InstanceType, Clue> poolFactory = null;
75
76     /**
77      * List of available objects in the pool.
78      */

79     private List JavaDoc<InstanceType> availableList = null;
80
81     /**
82      * List of objects which are currently busy and not available from the pool.
83      */

84     private List JavaDoc<InstanceType> busyList = null;
85
86     /**
87      * Information on entries managed in the pool.
88      */

89     private Map JavaDoc<InstanceType, PoolEntryStatistics> infoMap = null;
90
91     /**
92      * Minimum size of the pool.
93      */

94     private int minSize = 0;
95
96     /**
97      * Maximum size of the pool.
98      */

99     private int maxSize = NO_LIMIT;
100
101     /**
102      * Initial size of the pool.
103      */

104     private int initSize = 0;
105
106     /**
107      * Maximum size of the pool is strict.
108      */

109     private boolean strict = true;
110
111     /**
112      * Max nb of waiters allowed to wait for an instance.
113      */

114     private int maxWaiters = DEFAULT_MAX_WAITERS;
115
116     /**
117      * Max nb of milliseconds to wait for an object when the pool is full.
118      */

119     private long waiterTimeout = DEFAULT_TIMEOUT;
120
121     /**
122      * Current number of waiters.
123      */

124     private int currentWaiters = 0;
125
126     /**
127      * Maximum number of waiters during current period.
128      */

129     private int highMaxWaiters = 0;
130
131     /**
132      * Total nb of waiters since pool creation.
133      */

134     private int totalWaiters = 0;
135
136     /**
137      * total waiting time in milliseconds.
138      */

139     private long totalWaitingTime = 0;
140
141     /**
142      * Maximum waiting time during current period.
143      */

144     private long highWaitingTime = 0;
145
146     /**
147      * Total number of instances since the pool creation.
148      */

149     private int servedInstance = 0;
150
151     /**
152      * Total nb of instance not served due to timeout.
153      */

154     private int rejectedTimeout = 0;
155
156     /**
157      * Total nb of instance not served due to an overflow of waiters.
158      */

159     private int rejectedFull = 0;
160
161     /**
162      * Allow to build instance with the same clue if the pool is not at the max size.
163      * For example, for stateful this is not allowed.
164      */

165     private boolean allowSharedInstance = true;
166
167     /**
168      * Builds a new pool.
169      * @param poolFactory factory used for delegating create, remove, etc.
170      */

171     public JPool(final PoolFactory<InstanceType, Clue> poolFactory) {
172
173         // factory use to delegate some operations
174
this.poolFactory = poolFactory;
175
176         // available entries
177
this.availableList = new ArrayList JavaDoc<InstanceType>();
178
179         // entries send to client, which are busy
180
this.busyList = new ArrayList JavaDoc<InstanceType>();
181
182         // statistics on entries
183
infoMap = new HashMap JavaDoc<InstanceType, PoolEntryStatistics>();
184     }
185
186     /**
187      * Gets an object from the pool.
188      * @return an instance of an object with type Type.
189      * @throws PoolException if instance cannot be returned.
190      */

191     public InstanceType get() throws PoolException {
192         // delegates to getter method with a parameter
193
return this.get(null);
194     }
195
196     /**
197      * Gets an object by using a specific hint.
198      * @param clue attribute used to retrieve a given instance
199      * @return a specific instance of the resource.
200      * @throws PoolException if instance cannot be returned.
201      */

202     public synchronized InstanceType get(final Clue clue) throws PoolException {
203         InstanceType instance = null;
204
205         // time to wait when pool is full
206
long timeToWait = waiterTimeout;
207
208         // Try to find an instance
209
// Enter in the big loop :)
210
while (instance == null) {
211
212             // instances are available
213
if (!availableList.isEmpty()) {
214                 logger.debug("Instances are available");
215
216                 int indexToExtract = -1;
217
218                 // No clue, get first instance available
219
if (clue == null) {
220                     logger.debug("No clue, return the first available entry.");
221                     indexToExtract = 0;
222                 } else {
223                     logger.debug("Clue is used, try to get a matching entry.");
224                     // need to find a matching instance.
225
// use this kind of loop to call remove() method
226
// with an index instead of an element.
227
for (int i = 0; i < availableList.size(); i++) {
228                         InstanceType tmpInstance = availableList.get(i);
229                         if (poolFactory.isMatching(tmpInstance, clue)) {
230                             logger.debug("Found a matching instance, instance = {0}", tmpInstance);
231                             indexToExtract = i;
232                             break;
233                         }
234                     }
235                     // Note : instance could not be found
236
}
237                 // An instance is available ?
238
if (indexToExtract != -1) {
239                     logger
240                             .debug("Remove from available instance, item with index {0}", Integer
241                                     .valueOf(indexToExtract));
242                     instance = availableList.remove(indexToExtract);
243                     busyList.add(instance);
244                 }
245             }
246
247             /**
248              * If here :
249              * <ul>
250              * <li> - No objects available in the pool</li>
251              * <li>or - No matching instance in the pool</li>
252              * </ul>
253              */

254             if (instance == null) {
255                 // current size of managed entries (available and busy)
256
int curSize = availableList.size() + busyList.size();
257
258                 boolean sharedInstance = true;
259                 if (!allowSharedInstance) {
260                     // Search if an instance is currently used
261
for (int i = 0; i < busyList.size(); i++) {
262                         InstanceType tmpInstance = busyList.get(i);
263                         if (poolFactory.isMatching(tmpInstance, clue)) {
264                             logger.debug("Found a matching instance, instance = {0}", tmpInstance);
265                             sharedInstance = false;
266                             break;
267                         }
268                     }
269                 }
270
271
272                 // limit not reached (or pool without limit)
273
if (sharedInstance && (maxSize == NO_LIMIT || curSize < maxSize)) {
274                     logger.debug("Maximum size not reached, can create a new entry with clue = {0}", clue);
275                     instance = poolFactory.create(clue);
276                     busyList.add(instance);
277                 } else if (sharedInstance && availableList.size() > 0) {
278                     // limit reached but pool entries still available
279
logger.debug("limit reached but entries available in the pool. Replace one by a new one.");
280
281                     // get first entry found (that will be replaced)
282
InstanceType previousInstance = availableList.get(0);
283
284                     // remove it from the delegating factory.
285
// Factory is notified that the instance is being removed.
286
poolFactory.remove(previousInstance);
287
288                     // now, remove the entry from pool
289
availableList.remove(previousInstance);
290                     // and from statistics
291
infoMap.remove(previousInstance);
292
293                     // As previous instance has been removed, new one can be
294
// created
295
instance = poolFactory.create(clue);
296                     // this instance is now busy.
297
busyList.add(instance);
298                 } else {
299                     logger.debug("limit reached and no available instances in the pool");
300                     boolean timeoutWokenUp = true;
301                     long startSleeping = 0;
302
303                     // Need to wait
304
if (timeToWait > 0) {
305                         if (currentWaiters < maxWaiters) {
306                             currentWaiters++;
307                             // Store the maximum concurrent waiters
308
if (highMaxWaiters < currentWaiters) {
309                                 highMaxWaiters = currentWaiters;
310                             }
311                             if (startSleeping == 0) {
312                                 startSleeping = System.currentTimeMillis();
313                                 logger.debug("Waiting an instance");
314                             }
315                             try {
316                                 wait(timeToWait);
317                             } catch (InterruptedException JavaDoc ie) {
318                                 logger.warn("Waiter has been interrupted", ie);
319                             } finally {
320                                 currentWaiters--;
321                             }
322                             long sleepTime = System.currentTimeMillis() - startSleeping;
323                             // check if waiter has been woken up
324
timeoutWokenUp = (waiterTimeout - sleepTime <= 0);
325
326                             // increment counters
327
totalWaiters++;
328                             totalWaitingTime += sleepTime;
329                             if (highWaitingTime < sleepTime) {
330                                 highWaitingTime = sleepTime;
331                             }
332                             // continue if we were only notified. (no timeout)
333
if (!timeoutWokenUp) {
334                                 continue;
335                             }
336                         }
337                     }
338
339                     // timeout expired and no entry is available
340
if (timeoutWokenUp && availableList.isEmpty() && busyList.size() >= maxSize) {
341                         if (startSleeping > 0) {
342                             rejectedTimeout++;
343                             logger.warn("Cannot create an instance due to a timeout");
344                         } else {
345                             rejectedFull++;
346                             logger.warn("Cannot create an instance");
347                         }
348                         throw new PoolException("No more instances available");
349                     }
350                 }
351             }
352         }
353
354         // TODO: delegate to factory the entry
355
PoolEntryStatistics poolEntryStat = new PoolEntryStatistics();
356
357         infoMap.put(instance, poolEntryStat);
358
359         // printLists();
360

361         // recomputeBusy();
362

363         servedInstance++;
364         return instance;
365     }
366
367     /**
368      * Puts back the instance in the pool so it can be reused.
369      * @param instance which will be put back in the pool.
370      * @throws PoolException if instance is not released.
371      */

372     public synchronized void release(final InstanceType instance) throws PoolException {
373
374         if (!busyList.contains(instance)) {
375             logger.debug("Attempt to release inactive resource {0}. Probably discarded.", instance);
376             return;
377         }
378         busyList.remove(instance);
379         logger.debug("Put back into the pool the instance {0}", instance);
380
381         availableList.add(instance);
382         infoMap.remove(instance);
383
384         // Notify 1 thread waiting for that an instance is available.
385
if (currentWaiters > 0) {
386             notify();
387         }
388     }
389
390     /**
391      * Discard the instance which is in the pool.
392      * @param instance which will be discarded.
393      * @throws PoolException if instance is not discarded
394      */

395     public synchronized void discard(final InstanceType instance) throws PoolException {
396         if (!busyList.contains(instance)) {
397             throw new PoolException("Attempt to discard an inactive resource(" + instance + ")");
398         }
399
400         // Notify the factory that it's going to be removed
401
poolFactory.remove(instance);
402
403         // Remove instance from the busy & info list
404
busyList.remove(instance);
405         infoMap.remove(instance);
406
407
408         // Notify 1 thread waiting that an instance has been freed
409
if (currentWaiters > 0) {
410             notify();
411         }
412
413     }
414
415     /**
416      * Allow to share instances (shouldn't be use in stateful case as one
417      * stateful ID is linked to one client. No Stateful with same ID are
418      * authorized).
419      * @param allowSharedInstance true if it is allowed, else false.
420      */

421     public void setAllowSharedInstance(final boolean allowSharedInstance) {
422         this.allowSharedInstance = allowSharedInstance;
423     }
424
425     /**
426      * Return true if many instances of the same object can be created (when pool is not full).
427      * @return true if this is allowed.
428      */

429     public boolean isAllowSharedInstance() {
430         return allowSharedInstance;
431     }
432
433
434     /**
435      * Start the pool.<br>
436      * It could create initial instances if specified.
437      * @throws PoolException if initialization fails
438      */

439     public void start() throws PoolException {
440
441     }
442
443     /**
444      * Stop this pool.
445      * @throws PoolException if destroy fails
446      */

447     public void stop() throws PoolException {
448
449     }
450
451 }
452
Popular Tags