View Javadoc
1 package org.apache.turbine.services.pool; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import java.lang.reflect.Method; 58 import java.util.ArrayList; 59 import java.util.HashMap; 60 import java.util.Iterator; 61 import org.apache.commons.configuration.Configuration; 62 import org.apache.turbine.services.InitializationException; 63 import org.apache.turbine.services.TurbineServices; 64 import org.apache.turbine.services.factory.FactoryService; 65 import org.apache.turbine.services.factory.TurbineFactoryService; 66 import org.apache.turbine.util.TurbineException; 67 import org.apache.turbine.util.pool.ArrayCtorRecyclable; 68 import org.apache.turbine.util.pool.BoundedBuffer; 69 import org.apache.turbine.util.pool.Recyclable; 70 71 /*** 72 * The Pool Service extends the Factory Service by adding support 73 * for pooling instantiated objects. When a new instance is 74 * requested, the service first checks its pool if one is available. 75 * If the the pool is empty, a new instance will be requested 76 * from the FactoryService. 77 * 78 * <p>For objects implementing the Recyclable interface, a recycle 79 * method will be called, when they taken from the pool, and 80 * a dispose method, when they are returned to the pool. 81 * 82 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> 83 * @version $Id: TurbinePoolService.java,v 1.4 2002/07/11 16:53:25 mpoeschl Exp $ 84 */ 85 public class TurbinePoolService 86 extends TurbineFactoryService 87 implements PoolService 88 { 89 /*** 90 * The property specifying the pool capacity. 91 */ 92 public static final String POOL_CAPACITY = "pool.capacity"; 93 94 /*** 95 * An inner class for class specific pools. 96 */ 97 private class PoolBuffer 98 { 99 /*** 100 * An inner class for cached recycle methods. 101 */ 102 private class Recycler 103 { 104 /*** 105 * The method. 106 */ 107 private final Method recycle; 108 109 /*** 110 * The signature. 111 */ 112 private final String[] signature; 113 114 /*** 115 * Constructs a new recycler. 116 * 117 * @param rec the recycle method. 118 * @param sign the signature. 119 */ 120 public Recycler(Method rec, String[] sign) 121 { 122 recycle = rec; 123 signature = (sign != null) && (sign.length > 0) ? sign : null; 124 } 125 126 /*** 127 * Matches the given signature against 128 * that of the recycle method of this recycler. 129 * 130 * @param sign the signature. 131 * @return the matching recycle method or null. 132 */ 133 public Method match(String[] sign) 134 { 135 if ((sign != null) && (sign.length > 0)) 136 { 137 if ((signature != null) 138 && (sign.length == signature.length)) 139 { 140 for (int i = 0; i < signature.length; i++) 141 { 142 if (!signature[i].equals(sign[i])) 143 { 144 return null; 145 } 146 } 147 return recycle; 148 } 149 else 150 { 151 return null; 152 } 153 } 154 else if (signature == null) 155 { 156 return recycle; 157 } 158 else 159 { 160 return null; 161 } 162 } 163 } 164 165 /*** 166 * A buffer for class instances. 167 */ 168 private BoundedBuffer pool; 169 170 /*** 171 * A flag to determine if a more efficient recycler is implemented. 172 */ 173 private boolean arrayCtorRecyclable; 174 175 /*** 176 * A cache for recycling methods. 177 */ 178 private ArrayList recyclers; 179 180 /*** 181 * Contructs a new pool buffer with a specific capacity. 182 * 183 * @param capacity a capacity. 184 */ 185 public PoolBuffer(int capacity) 186 { 187 pool = new BoundedBuffer(capacity); 188 } 189 190 /*** 191 * Tells pool that it contains objects which can be 192 * initialized using an Object array. 193 * 194 * @param isArrayCtor a <code>boolean</code> value 195 */ 196 public void setArrayCtorRecyclable(boolean isArrayCtor) 197 { 198 arrayCtorRecyclable = isArrayCtor; 199 } 200 201 /*** 202 * Polls for an instance from the pool. 203 * 204 * @return an instance or null. 205 */ 206 public Object poll(Object[] params, String[] signature) 207 throws TurbineException 208 { 209 Object instance = pool.poll(); 210 if (instance != null) 211 { 212 if (arrayCtorRecyclable) 213 { 214 ((ArrayCtorRecyclable) instance).recycle(params); 215 } 216 else if (instance instanceof Recyclable) 217 { 218 try 219 { 220 if ((signature != null) && (signature.length > 0)) 221 { 222 /* Get the recycle method from the cache. */ 223 Method recycle = getRecycle(signature); 224 if (recycle == null) 225 { 226 synchronized(this) 227 { 228 /* Make a synchronized recheck. */ 229 recycle = getRecycle(signature); 230 if (recycle == null) 231 { 232 Class clazz = instance.getClass(); 233 recycle = clazz.getMethod("recycle", 234 TurbinePoolService.this.getSignature( 235 clazz,params,signature)); 236 ArrayList cache = recyclers != null ? 237 (ArrayList) recyclers.clone() : 238 new ArrayList(); 239 cache.add( 240 new Recycler(recycle,signature)); 241 recyclers = cache; 242 } 243 } 244 } 245 recycle.invoke(instance,params); 246 } 247 else 248 { 249 ((Recyclable) instance).recycle(); 250 } 251 } 252 catch (Exception x) 253 { 254 throw new TurbineException( 255 "Recycling failed for " + instance.getClass().getName(),x); 256 } 257 } 258 } 259 return instance; 260 } 261 262 /*** 263 * Offers an instance to the pool. 264 * 265 * @param instance an instance. 266 */ 267 public boolean offer(Object instance) 268 { 269 if (instance instanceof Recyclable) 270 { 271 try 272 { 273 ((Recyclable) instance).dispose(); 274 } 275 catch (Exception x) 276 { 277 return false; 278 } 279 } 280 return pool.offer(instance); 281 } 282 283 /*** 284 * Returns the capacity of the pool. 285 * 286 * @return the capacity. 287 */ 288 public int capacity() 289 { 290 return pool.capacity(); 291 } 292 293 /*** 294 * Returns the size of the pool. 295 * 296 * @return the size. 297 */ 298 public int size() 299 { 300 return pool.size(); 301 } 302 303 /*** 304 * Returns a cached recycle method 305 * corresponding to the given signature. 306 * 307 * @param signature the signature. 308 * @return the recycle method or null. 309 */ 310 private Method getRecycle(String[] signature) 311 { 312 ArrayList cache = recyclers; 313 if (cache != null) 314 { 315 Method recycle; 316 for (Iterator i = cache.iterator(); i.hasNext();) 317 { 318 recycle = ((Recycler) i.next()).match(signature); 319 if (recycle != null) 320 { 321 return recycle; 322 } 323 } 324 } 325 return null; 326 } 327 } 328 329 /*** 330 * The default capacity of pools. 331 */ 332 private int poolCapacity = DEFAULT_POOL_CAPACITY; 333 334 /*** 335 * The pool repository, one pool for each class. 336 */ 337 private HashMap poolRepository = new HashMap(); 338 339 /*** 340 * Constructs a Pool Service. 341 */ 342 public TurbinePoolService() 343 { 344 } 345 346 /*** 347 * Initializes the service by setting the pool capacity. 348 * 349 * @param config initialization configuration. 350 * @throws InitializationException if initialization fails. 351 */ 352 public void init() 353 throws InitializationException 354 { 355 Configuration conf = getConfiguration(); 356 if (conf != null) 357 { 358 try 359 { 360 int capacity = conf.getInt(POOL_CAPACITY,DEFAULT_POOL_CAPACITY); 361 if (capacity <= 0) 362 { 363 throw new IllegalArgumentException("Capacity must be >0"); 364 } 365 poolCapacity = capacity; 366 } 367 catch (Exception x) 368 { 369 throw new InitializationException( 370 "Failed to initialize TurbinePoolService",x); 371 } 372 } 373 setInit(true); 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 * 380 * @param className the name of the class. 381 * @return the instance. 382 * @throws TurbineException if recycling fails. 383 */ 384 public Object getInstance(String className) 385 throws TurbineException 386 { 387 Object instance = pollInstance(className,null,null); 388 return instance == null ? 389 getFactory().getInstance(className) : instance; 390 } 391 392 /*** 393 * Gets an instance of a named class either from the pool 394 * or by calling the Factory Service if the pool is empty. 395 * The specified class loader will be passed to the Factory Service. 396 * 397 * @param className the name of the class. 398 * @param loader the class loader. 399 * @return the instance. 400 * @throws TurbineException if recycling fails. 401 */ 402 public Object getInstance(String className, 403 ClassLoader loader) 404 throws TurbineException 405 { 406 Object instance = pollInstance(className,null,null); 407 return instance == null ? 408 getFactory().getInstance(className,loader) : instance; 409 } 410 411 /*** 412 * Gets an instance of a named class either from the pool 413 * or by calling the Factory Service if the pool is empty. 414 * Parameters for its constructor are given as an array of objects, 415 * primitive types must be wrapped with a corresponding class. 416 * 417 * @param className the name of the class. 418 * @param loader the class loader. 419 * @param params an array containing the parameters of the constructor. 420 * @param signature an array containing the signature of the constructor. 421 * @return the instance. 422 * @throws TurbineException if recycling fails. 423 */ 424 public Object getInstance(String className, 425 Object[] params, 426 String[] signature) 427 throws TurbineException 428 { 429 Object instance = pollInstance(className,params,signature); 430 return instance == null ? 431 getFactory().getInstance(className,params,signature) : instance; 432 } 433 434 /*** 435 * Gets an instance of a named class either from the pool 436 * or by calling the Factory Service if the pool is empty. 437 * Parameters for its constructor are given as an array of objects, 438 * primitive types must be wrapped with a corresponding class. 439 * The specified class loader will be passed to the Factory Service. 440 * 441 * @param className the name of the class. 442 * @param loader the class loader. 443 * @param params an array containing the parameters of the constructor. 444 * @param signature an array containing the signature of the constructor. 445 * @return the instance. 446 * @throws TurbineException if recycling fails. 447 */ 448 public Object getInstance(String className, 449 ClassLoader loader, 450 Object[] params, 451 String[] signature) 452 throws TurbineException 453 { 454 Object instance = pollInstance(className,params,signature); 455 return instance == null ? 456 getFactory().getInstance(className,loader,params,signature) : instance; 457 } 458 459 /*** 460 * Tests if specified class loaders are supported for a named class. 461 * 462 * @param className the name of the class. 463 * @return true if class loaders are supported, false otherwise. 464 * @throws TurbineException if test fails. 465 */ 466 public boolean isLoaderSupported(String className) 467 throws TurbineException 468 { 469 return getFactory().isLoaderSupported(className); 470 } 471 472 /*** 473 * Gets an instance of a specified class either from the pool 474 * or by instatiating from the class if the pool is empty. 475 * 476 * @param clazz the class. 477 * @return the instance. 478 * @throws TurbineException if recycling fails. 479 */ 480 public Object getInstance(Class clazz) 481 throws TurbineException 482 { 483 Object instance = pollInstance(clazz.getName(),null,null); 484 return instance == null ? 485 super.getInstance(clazz) : instance; 486 } 487 488 /*** 489 * Gets an instance of a specified class either from the pool 490 * or by instatiating from the class if the pool is empty. 491 * 492 * @param clazz the class. 493 * @param params an array containing the parameters of the constructor. 494 * @param signature an array containing the signature of the constructor. 495 * @return the instance. 496 * @throws TurbineException if recycling fails. 497 */ 498 public Object getInstance(Class clazz, 499 Object params[], 500 String signature[]) 501 throws TurbineException 502 { 503 Object instance = pollInstance(clazz.getName(),params,signature); 504 return instance == null ? 505 super.getInstance(clazz,params,signature) : instance; 506 } 507 508 /*** 509 * Puts a used object back to the pool. Objects implementing 510 * the Recyclable interface can provide a recycle method to 511 * be called when they are reused and a dispose method to be 512 * called when they are returned to the pool. 513 * 514 * @param instance the object instance to recycle. 515 * @return true if the instance was accepted. 516 */ 517 public boolean putInstance(Object instance) 518 { 519 if (instance != null) 520 { 521 HashMap repository = poolRepository; 522 String className = instance.getClass().getName(); 523 PoolBuffer pool = (PoolBuffer) repository.get(className); 524 if (pool == null) 525 { 526 pool = new PoolBuffer(getCapacity(className)); 527 repository = (HashMap) repository.clone(); 528 repository.put(className,pool); 529 poolRepository = repository; 530 531 if (instance instanceof ArrayCtorRecyclable) 532 { 533 pool.setArrayCtorRecyclable(true); 534 } 535 } 536 return pool.offer(instance); 537 } 538 else 539 { 540 return false; 541 } 542 } 543 544 /*** 545 * Gets the capacity of the pool for a named class. 546 * 547 * @param className the name of the class. 548 */ 549 public int getCapacity(String className) 550 { 551 PoolBuffer pool = (PoolBuffer) poolRepository.get(className); 552 if (pool == null) 553 { 554 /* Check class specific capacity. */ 555 int capacity = poolCapacity; 556 Configuration conf = getConfiguration(); 557 if (conf != null) 558 { 559 try 560 { 561 capacity = conf.getInt( 562 POOL_CAPACITY + '.' + className,poolCapacity); 563 if (capacity <= 0) 564 { 565 capacity = poolCapacity; 566 } 567 } 568 catch (Exception x) 569 { 570 } 571 } 572 return capacity; 573 } 574 else 575 { 576 return pool.capacity(); 577 } 578 } 579 580 /*** 581 * Sets the capacity of the pool for a named class. 582 * Note that the pool will be cleared after the change. 583 * 584 * @param className the name of the class. 585 * @param capacity the new capacity. 586 */ 587 public void setCapacity(String className, 588 int capacity) 589 { 590 HashMap repository = poolRepository; 591 repository = repository != null ? 592 (HashMap) repository.clone() : new HashMap(); 593 repository.put(className,new PoolBuffer(capacity)); 594 poolRepository = repository; 595 } 596 597 /*** 598 * Gets the current size of the pool for a named class. 599 * 600 * @param className the name of the class. 601 */ 602 public int getSize(String className) 603 { 604 PoolBuffer pool = (PoolBuffer) poolRepository.get(className); 605 return pool != null ? pool.size() : 0; 606 } 607 608 /*** 609 * Clears instances of a named class from the pool. 610 * 611 * @param className the name of the class. 612 */ 613 public void clearPool(String className) 614 { 615 HashMap repository = poolRepository; 616 if (repository.get(className) != null) 617 { 618 repository = (HashMap) repository.clone(); 619 repository.remove(className); 620 poolRepository = repository; 621 } 622 } 623 624 /*** 625 * Clears all instances from the pool. 626 */ 627 public void clearPool() 628 { 629 poolRepository = new HashMap(); 630 } 631 632 /*** 633 * Polls and recycles an object of the named class from the pool. 634 * 635 * @param className the name of the class. 636 * @param params an array containing the parameters of the constructor. 637 * @param signature an array containing the signature of the constructor. 638 * @return the object or null. 639 * @throws TurbineException if recycling fails. 640 */ 641 private Object pollInstance(String className, 642 Object[] params, 643 String[] signature) 644 throws TurbineException 645 { 646 PoolBuffer pool = (PoolBuffer) poolRepository.get(className); 647 return pool != null ? pool.poll(params,signature) : null; 648 } 649 650 /*** 651 * Gets the factory service. 652 * 653 * @return the factory service. 654 */ 655 private FactoryService getFactory() 656 { 657 return (FactoryService) TurbineServices. 658 getInstance().getService(FactoryService.SERVICE_NAME); 659 } 660 }

This page was automatically generated by Maven