1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.jcreme.pool;
29
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Stack;
33
34 /***
35 * This class represents a pool of objects. That is a number of objects that are
36 * shared in an application as a limited resource. This is a lazy
37 * implementation, it builds the pooled objects as needed through the use of the
38 * buildObject method. This class must be derived to provide an actual
39 * implementation of the buildNew method.
40 *
41 * @author $Author: dbregeon $
42 * @version $Revision: 1.3 $
43 */
44 public abstract class ObjectPool {
45 /***
46 * The initial size of the pool. It might be reused to reinitialize the
47 * pool.
48 */
49 private int minSize = 0;
50
51 /***
52 * The maximum size of the pool.
53 */
54 private int maxSize = 1;
55
56 /***
57 * The pool objects that are not currently in use.
58 */
59 private final Stack freeObjects = new Stack();
60
61 /***
62 * The pool objects that are currently in use.
63 */
64 private final ArrayList usedObjects = new ArrayList();
65
66 /***
67 * Creates a new instance of ObjectPool If the minSize is greater than the
68 * maxSize, it is reduced to the maxSize. The constructor builds as many
69 * objects as minSize through the initPool method.
70 *
71 * @param minSize
72 * the initial size of the pool.
73 * @param maxSize
74 * the maximum size of the pool.
75 */
76 protected ObjectPool(int minSize, int maxSize) {
77 if (minSize > maxSize) {
78 minSize = maxSize;
79 }
80 this.minSize = minSize;
81 this.maxSize = maxSize;
82 initPool();
83 }
84
85 /***
86 * This method makes as many calls to buildNew as minSize. It is used to
87 * populate the pool.
88 */
89 protected final void initPool() {
90 Object current = null;
91 for (int i = 0; ((i < this.minSize) && (i < this.maxSize)); i++) {
92 current = buildNew();
93 if (current != null) {
94 this.freeObjects.add(current);
95 }
96 }
97 }
98
99 /***
100 * This method enabled to build a new object when needed. Any parameters
101 * needed should be provided by the actual ObjectPool implementation.
102 *
103 * @return a newly constructed pool element.
104 */
105 protected abstract Object buildNew();
106
107 /***
108 * This method enabled to remove an old object when needed. It enables to
109 * free resources when an object is permanently removed from the ObjectPool.
110 *
111 * @param obj
112 * the object to remove.
113 */
114 protected abstract void removeOld(final Object obj);
115
116 /***
117 * This method enables to retrieve an object from the freeObjects stack. If
118 * the stack is empty and the maxSize is not exceeded, it builds a new
119 * object using the buildNew method. If the stack is empty and the maxSize
120 * was reached, it waits for an object to be released. The call is then
121 * blocked indefinitely.
122 *
123 * @return an object freshly removed from the freeObjects stack.
124 * @throws InterruptedException
125 * if the wait for a free object was interrupted.
126 */
127 protected Object getObjectFromFree() throws InterruptedException {
128 Object result = null;
129 synchronized (this.freeObjects) {
130 if (this.freeObjects.isEmpty()) {
131 if (this.usedObjects.size() < this.maxSize) {
132 result = buildNew();
133 } else {
134 this.freeObjects.wait();
135 }
136 } else {
137 result = this.freeObjects.pop();
138 }
139 }
140 return result;
141 }
142
143 /***
144 * This method enables to retrieve an object from the freeObjects stack. If
145 * the stack is empty and the maxSize is not exceeded, it builds a new
146 * object using the buildNew method. If the stack is empty and the maxSize
147 * was reached, it waits for an object to be released for the given time.
148 *
149 * @param waitingPeriod
150 * the time the method is allowed to wait for an object from the
151 * pool.
152 * @return an object freshly removed from the freeObjects stack.
153 * @throws InterruptedException
154 * if the wait for a free object was interrupted.
155 */
156 protected Object getObjectFromFree(final int waitingPeriod)
157 throws InterruptedException {
158 Object result = null;
159 synchronized (this.freeObjects) {
160 if (this.freeObjects.isEmpty()) {
161 if (this.usedObjects.size() < this.maxSize) {
162 result = buildNew();
163 } else if (waitingPeriod > 0) {
164 this.freeObjects.wait(waitingPeriod);
165 }
166 } else {
167 result = this.freeObjects.pop();
168 }
169 }
170 return result;
171 }
172
173 /***
174 * This method enables to remove an object from the usedObjects list.
175 *
176 * @param o
177 * the object to remove from the usedObjects.
178 * @return the object actually removed from the list. This is to prevent
179 * objects from being introduced in the ObjectPool while they may
180 * have been created outside.
181 */
182 protected Object getObjectFromUsed(final Object o) {
183 synchronized (this.usedObjects) {
184
185
186 return this.usedObjects.remove(this.usedObjects.indexOf(o));
187 }
188 }
189
190 /***
191 * This method enabled to return an object to the freeObjects stack.
192 *
193 * @param o
194 * the object to return to the stack.
195 */
196 protected void putInFreeObjects(final Object o) {
197 if (o != null) {
198 synchronized (this.freeObjects) {
199 this.freeObjects.push(o);
200 this.freeObjects.notifyAll();
201 }
202 }
203 }
204
205 /***
206 * This method enabled to register an object to the usedObjects list.
207 *
208 * @param o
209 * the object to add to the usedObjects list.
210 */
211 protected void putInUsedObjects(final Object o) {
212 if (o != null) {
213 synchronized (this.usedObjects) {
214 this.usedObjects.add(o);
215 }
216 }
217 }
218
219 /***
220 * This method enables to get an object from the ObjectPool. It will block
221 * indefinitely while waiting for a free object.
222 *
223 * @return an object from the ObjectPool. Null if the method was
224 * interrupted.
225 */
226 protected Object getObject() {
227 Object result = null;
228 try {
229 while (result == null) {
230 result = getObjectFromFree();
231 }
232 putInUsedObjects(result);
233 } catch (InterruptedException e) {
234 e.printStackTrace();
235 }
236 return result;
237 }
238
239 /***
240 * This method enables to get an object from the ObjectPool. It will block
241 * for the given time while waiting for a free object.
242 *
243 * @param waitingPeriod
244 * the number of millisecond the method will wait for an object
245 * to be freed.
246 * @return an object from the ObjectPool. Null if the method was
247 * interrupted.
248 */
249 protected Object getObject(final int waitingPeriod) {
250 Object result = null;
251 int loopCount = 0;
252 int wait = waitingPeriod;
253 try {
254 while ((result == null) && (loopCount < 2)) {
255 if (loopCount > 0) {
256 wait = 0;
257 }
258 result = getObjectFromFree(wait);
259 loopCount++;
260 }
261 putInUsedObjects(result);
262 } catch (InterruptedException e) {
263 e.printStackTrace();
264 }
265 return result;
266 }
267
268 /***
269 * This method enables to return an object to the ObjectPool.
270 *
271 * @param obj
272 * the object to release.
273 */
274 protected void releaseObject(final Object obj) {
275 final Object pooledObject = getObjectFromUsed(obj);
276
277
278 if (this.usedObjects.size() + this.freeObjects.size() < this.maxSize) {
279 putInFreeObjects(pooledObject);
280 } else {
281 removeOld(obj);
282 }
283 }
284
285 /***
286 * Gives access to the freeObjects Stack.
287 *
288 * @return the freeObjects.
289 */
290 protected Collection getFreeObjects() {
291 return this.freeObjects;
292 }
293
294 /***
295 * Gives access to the usedObjects Vector.
296 *
297 * @return the usedObjects.
298 */
299 protected Collection getUsedObjects() {
300 return this.usedObjects;
301 }
302
303 /***
304 * This method enables to change the minimum size of the ConnectionPool.
305 * Sizes lesser than 0 will be ignored.
306 *
307 * @param minSize
308 * the new minimum size to apply.
309 *
310 */
311 public void setMinimumSize(final int minSize) {
312 if (minSize >= 0) {
313 this.minSize = minSize;
314 if (this.freeObjects.size() + this.usedObjects.size() < this.minSize) {
315 synchronized (this.freeObjects) {
316 Object current = null;
317 for (int i = this.freeObjects.size()
318 + this.usedObjects.size(); ((i < this.minSize) && (i < this.maxSize)); i++) {
319 current = buildNew();
320
321 if (current != null) {
322 this.freeObjects.add(current);
323 }
324 }
325 }
326 }
327 }
328 }
329
330 /***
331 * This method enables to change the maximum size of the ConnectionPool. If
332 * the size is lower than the minimum size, it will be ignored.
333 *
334 * @param maxSize
335 * the new maximum size to apply.
336 *
337 */
338 public void setMaximumSize(final int maxSize) {
339 if (maxSize >= this.minSize) {
340 this.maxSize = maxSize;
341 synchronized (this.freeObjects) {
342 Object current = null;
343 while (this.usedObjects.size() + this.freeObjects.size() > this.maxSize) {
344 current = this.freeObjects.lastElement();
345 this.freeObjects.remove(current);
346 removeOld(current);
347 }
348 }
349 }
350 }
351 }