KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > pool > TurbinePoolService


1 package org.apache.turbine.services.pool;
2
3 /*
4  * Copyright 2001-2004 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License")
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.lang.reflect.Method JavaDoc;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24
25 import org.apache.commons.configuration.Configuration;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import org.apache.turbine.services.InitializationException;
31 import org.apache.turbine.services.TurbineBaseService;
32 import org.apache.turbine.services.factory.FactoryService;
33 import org.apache.turbine.services.factory.TurbineFactory;
34 import org.apache.turbine.util.TurbineException;
35 import org.apache.turbine.util.pool.ArrayCtorRecyclable;
36 import org.apache.turbine.util.pool.BoundedBuffer;
37 import org.apache.turbine.util.pool.Recyclable;
38
39 /**
40  * The Pool Service extends the Factory Service by adding support
41  * for pooling instantiated objects. When a new instance is
42  * requested, the service first checks its pool if one is available.
43  * If the the pool is empty, a new instance will be requested
44  * from the FactoryService.
45  *
46  * <p>For objects implementing the Recyclable interface, a recycle
47  * method will be called, when they taken from the pool, and
48  * a dispose method, when they are returned to the pool.
49  *
50  * @author <a HREF="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
51  * @author <a HREF="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
52  * @version $Id: TurbinePoolService.java,v 1.9.2.2 2004/05/20 03:06:52 seade Exp $
53  */

54 public class TurbinePoolService
55         extends TurbineBaseService
56         implements PoolService
57 {
58     /** Are we currently debugging the pool recycling? */
59     private boolean debugPool = false;
60
61     /** Internal Reference to the Factory */
62     private FactoryService factoryService;
63
64     /** Logging */
65     private static Log log = LogFactory.getLog(TurbinePoolService.class);
66
67     /**
68      * An inner class for class specific pools.
69      */

70     private class PoolBuffer
71     {
72         /**
73          * An inner class for cached recycle methods.
74          */

75         private class Recycler
76         {
77             /** The recycle method. */
78             private final Method JavaDoc recycle;
79
80             /** The signature. */
81             private final String JavaDoc[] signature;
82
83             /**
84              * Constructs a new recycler.
85              *
86              * @param rec the recycle method.
87              * @param sign the signature.
88              */

89             public Recycler(Method JavaDoc rec, String JavaDoc[] sign)
90             {
91                 recycle = rec;
92                 signature = ((sign != null) && (sign.length > 0))
93                         ? sign : null;
94             }
95
96             /**
97              * Matches the given signature against
98              * that of the recycle method of this recycler.
99              *
100              * @param sign the signature.
101              * @return the matching recycle method or null.
102              */

103             public Method JavaDoc match(String JavaDoc[] sign)
104             {
105                 if ((sign != null) && (sign.length > 0))
106                 {
107                     if ((signature != null)
108                             && (sign.length == signature.length))
109                     {
110                         for (int i = 0; i < signature.length; i++)
111                         {
112                             if (!signature[i].equals(sign[i]))
113                             {
114                                 return null;
115                             }
116                         }
117                         return recycle;
118                     }
119                     else
120                     {
121                         return null;
122                     }
123                 }
124                 else if (signature == null)
125                 {
126                     return recycle;
127                 }
128                 else
129                 {
130                     return null;
131                 }
132             }
133         }
134
135         /** A buffer for class instances. */
136         private BoundedBuffer pool;
137
138         /** A flag to determine if a more efficient recycler is implemented. */
139         private boolean arrayCtorRecyclable;
140
141         /** A cache for recycling methods. */
142         private ArrayList JavaDoc recyclers;
143
144         /**
145          * Constructs a new pool buffer with a specific capacity.
146          *
147          * @param capacity a capacity.
148          */

149         public PoolBuffer(int capacity)
150         {
151             pool = new BoundedBuffer(capacity);
152         }
153
154         /**
155          * Tells pool that it contains objects which can be
156          * initialized using an Object array.
157          *
158          * @param isArrayCtor a <code>boolean</code> value
159          */

160         public void setArrayCtorRecyclable(boolean isArrayCtor)
161         {
162             arrayCtorRecyclable = isArrayCtor;
163         }
164
165         /**
166          * Polls for an instance from the pool.
167          *
168          * @return an instance or null.
169          */

170         public Object JavaDoc poll(Object JavaDoc[] params, String JavaDoc[] signature)
171                 throws TurbineException
172         {
173             // If we're debugging the recycling code, we want different
174
// objects to be used when pulling from the pool. Ensure that
175
// each pool fills up at least to half its capacity.
176
if (debugPool && (pool.size() < (pool.capacity() / 2)))
177             {
178                 log.debug("Size: " + pool.size()
179                         + ", capacity: " + pool.capacity());
180                 return null;
181             }
182
183             Object JavaDoc instance = pool.poll();
184             if (instance != null)
185             {
186                 if (arrayCtorRecyclable)
187                 {
188                     ((ArrayCtorRecyclable) instance).recycle(params);
189                 }
190                 else if (instance instanceof Recyclable)
191                 {
192                     try
193                     {
194                         if ((signature != null) && (signature.length > 0))
195                         {
196                             /* Get the recycle method from the cache. */
197                             Method JavaDoc recycle = getRecycle(signature);
198                             if (recycle == null)
199                             {
200                                 synchronized (this)
201                                 {
202                                     /* Make a synchronized recheck. */
203                                     recycle = getRecycle(signature);
204                                     if (recycle == null)
205                                     {
206                                         Class JavaDoc clazz = instance.getClass();
207                                         recycle = clazz.getMethod("recycle",
208                                                 factoryService.getSignature(
209                                                         clazz, params, signature));
210                                         ArrayList JavaDoc cache = recyclers != null
211                                                 ? (ArrayList JavaDoc) recyclers.clone()
212                                                 : new ArrayList JavaDoc();
213                                         cache.add(
214                                                 new Recycler(recycle, signature));
215                                         recyclers = cache;
216                                     }
217                                 }
218                             }
219                             recycle.invoke(instance, params);
220                         }
221                         else
222                         {
223                             ((Recyclable) instance).recycle();
224                         }
225                     }
226                     catch (Exception JavaDoc x)
227                     {
228                         throw new TurbineException(
229                                 "Recycling failed for " + instance.getClass().getName(), x);
230                     }
231                 }
232             }
233             return instance;
234         }
235
236         /**
237          * Offers an instance to the pool.
238          *
239          * @param instance an instance.
240          */

241         public boolean offer(Object JavaDoc instance)
242         {
243             if (instance instanceof Recyclable)
244             {
245                 try
246                 {
247                     ((Recyclable) instance).dispose();
248                 }
249                 catch (Exception JavaDoc x)
250                 {
251                     return false;
252                 }
253             }
254             return pool.offer(instance);
255         }
256
257         /**
258          * Returns the capacity of the pool.
259          *
260          * @return the capacity.
261          */

262         public int capacity()
263         {
264             return pool.capacity();
265         }
266
267         /**
268          * Returns the size of the pool.
269          *
270          * @return the size.
271          */

272         public int size()
273         {
274             return pool.size();
275         }
276
277         /**
278          * Returns a cached recycle method
279          * corresponding to the given signature.
280          *
281          * @param signature the signature.
282          * @return the recycle method or null.
283          */

284         private Method JavaDoc getRecycle(String JavaDoc[] signature)
285         {
286             ArrayList JavaDoc cache = recyclers;
287             if (cache != null)
288             {
289                 Method JavaDoc recycle;
290                 for (Iterator JavaDoc i = cache.iterator(); i.hasNext();)
291                 {
292                     recycle = ((Recycler) i.next()).match(signature);
293                     if (recycle != null)
294                     {
295                         return recycle;
296                     }
297                 }
298             }
299             return null;
300         }
301     }
302
303     /**
304      * The default capacity of pools.
305      */

306     private int poolCapacity = DEFAULT_POOL_CAPACITY;
307
308     /**
309      * The pool repository, one pool for each class.
310      */

311     private HashMap JavaDoc poolRepository = new HashMap JavaDoc();
312
313     /**
314      * Constructs a Pool Service.
315      */

316     public TurbinePoolService()
317     {
318     }
319
320     /**
321      * Initializes the service by setting the pool capacity.
322      *
323      * @param config initialization configuration.
324      * @throws InitializationException if initialization fails.
325      */

326     public void init()
327             throws InitializationException
328     {
329         Configuration conf = getConfiguration();
330
331         int capacity = conf.getInt(POOL_CAPACITY_KEY,
332                 DEFAULT_POOL_CAPACITY);
333
334         if (capacity <= 0)
335         {
336             throw new IllegalArgumentException JavaDoc("Capacity must be >0");
337         }
338         poolCapacity = capacity;
339
340         debugPool = conf.getBoolean(POOL_DEBUG_KEY,
341                 POOL_DEBUG_DEFAULT);
342         
343         if (debugPool)
344         {
345             log.info("Activated Pool Debugging!");
346         }
347
348         factoryService = TurbineFactory.getService();
349         
350         if (factoryService == null)
351         {
352             throw new InitializationException("Factory Service is not configured"
353                     + " but required for the Pool Service!");
354         }
355         
356         setInit(true);
357     }
358
359     /**
360      * Gets an instance of a named class either from the pool
361      * or by calling the Factory Service if the pool is empty.
362      *
363      * @param className the name of the class.
364      * @return the instance.
365      * @throws TurbineException if recycling fails.
366      */

367     public Object JavaDoc getInstance(String JavaDoc className)
368             throws TurbineException
369     {
370         Object JavaDoc instance = pollInstance(className, null, null);
371         return (instance == null)
372                 ? factoryService.getInstance(className)
373                 : instance;
374     }
375
376     /**
377      * Gets an instance of a named class either from the pool
378      * or by calling the Factory Service if the pool is empty.
379      * The specified class loader will be passed to the Factory Service.
380      *
381      * @param className the name of the class.
382      * @param loader the class loader.
383      * @return the instance.
384      * @throws TurbineException if recycling fails.
385      */

386     public Object JavaDoc getInstance(String JavaDoc className,
387                               ClassLoader JavaDoc loader)
388             throws TurbineException
389     {
390         Object JavaDoc instance = pollInstance(className, null, null);
391         return (instance == null)
392                 ? factoryService.getInstance(className, loader)
393                 : instance;
394     }
395
396     /**
397      * Gets an instance of a named class either from the pool
398      * or by calling the Factory Service if the pool is empty.
399      * Parameters for its constructor are given as an array of objects,
400      * primitive types must be wrapped with a corresponding class.
401      *
402      * @param className the name of the class.
403      * @param loader the class loader.
404      * @param params an array containing the parameters of the constructor.
405      * @param signature an array containing the signature of the constructor.
406      * @return the instance.
407      * @throws TurbineException if recycling fails.
408      */

409     public Object JavaDoc getInstance(String JavaDoc className,
410                               Object JavaDoc[] params,
411                               String JavaDoc[] signature)
412             throws TurbineException
413     {
414         Object JavaDoc instance = pollInstance(className, params, signature);
415         return (instance == null)
416                 ? factoryService.getInstance(className, params, signature)
417                 : instance;
418     }
419
420     /**
421      * Gets an instance of a named class either from the pool
422      * or by calling the Factory Service if the pool is empty.
423      * Parameters for its constructor are given as an array of objects,
424      * primitive types must be wrapped with a corresponding class.
425      * The specified class loader will be passed to the Factory Service.
426      *
427      * @param className the name of the class.
428      * @param loader the class loader.
429      * @param params an array containing the parameters of the constructor.
430      * @param signature an array containing the signature of the constructor.
431      * @return the instance.
432      * @throws TurbineException if recycling fails.
433      */

434     public Object JavaDoc getInstance(String JavaDoc className,
435                               ClassLoader JavaDoc loader,
436                               Object JavaDoc[] params,
437                               String JavaDoc[] signature)
438             throws TurbineException
439     {
440         Object JavaDoc instance = pollInstance(className, params, signature);
441         return (instance == null)
442                 ? factoryService.getInstance(className, loader, params, signature)
443                 : instance;
444     }
445
446     /**
447      * Tests if specified class loaders are supported for a named class.
448      *
449      * @param className the name of the class.
450      * @return true if class loaders are supported, false otherwise.
451      * @throws TurbineException if test fails.
452      * @deprecated Use TurbineFactory.isLoaderSupported(className);
453      */

454     public boolean isLoaderSupported(String JavaDoc className)
455             throws TurbineException
456     {
457         return factoryService.isLoaderSupported(className);
458     }
459
460     /**
461      * Gets an instance of a specified class either from the pool
462      * or by instatiating from the class if the pool is empty.
463      *
464      * @param clazz the class.
465      * @return the instance.
466      * @throws TurbineException if recycling fails.
467      */

468     public Object JavaDoc getInstance(Class JavaDoc clazz)
469             throws TurbineException
470     {
471         Object JavaDoc instance = pollInstance(clazz.getName(), null, null);
472         return (instance == null)
473                 ? factoryService.getInstance(clazz.getName())
474                 : instance;
475     }
476
477     /**
478      * Gets an instance of a specified class either from the pool
479      * or by instatiating from the class if the pool is empty.
480      *
481      * @param clazz the class.
482      * @param params an array containing the parameters of the constructor.
483      * @param signature an array containing the signature of the constructor.
484      * @return the instance.
485      * @throws TurbineException if recycling fails.
486      */

487     public Object JavaDoc getInstance(Class JavaDoc clazz,
488                               Object JavaDoc params[],
489                               String JavaDoc signature[])
490             throws TurbineException
491     {
492         Object JavaDoc instance = pollInstance(clazz.getName(), params, signature);
493         return (instance == null)
494                 ? factoryService.getInstance(clazz.getName(), params, signature)
495                 : instance;
496     }
497
498     /**
499      * Puts a used object back to the pool. Objects implementing
500      * the Recyclable interface can provide a recycle method to
501      * be called when they are reused and a dispose method to be
502      * called when they are returned to the pool.
503      *
504      * @param instance the object instance to recycle.
505      * @return true if the instance was accepted.
506      */

507     public boolean putInstance(Object JavaDoc instance)
508     {
509         if (instance != null)
510         {
511             HashMap JavaDoc repository = poolRepository;
512             String JavaDoc className = instance.getClass().getName();
513             PoolBuffer pool = (PoolBuffer) repository.get(className);
514             if (pool == null)
515             {
516                 pool = new PoolBuffer(getCapacity(className));
517                 repository = (HashMap JavaDoc) repository.clone();
518                 repository.put(className, pool);
519                 poolRepository = repository;
520
521                 if (instance instanceof ArrayCtorRecyclable)
522                 {
523                     pool.setArrayCtorRecyclable(true);
524                 }
525             }
526             return pool.offer(instance);
527         }
528         else
529         {
530             return false;
531         }
532     }
533
534     /**
535      * Gets the capacity of the pool for a named class.
536      *
537      * @param className the name of the class.
538      */

539     public int getCapacity(String JavaDoc className)
540     {
541         PoolBuffer pool = (PoolBuffer) poolRepository.get(className);
542         if (pool == null)
543         {
544             /* Check class specific capacity. */
545             int capacity;
546
547             Configuration conf = getConfiguration();
548             capacity = conf.getInt(
549                     POOL_CAPACITY_KEY + '.' + className,
550                     poolCapacity);
551             capacity = (capacity <= 0) ? poolCapacity : capacity;
552             return capacity;
553         }
554         else
555         {
556             return pool.capacity();
557         }
558     }
559
560     /**
561      * Sets the capacity of the pool for a named class.
562      * Note that the pool will be cleared after the change.
563      *
564      * @param className the name of the class.
565      * @param capacity the new capacity.
566      */

567     public void setCapacity(String JavaDoc className,
568                             int capacity)
569     {
570         HashMap JavaDoc repository = poolRepository;
571         repository = (repository != null)
572                 ? (HashMap JavaDoc) repository.clone() : new HashMap JavaDoc();
573         
574         capacity = (capacity <= 0) ? poolCapacity : capacity;
575
576         repository.put(className, new PoolBuffer(capacity));
577         poolRepository = repository;
578     }
579
580     /**
581      * Gets the current size of the pool for a named class.
582      *
583      * @param className the name of the class.
584      */

585     public int getSize(String JavaDoc className)
586     {
587         PoolBuffer pool = (PoolBuffer) poolRepository.get(className);
588         return (pool != null) ? pool.size() : 0;
589     }
590
591     /**
592      * Clears instances of a named class from the pool.
593      *
594      * @param className the name of the class.
595      */

596     public void clearPool(String JavaDoc className)
597     {
598         HashMap JavaDoc repository = poolRepository;
599         if (repository.get(className) != null)
600         {
601             repository = (HashMap JavaDoc) repository.clone();
602             repository.remove(className);
603             poolRepository = repository;
604         }
605     }
606
607     /**
608      * Clears all instances from the pool.
609      */

610     public void clearPool()
611     {
612         poolRepository = new HashMap JavaDoc();
613     }
614
615     /**
616      * Polls and recycles an object of the named class from the pool.
617      *
618      * @param className the name of the class.
619      * @param params an array containing the parameters of the constructor.
620      * @param signature an array containing the signature of the constructor.
621      * @return the object or null.
622      * @throws TurbineException if recycling fails.
623      */

624     private Object JavaDoc pollInstance(String JavaDoc className,
625                                 Object JavaDoc[] params,
626                                 String JavaDoc[] signature)
627             throws TurbineException
628     {
629         PoolBuffer pool = (PoolBuffer) poolRepository.get(className);
630         return (pool != null) ? pool.poll(params, signature) : null;
631     }
632 }
633
Popular Tags