KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > perseus > pool > lib > ArrayListPool


1 /**
2  * Copyright (C) 2003 France Telecom R&D
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package org.objectweb.perseus.pool.lib;
19
20 import org.objectweb.perseus.pool.api.Pool;
21 import org.objectweb.perseus.pool.api.PoolAttributes;
22 import org.objectweb.perseus.pool.api.PoolMatchFactory;
23 import org.objectweb.perseus.pool.api.PoolException;
24 import org.objectweb.perseus.dependency.api.DependencyGraph;
25 import org.objectweb.perseus.dependency.api.DeadLockException;
26 import org.objectweb.fractal.api.control.BindingController;
27 import org.objectweb.util.monolog.api.Logger;
28 import org.objectweb.util.monolog.api.BasicLevel;
29
30 import java.util.Collection JavaDoc;
31 import java.util.Collections JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Calendar JavaDoc;
36
37 /**
38  * The class <b>LArrayPool</b> implements a Pool as an array of PoolResource,
39  * managing free/active resources through two ArrayList objects. An unlimited
40  * size and a timeout features are supported. This implementation is thread
41  * safe.
42  * This implementation is able to manage an InactiveTTL for the free
43  * pooled resources, but by default the resource has not a TTL (negative value).
44  * This implementation is able to manage a TTL for each
45  * pooled resources, but by default the resource has not a TTL (negative value).
46  *
47  * @author S.Chassande-Barrioz
48  */

49 public class ArrayListPool
50         implements Pool, PoolAttributes, BindingController {
51
52     public final static String JavaDoc POOL_MATCH_FACTORY_BINDING = "pool-match-factory";
53     public final static String JavaDoc DEPENDENCY_GRAPH_BINDING = "dependency-graph";
54
55     /**
56      * The int value used for the timeout or the max size
57      */

58     public final static int UNLIMITED = -1;
59
60     /**
61      * The default minimum size of the pool: 0
62      */

63     public final static int DEFAULT_MIN_SIZE = 0;
64
65     /**
66      * The default maximum size of the pool: UNLIMITED
67      */

68     public final static int DEFAULT_MAX_SIZE = UNLIMITED;
69
70     /**
71      * The default time out for a request: 100ms
72      */

73     public final static int DEFAULT_TIME_OUT = 300;
74
75     private PoolMatchFactory matchFactory = null;
76     private long freettl = 0;
77     private long ttl = 0;
78     private long timeOut = DEFAULT_TIME_OUT;
79     private int minSize = DEFAULT_MIN_SIZE;
80     private int maxSize = DEFAULT_MAX_SIZE;
81     private List JavaDoc free = new ArrayList JavaDoc();
82     private List JavaDoc timesOfFree = new ArrayList JavaDoc();
83     private HashMap JavaDoc res2ttl = new HashMap JavaDoc();
84     private List JavaDoc used = new ArrayList JavaDoc();
85     private List JavaDoc users = new ArrayList JavaDoc();
86     private boolean started = false;
87     private Logger logger = null;
88     private DependencyGraph dg = null;
89
90
91     /**
92      * destroy the resource that the ttl or freettl is expired
93      */

94     private void cleanExpiredResource() {
95         long time = 0;
96         if (freettl > 0 || ttl > 0) {
97             time = Calendar.getInstance().getTimeInMillis();
98             for(int i=0; i<free.size();) {
99                 boolean remove = false;//indicates if the resource has to be removed
100
Object JavaDoc resource = free.get(i);
101                 if (freettl > 0) {
102                     Long JavaDoc l = (Long JavaDoc) timesOfFree.get(i);
103                     if (l == null) {
104                         throw new IllegalThreadStateException JavaDoc("The resource '" + resource + "' has no inactivettl !");
105                     }
106                     remove = (time - l.longValue()) > freettl;
107                     if (remove && logger != null && logger.isLoggable(BasicLevel.INFO)) {
108                         logger.log(BasicLevel.INFO, "Resource is being destroyed (too long time unused): '" + resource + "'.");
109                     }
110                 }
111                 if (!remove && ttl > 0) {
112                     //inactivettll does not expire ==> check the ttl
113
Long JavaDoc l = (Long JavaDoc) res2ttl.get(resource);
114                     if (l == null) {
115                         throw new IllegalThreadStateException JavaDoc("The resource '" + resource + "' has no ttl !");
116                     }
117                     remove = (time - l.longValue()) > ttl;
118                     if (remove && logger != null && logger.isLoggable(BasicLevel.INFO)) {
119                         logger.log(BasicLevel.INFO, "Resource is being destroyed (too old): '" + resource + "'.");
120                     }
121                 }
122                 if (remove) {
123                     //one of both ttl has expired ==> remove the resource
124
free.remove(i);
125                     if (freettl > 0) {
126                         timesOfFree.remove(i);
127                     }
128                     if (ttl>0) {
129                         res2ttl.remove(resource);
130                     }
131                     matchFactory.destroyResource(resource);
132                 } else {
133                     i++;
134                 }
135             }
136         }
137     }
138
139     private void updateToMinsize(Object JavaDoc hints) throws PoolException {
140         cleanExpiredResource();
141         int delta = minSize - free.size() - used.size();
142         if (matchFactory != null && delta>0) {
143             for(int i=0; i<delta; i++) {
144                 Object JavaDoc resource = createResource(hints);
145                 free.add(resource);
146                 if (freettl > 0) {
147                     timesOfFree.add(new Long JavaDoc(Calendar.getInstance().getTimeInMillis()));
148                 }
149
150             }
151         }
152     }
153
154     private Object JavaDoc createResource(Object JavaDoc hints) throws PoolException {
155         Object JavaDoc resource = matchFactory.createResource(hints);
156         if (resource == null) {
157             if (started) {
158                 throw new PoolException("The pool resource factory does not create a new resource with the hints: " + hints);
159             } else if (logger != null) {
160                 logger.log(BasicLevel.WARN, "The pool resource factory does not create a new resource with the hints: " + hints);
161             }
162         } else {
163             long t = 0;
164             if (ttl > 0) {
165                 t = Calendar.getInstance().getTimeInMillis();
166                 res2ttl.put(resource, new Long JavaDoc(t));
167             }
168             if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
169                 logger.log(BasicLevel.INFO, "Resource created"
170                         + (t == 0 ? "" : " (born:" + t + ")")
171                         + ": '" + resource + "'.");
172             }
173         }
174         return resource;
175     }
176     
177     private void updateToMaxsize() {
178         cleanExpiredResource();
179         if (maxSize != UNLIMITED) {
180             int delta = free.size() + used.size() - maxSize;
181             //Remove the free pool resource if availlable
182
if (delta > 0) {
183                 for (int i = 0; i < delta && !free.isEmpty(); i++) {
184                     int j = free.size() - 1;
185                     Object JavaDoc resource = free.remove(j);
186                     if (freettl > 0) {
187                         timesOfFree.remove(j);
188                     }
189                     if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
190                         logger.log(BasicLevel.INFO, "Resource destroyed: '" + resource + "'.");
191                     }
192                     matchFactory.destroyResource(resource);
193                 }
194             }
195         }
196     }
197
198
199     // IMPLEMENTATION OF METHODS FROM THE BindingController INTERFACE //
200
//----------------------------------------------------------------//
201

202     public String JavaDoc[] listFc() {
203         return new String JavaDoc[] {
204             POOL_MATCH_FACTORY_BINDING, DEPENDENCY_GRAPH_BINDING };
205     }
206
207     public Object JavaDoc lookupFc(String JavaDoc clientItfName) {
208         if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) {
209             return matchFactory;
210         } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) {
211             return dg;
212         } else {
213             return null;
214         }
215     }
216
217     public void bindFc(String JavaDoc clientItfName, Object JavaDoc serverItf) {
218         if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) {
219             matchFactory = (PoolMatchFactory) serverItf;
220             try {
221                 updateToMinsize(null);
222             } catch (Exception JavaDoc e) {
223             }
224         } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) {
225             dg = (DependencyGraph) serverItf;
226         } else if ("logger".equals(clientItfName)) {
227             logger = (Logger) serverItf;
228         }
229     }
230
231     public void unbindFc(String JavaDoc clientItfName) {
232         if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) {
233             matchFactory = null;
234         } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) {
235             dg = null;
236         }
237     }
238
239
240     // IMPLEMENTATION OF METHODS FROM THE Pool INTERFACE //
241
//---------------------------------------------------//
242

243     /**
244      * <b>getResource</b> is used to allocate a PoolResource from the Pool.
245      * Some hints are passed in order to specialise the matching or creation
246      * of PoolResource.
247      * @param hints Some properties to specialise the matching or the creation
248      * of PoolResource.
249      * @return The PoolResource allocated from the Pool.
250      */

251     public synchronized Object JavaDoc getResource(Object JavaDoc hints) throws PoolException {
252         try {
253             return getResource(hints, null);
254         } catch (DeadLockException e) {
255             //not possible because no user is specified
256
throw new PoolException(e);
257         }
258     }
259     public synchronized Object JavaDoc getResource(Object JavaDoc hints, Object JavaDoc user)
260             throws PoolException, DeadLockException {
261         if (!started) {
262             started = true;
263             updateToMaxsize();
264         }
265         //System.out.println("getResource: max=" + (maxSize == UNLIMITED ? "U" : "" + maxSize) + ", free=" + free.size() + ", used=" + used.size() +")");
266
if (maxSize != UNLIMITED && used.size() >= maxSize) {
267             if (timeOut != 0) {
268                 int vertexIdx = 0;
269                 try {
270                     //Add dependencies in order to detect dead lock
271
if (user != null && dg != null) {
272                         int s = users.size();
273                         for(vertexIdx=0; vertexIdx<s; vertexIdx++) {
274                             Object JavaDoc dst = users.get(vertexIdx);
275                             if (dst != null) {
276                                 if (!dg.addVertex(user, dst)) {
277                                     throw new DeadLockException("Impossible to allocate a resource: no resource is availlable and a dead lock occurs if the current thread wait a resource");
278                                 }
279                             }
280                         }
281                     }
282                     //wait a free resource or a max time
283
if (timeOut > 0) {
284                         long to = timeOut;
285                         while(maxSize != UNLIMITED && used.size() >= maxSize && to > 0) {
286                             long exectime = System.currentTimeMillis();
287                             wait(timeOut);
288                             exectime = System.currentTimeMillis() - exectime;
289                             to -= exectime;
290                         }
291                     } else {
292                         while (maxSize != UNLIMITED && used.size() >= maxSize) {
293                             wait();
294                         }
295                     }
296                 } catch (InterruptedException JavaDoc e) {
297                     throw new PoolException("Pool wait has been interrupted: ", e);
298                 } finally {
299                     if (user != null && dg != null) {
300                         for(int i=0; i<vertexIdx; i++) {
301                             Object JavaDoc dst = users.get(i);
302                             if (dst != null) {
303                                 dg.removeVertex(user, dst);
304                             }
305                         }
306                     }
307                 }
308                 if (maxSize != UNLIMITED && used.size() >= maxSize) {
309                     throw new PoolException(
310                             "No more resource available in pool, time out exceeded ("
311                             + timeOut + ") ! (pool max size=" + maxSize + ")");
312                 }
313             } else {
314                 throw new PoolException("No more resource available in pool (max="
315                         + maxSize + ")");
316             }
317         }
318         updateToMinsize(hints);
319
320         //search a free resource matching the hints
321
Object JavaDoc resource = null;
322         int freesize = free.size() -1;
323         for (int i = freesize; resource == null && i >=0; i--) {
324             resource = free.get(i);
325             if (matchFactory.matchResource(resource, hints)) {
326                 free.remove(i);
327                 if (freettl > 0) {
328                     timesOfFree.remove(i);
329                 }
330                 if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
331                     logger.log(BasicLevel.DEBUG, "Resource reused: '" + resource + "'.");
332                 }
333             } else {
334                 resource = null;
335             }
336         }
337         
338         if (resource == null) {
339             //no free and matching resource found ==> create it
340
resource = createResource(hints);
341         }
342
343         used.add(resource);
344         if (dg != null) {
345             // register the user for the dependencies management even if the
346
// value is null. Indeed we MUST keep the same size between both
347
// lists (used and users).
348
users.add(user);
349             if (user != null && logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
350                 logger.log(BasicLevel.DEBUG, "The user '" + user
351                         + "' gets the resource '" + resource +"'.");
352             }
353         }
354         return resource;
355     }
356
357     public synchronized int getSize() {
358         return free.size() + used.size();
359     }
360     
361     public synchronized int getFreeResourceNumber() {
362         return free.size();
363     }
364     public synchronized int getUsedResourceNumber() {
365         return used.size();
366     }
367     public synchronized Collection JavaDoc getUsers() {
368         return Collections.unmodifiableCollection(users);
369     }
370     
371     /**
372      * <b>releaseResource</b> releases a PoolResource in order to allow the
373      * Pool to recycle this PoolResource.
374      * @param resource The PoolResource to be released.
375      */

376     public synchronized void releaseResource(Object JavaDoc resource) throws PoolException {
377         //System.out.println("releaseResource: max=" + (maxSize == UNLIMITED ? "U" : "" + maxSize) + ", free=" + free.size() + ", used=" + used.size() +")");
378
boolean found = false;
379         for(int i=(used.size() -1); !found && i>=0; i--) {
380             if (resource == used.get(i)) {
381                 found = true;
382                 used.remove(i);
383                 if (dg != null) {
384                     Object JavaDoc user = users.remove(i);
385                     if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) {
386                         if (user == null) {
387                             logger.log(BasicLevel.DEBUG, "The resource '"
388                                     + resource +"' is released.");
389                         } else {
390                             logger.log(BasicLevel.DEBUG, "The user '" + user
391                                     + "' releases the resource '" + resource +"'.");
392                         }
393                     }
394                 }
395             }
396         }
397         if (!found) {
398             throw new PoolException("Release an unused resource:" + resource);
399         }
400         boolean toremove = false;
401         boolean notify = true;
402         if (maxSize != UNLIMITED
403                 && (free.size() + used.size()) > maxSize) {
404             toremove = true;
405             notify = false;
406             if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
407                 logger.log(BasicLevel.INFO, "Released resource is destroyed (too many resources in the pool): '" + resource + "'.");
408             }
409         } else {
410             if (ttl > 0) {
411                 long t = Calendar.getInstance().getTimeInMillis();
412                 t -= ((Long JavaDoc) res2ttl.get(resource)).longValue();
413                 if (t > ttl) {
414                     if (logger != null && logger.isLoggable(BasicLevel.INFO)) {
415                         logger.log(BasicLevel.INFO, "Released resource is being destroyed (too old): '" + resource + "'.");
416                     }
417                     toremove = true;
418                     //notify because a slot is available
419
}
420             }
421         }
422         if (toremove) {
423             //The resource is removed from the pool
424
if (ttl>0) {
425                 res2ttl.remove(resource);
426             }
427             matchFactory.destroyResource(resource);
428         } else {
429             //The resource is put into the list of free resources
430
free.add(resource);
431             if (freettl > 0) {
432                 timesOfFree.add(new Long JavaDoc(Calendar.getInstance().getTimeInMillis()));
433             }
434         }
435         if (notify) {
436             //signal that a resource has been free
437
notify();
438         }
439     }
440
441
442     // IMPLEMENTATION OF THE PoolAttributes INTERFACE //
443
//------------------------------------------------//
444

445     /**
446      * <b>getTimeout</b> retrieves the timeout assigned to this Pool.
447      * @return The timeout currently assigned to this Pool.
448      */

449     public long getTimeout() {
450         return timeOut;
451     }
452
453     /**
454      * <b>getMinSize</b> retrieves the minimum size assigned to this Pool.
455      * @return The minimum size currently assigned to this Pool.
456      */

457     public int getMinSize() {
458         return minSize;
459     }
460
461     /**
462      * <b>getMaxSize</b> retrieves the maximum size assigned to this Pool.
463      * @return The maximum size currently assigned to this Pool.
464      */

465     public int getMaxSize() {
466         return maxSize;
467     }
468
469     /**
470      * <b>setTimeout</b> assigns a timeout to this Pool.
471      * @param crto The timeout to be assigned.
472      */

473     public void setTimeout(long crto) {
474         timeOut = crto;
475     }
476
477     /**
478      * <b>setMinSize</b> assigns a minimum size to this Pool.
479      * @param minsize The minimum size to be assigned.
480      */

481     public void setMinSize(int minsize) throws Exception JavaDoc {
482         minSize = minsize;
483         if (started) {
484             updateToMinsize(null);
485         }
486     }
487
488     /**
489      * <b>setMaxSize</b> assigns a maximum size to this Pool.
490      * @param maxsize The maximum size to be assigned.
491      */

492     public void setMaxSize(int maxsize) throws Exception JavaDoc {
493         maxSize = maxsize;
494         if (started) {
495             updateToMaxsize();
496         }
497     }
498
499     public long getTTL() {
500         return ttl;
501     }
502     
503     public void setTTL(long ttl) {
504         this.ttl = ttl;
505     }
506
507     public long getInactiveTTL() {
508         return freettl;
509     }
510
511     public void setInactiveTTL(long fttl) {
512         this.freettl = fttl;
513     }
514 }
515
Popular Tags