1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.util;
19
20 import java.util.Stack;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 /**
26 * A general purpose pooling class.
27 *
28 * @author Dave Bristor
29 */
30 public class Pool {
31
32 private final Stack stack = new Stack();
33
34
35 private final int size;
36
37
38 private int count = 0;
39
40 /** Number of millis to wait for a free entry
41 * Currently fixed; might be made configurable in future.
42 */
43 private int waitMillis = 1000;
44
45 /** Number of times to wait for a free entry
46 * Currently fixed; might be made configurable in future.
47 */
48 private int waitNumber = 5;
49
50 /** I18N */
51 private final static I18NHelper msg = I18NHelper.getInstance("org.apache.jdo.util.Bundle");
52
53
54 static final Log test = LogFactory.getFactory().getInstance(
55 "org.apache.jdo.util");
56
57 /**
58 * Constructs a pool that will limit the number of objects which it can
59 * contain.
60 * @param size The maximum number of items that can be put into the pool.
61 */
62 public Pool(int size) {
63 this.size = size;
64 }
65
66 /**
67 * Puts the given object into the pool, if there the pool has fewer than
68 * the number of elements specifed when created. If the pool is full,
69 * blocks until an element is removed.
70 * @param o Object to be put in the pool.
71 * @throws InterruptedException
72 */
73 public synchronized void put(Object o) throws InterruptedException {
74 boolean debug = test.isDebugEnabled();
75
76 if (debug) {
77 test.debug("Pool.put: " + o);
78 }
79
80 if (count > size || count < 0) {
81 if (debug) {
82 test.debug("Pool: count " + count +
83 " out of range 0-" + size);
84 }
85 throw new RuntimeException(
86 msg.msg(
87 "EXC_CountOutOfRange",
88 new Integer(count).toString(),
89 new Integer(size).toString()));
90 }
91
92 if (stack.contains(o)) {
93 if (debug) {
94 test.debug("Pool: duplicate object");
95 }
96 throw new RuntimeException(
97 msg.msg(
98 "EXC_DuplicateObject", o));
99 }
100
101 while (count == size) {
102 if (debug) {
103 test.debug("Pool.put: block");
104 }
105 wait();
106 }
107 stack.push(o);
108 ++count;
109 notify();
110 }
111
112 /**
113 * Gets an object from the pool, if one is available. If an object is not
114 * available, waits until one is. The waiting is governed by two
115 * variables, which are currently fixed: waitMillis and waitNumber.
116 * If no object is available from the pool within (waitNumber) times
117 * (waitMillis) milliseconds, then a RuntimeException is thrown.
118 * In future, the waitMillis and waitNumber should be configurable.
119 * @return An object from the pool.
120 */
121 public synchronized Object get() throws InterruptedException {
122 boolean debug = test.isDebugEnabled();
123 Object rc = null;
124
125 if (count > size || count < 0) {
126 if (debug) {
127 test.debug("Pool: count " + count +
128 " out of range 0-" + size);
129 }
130 throw new RuntimeException(
131 msg.msg(
132 "EXC_CountOutOfRange",
133 new Integer(count).toString(),
134 new Integer(size).toString()));
135 }
136
137 int timeouts = 0;
138 while (count == 0 && timeouts++ < waitNumber) {
139 if (debug) {
140 test.debug("Pool.get: block " + timeouts);
141 }
142 wait(waitMillis);
143 }
144 if (timeouts >= waitNumber) {
145 throw new RuntimeException(
146 msg.msg("EXC_PoolGetTimeout"));
147 }
148 rc = stack.pop();
149 --count;
150 notify();
151 if (debug) {
152 test.debug("Pool.get: " + rc);
153 }
154 return rc;
155 }
156 }