1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.pool2.impl;
18
19 import java.io.PrintWriter;
20 import java.time.Clock;
21 import java.time.Duration;
22 import java.time.Instant;
23 import java.util.Deque;
24
25 import org.apache.commons.pool2.PooledObject;
26 import org.apache.commons.pool2.PooledObjectState;
27 import org.apache.commons.pool2.TrackedUse;
28
29
30
31
32
33
34
35
36
37
38
39 public class DefaultPooledObject<T> implements PooledObject<T> {
40
41 private final T object;
42 private PooledObjectState state = PooledObjectState.IDLE;
43 private final Clock systemClock = Clock.systemUTC();
44 private final Instant createInstant = now();
45
46 private volatile Instant lastBorrowInstant = createInstant;
47 private volatile Instant lastUseInstant = createInstant;
48 private volatile Instant lastReturnInstant = createInstant;
49 private volatile boolean logAbandoned;
50 private volatile CallStack borrowedBy = NoOpCallStack.INSTANCE;
51 private volatile CallStack usedBy = NoOpCallStack.INSTANCE;
52 private volatile long borrowedCount;
53
54
55
56
57
58
59
60 public DefaultPooledObject(final T object) {
61 this.object = object;
62 }
63
64
65
66
67
68
69 @Override
70 public synchronized boolean allocate() {
71 if (state == PooledObjectState.IDLE) {
72 state = PooledObjectState.ALLOCATED;
73 lastBorrowInstant = now();
74 lastUseInstant = lastBorrowInstant;
75 borrowedCount++;
76 if (logAbandoned) {
77 borrowedBy.fillInStackTrace();
78 }
79 return true;
80 }
81 if (state == PooledObjectState.EVICTION) {
82
83 state = PooledObjectState.EVICTION_RETURN_TO_HEAD;
84 }
85
86
87 return false;
88 }
89
90 @Override
91 public int compareTo(final PooledObject<T> other) {
92 final int compareTo = getLastReturnInstant().compareTo(other.getLastReturnInstant());
93 if (compareTo == 0) {
94
95
96
97
98 return System.identityHashCode(this) - System.identityHashCode(other);
99 }
100 return compareTo;
101 }
102
103
104
105
106
107
108
109
110
111 @Override
112 public synchronized boolean deallocate() {
113 if (state == PooledObjectState.ALLOCATED || state == PooledObjectState.RETURNING) {
114 state = PooledObjectState.IDLE;
115 lastReturnInstant = now();
116 borrowedBy.clear();
117 return true;
118 }
119
120 return false;
121 }
122
123 @Override
124 public synchronized boolean endEvictionTest(
125 final Deque<PooledObject<T>> idleQueue) {
126 if (state == PooledObjectState.EVICTION) {
127 state = PooledObjectState.IDLE;
128 return true;
129 }
130 if (state == PooledObjectState.EVICTION_RETURN_TO_HEAD) {
131 state = PooledObjectState.IDLE;
132 idleQueue.offerFirst(this);
133 }
134
135 return false;
136 }
137
138 @Override
139 public long getActiveTimeMillis() {
140 return getActiveDuration().toMillis();
141 }
142
143
144
145
146
147
148 @Override
149 public long getBorrowedCount() {
150 return borrowedCount;
151 }
152
153 @Override
154 public Instant getCreateInstant() {
155 return createInstant;
156 }
157
158 @Override
159 public long getCreateTime() {
160 return createInstant.toEpochMilli();
161 }
162
163 @Override
164 public Duration getIdleDuration() {
165
166
167
168 final Duration elapsed = Duration.between(lastReturnInstant, now());
169 return elapsed.isNegative() ? Duration.ZERO : elapsed;
170 }
171
172 @Override
173 public Duration getIdleTime() {
174 return getIdleDuration();
175 }
176
177 @Override
178 public long getIdleTimeMillis() {
179 return getIdleDuration().toMillis();
180 }
181
182 @Override
183 public Instant getLastBorrowInstant() {
184 return lastBorrowInstant;
185 }
186
187 @Override
188 public long getLastBorrowTime() {
189 return lastBorrowInstant.toEpochMilli();
190 }
191
192 @Override
193 public Instant getLastReturnInstant() {
194 return lastReturnInstant;
195 }
196
197 @Override
198 public long getLastReturnTime() {
199 return lastReturnInstant.toEpochMilli();
200 }
201
202
203
204
205
206
207
208
209
210
211 @Override
212 public Instant getLastUsedInstant() {
213 if (object instanceof TrackedUse) {
214 return PoolImplUtils.max(((TrackedUse) object).getLastUsedInstant(), lastUseInstant);
215 }
216 return lastUseInstant;
217 }
218
219
220
221
222
223
224
225
226
227
228 @Override
229 public long getLastUsedTime() {
230 return getLastUsedInstant().toEpochMilli();
231 }
232
233 @Override
234 public T getObject() {
235 return object;
236 }
237
238
239
240
241
242 @Override
243 public synchronized PooledObjectState getState() {
244 return state;
245 }
246
247
248
249
250 @Override
251 public synchronized void invalidate() {
252 state = PooledObjectState.INVALID;
253 }
254
255
256
257
258 @Override
259 public synchronized void markAbandoned() {
260 state = PooledObjectState.ABANDONED;
261 }
262
263
264
265
266 @Override
267 public synchronized void markReturning() {
268 state = PooledObjectState.RETURNING;
269 }
270
271
272
273
274
275
276 private Instant now() {
277 return systemClock.instant();
278 }
279
280 @Override
281 public void printStackTrace(final PrintWriter writer) {
282 boolean written = borrowedBy.printStackTrace(writer);
283 written |= usedBy.printStackTrace(writer);
284 if (written) {
285 writer.flush();
286 }
287 }
288
289 @Override
290 public void setLogAbandoned(final boolean logAbandoned) {
291 this.logAbandoned = logAbandoned;
292 }
293
294
295
296
297
298
299
300
301
302
303
304 @Override
305 public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
306 borrowedBy = CallStackUtils.newCallStack("'Pooled object created' " +
307 "yyyy-MM-dd HH:mm:ss Z 'by the following code has not been returned to the pool:'",
308 true, requireFullStackTrace);
309 usedBy = CallStackUtils.newCallStack("The last code to use this object was:",
310 false, requireFullStackTrace);
311 }
312
313 @Override
314 public synchronized boolean startEvictionTest() {
315 if (state == PooledObjectState.IDLE) {
316 state = PooledObjectState.EVICTION;
317 return true;
318 }
319 return false;
320 }
321
322 @Override
323 public String toString() {
324 final StringBuilder result = new StringBuilder();
325 result.append("Object: ");
326 result.append(object.toString());
327 result.append(", State: ");
328 synchronized (this) {
329 result.append(state.toString());
330 }
331 return result.toString();
332
333 }
334
335 @Override
336 public void use() {
337 lastUseInstant = now();
338 usedBy.fillInStackTrace();
339 }
340
341 }