1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.pool.impl;
  17. import java.util.EmptyStackException;
  18. import java.util.Enumeration;
  19. import java.util.NoSuchElementException;
  20. import java.util.Stack;
  21. import org.apache.commons.pool.BaseObjectPool;
  22. import org.apache.commons.pool.ObjectPool;
  23. import org.apache.commons.pool.PoolableObjectFactory;
  24. /**
  25. * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation.
  26. * <p>
  27. * Given a {@link PoolableObjectFactory}, this class will maintain
  28. * a simple pool of instances. A finite number of "sleeping"
  29. * or idle instances is enforced, but when the pool is
  30. * empty, new instances are created to support the new load.
  31. * Hence this class places no limit on the number of "active"
  32. * instances created by the pool, but is quite useful for
  33. * re-using <tt>Object</tt>s without introducing
  34. * artificial limits.
  35. *
  36. * @author Rodney Waldhoff
  37. * @version $Revision: 1.15 $ $Date: 2004/02/28 11:46:33 $
  38. */
  39. public class StackObjectPool extends BaseObjectPool implements ObjectPool {
  40. /**
  41. * Create a new pool using
  42. * no factory. Clients must first populate the pool
  43. * using {@link #returnObject(java.lang.Object)}
  44. * before they can be {@link #borrowObject borrowed}.
  45. */
  46. public StackObjectPool() {
  47. this((PoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
  48. }
  49. /**
  50. * Create a new pool using
  51. * no factory. Clients must first populate the pool
  52. * using {@link #returnObject(java.lang.Object)}
  53. * before they can be {@link #borrowObject borrowed}.
  54. *
  55. * @param maxIdle cap on the number of "sleeping" instances in the pool
  56. */
  57. public StackObjectPool(int maxIdle) {
  58. this((PoolableObjectFactory)null,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
  59. }
  60. /**
  61. * Create a new pool using
  62. * no factory. Clients must first populate the pool
  63. * using {@link #returnObject(java.lang.Object)}
  64. * before they can be {@link #borrowObject borrowed}.
  65. *
  66. * @param maxIdle cap on the number of "sleeping" instances in the pool
  67. * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
  68. * it does not cause the pool to be pre-populated.)
  69. */
  70. public StackObjectPool(int maxIdle, int initIdleCapacity) {
  71. this((PoolableObjectFactory)null,maxIdle,initIdleCapacity);
  72. }
  73. /**
  74. * Create a new <tt>StackObjectPool</tt> using
  75. * the specified <i>factory</i> to create new instances.
  76. *
  77. * @param factory the {@link PoolableObjectFactory} used to populate the pool
  78. */
  79. public StackObjectPool(PoolableObjectFactory factory) {
  80. this(factory,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
  81. }
  82. /**
  83. * Create a new <tt>SimpleObjectPool</tt> using
  84. * the specified <i>factory</i> to create new instances,
  85. * capping the number of "sleeping" instances to <i>max</i>
  86. *
  87. * @param factory the {@link PoolableObjectFactory} used to populate the pool
  88. * @param maxIdle cap on the number of "sleeping" instances in the pool
  89. */
  90. public StackObjectPool(PoolableObjectFactory factory, int maxIdle) {
  91. this(factory,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
  92. }
  93. /**
  94. * Create a new <tt>SimpleObjectPool</tt> using
  95. * the specified <i>factory</i> to create new instances,
  96. * capping the number of "sleeping" instances to <i>max</i>,
  97. * and initially allocating a container capable of containing
  98. * at least <i>init</i> instances.
  99. *
  100. * @param factory the {@link PoolableObjectFactory} used to populate the pool
  101. * @param maxIdle cap on the number of "sleeping" instances in the pool
  102. * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
  103. * it does not cause the pool to be pre-populated.)
  104. */
  105. public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) {
  106. _factory = factory;
  107. _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
  108. int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity);
  109. _pool = new Stack();
  110. _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity);
  111. }
  112. public synchronized Object borrowObject() throws Exception {
  113. assertOpen();
  114. Object obj = null;
  115. try {
  116. obj = _pool.pop();
  117. } catch(EmptyStackException e) {
  118. if(null == _factory) {
  119. throw new NoSuchElementException();
  120. } else {
  121. obj = _factory.makeObject();
  122. }
  123. }
  124. if(null != _factory && null != obj) {
  125. _factory.activateObject(obj);
  126. }
  127. _numActive++;
  128. return obj;
  129. }
  130. public void returnObject(Object obj) throws Exception {
  131. assertOpen();
  132. boolean success = true;
  133. if(null != _factory) {
  134. if(!(_factory.validateObject(obj))) {
  135. success = false;
  136. } else {
  137. try {
  138. _factory.passivateObject(obj);
  139. } catch(Exception e) {
  140. success = false;
  141. }
  142. }
  143. }
  144. boolean shouldDestroy = !success;
  145. synchronized(this) {
  146. _numActive--;
  147. if(_pool.size() >= _maxSleeping) {
  148. shouldDestroy = true;
  149. } else if(success) {
  150. _pool.push(obj);
  151. }
  152. notifyAll(); // _numActive has changed
  153. }
  154. if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
  155. try {
  156. _factory.destroyObject(obj);
  157. } catch(Exception e) {
  158. // ignored
  159. }
  160. }
  161. }
  162. public synchronized void invalidateObject(Object obj) throws Exception {
  163. assertOpen();
  164. _numActive--;
  165. if(null != _factory ) {
  166. _factory.destroyObject(obj);
  167. }
  168. notifyAll(); // _numActive has changed
  169. }
  170. public int getNumIdle() {
  171. assertOpen();
  172. return _pool.size();
  173. }
  174. public int getNumActive() {
  175. assertOpen();
  176. return _numActive;
  177. }
  178. public synchronized void clear() {
  179. assertOpen();
  180. if(null != _factory) {
  181. Enumeration enum = _pool.elements();
  182. while(enum.hasMoreElements()) {
  183. try {
  184. _factory.destroyObject(enum.nextElement());
  185. } catch(Exception e) {
  186. // ignore error, keep destroying the rest
  187. }
  188. }
  189. }
  190. _pool.clear();
  191. }
  192. synchronized public void close() throws Exception {
  193. clear();
  194. _pool = null;
  195. _factory = null;
  196. super.close();
  197. }
  198. /**
  199. * Create an object, and place it into the pool.
  200. * addObject() is useful for "pre-loading" a pool with idle objects.
  201. */
  202. public void addObject() throws Exception {
  203. Object obj = _factory.makeObject();
  204. synchronized(this) {
  205. _numActive++; // A little slimy - must do this because returnObject decrements it.
  206. this.returnObject(obj);
  207. }
  208. }
  209. synchronized public void setFactory(PoolableObjectFactory factory) throws IllegalStateException {
  210. assertOpen();
  211. if(0 < getNumActive()) {
  212. throw new IllegalStateException("Objects are already active");
  213. } else {
  214. clear();
  215. _factory = factory;
  216. }
  217. }
  218. /** The default cap on the number of "sleeping" instances in the pool. */
  219. protected static final int DEFAULT_MAX_SLEEPING = 8;
  220. /**
  221. * The default initial size of the pool
  222. * (this specifies the size of the container, it does not
  223. * cause the pool to be pre-populated.)
  224. */
  225. protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
  226. /** My pool. */
  227. protected Stack _pool = null;
  228. /** My {@link PoolableObjectFactory}. */
  229. protected PoolableObjectFactory _factory = null;
  230. /** The cap on the number of "sleeping" instances in the pool. */
  231. protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
  232. /** Number of object borrowed but not yet returned to the pool */
  233. protected int _numActive = 0;
  234. }