1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool2;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.commons.pool2.impl.DefaultPooledObject;
24
25
26
27
28
29
30
31
32
33
34 public class WaiterFactory<K> implements PooledObjectFactory<Waiter>, KeyedPooledObjectFactory<K, Waiter> {
35
36
37 private static final Integer ZERO = Integer.valueOf(0);
38
39
40 private static final Integer ONE = Integer.valueOf(1);
41
42
43 private final long activateLatency;
44
45
46 private final long destroyLatency;
47
48
49 private final long makeLatency;
50
51
52 private final long passivateLatency;
53
54
55 private final long validateLatency;
56
57
58 private final long waiterLatency;
59
60
61 private final double passivateInvalidationProbability;
62
63
64 private long activeCount;
65
66
67 private final Map<K, Integer> activeCounts = new HashMap<>();
68
69
70 private final long maxActive;
71
72
73 private final long maxActivePerKey;
74
75 public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
76 final long waiterLatency) {
77 this(activateLatency, destroyLatency, makeLatency, passivateLatency, validateLatency, waiterLatency, Long.MAX_VALUE, Long.MAX_VALUE, 0);
78 }
79
80 public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
81 final long waiterLatency, final long maxActive) {
82 this(activateLatency, destroyLatency, makeLatency, passivateLatency, validateLatency, waiterLatency, maxActive, Long.MAX_VALUE, 0);
83 }
84
85 public WaiterFactory(final long activateLatency, final long destroyLatency, final long makeLatency, final long passivateLatency, final long validateLatency,
86 final long waiterLatency, final long maxActive, final long maxActivePerKey, final double passivateInvalidationProbability) {
87 this.activateLatency = activateLatency;
88 this.destroyLatency = destroyLatency;
89 this.makeLatency = makeLatency;
90 this.passivateLatency = passivateLatency;
91 this.validateLatency = validateLatency;
92 this.waiterLatency = waiterLatency;
93 this.maxActive = maxActive;
94 this.maxActivePerKey = maxActivePerKey;
95 this.passivateInvalidationProbability = passivateInvalidationProbability;
96 }
97
98 @Override
99 public void activateObject(final K key, final PooledObject<Waiter> obj) {
100 activateObject(obj);
101 }
102
103 @Override
104 public void activateObject(final PooledObject<Waiter> obj) {
105 doWait(activateLatency);
106 obj.getObject().setActive(true);
107 }
108
109 @Override
110 public void destroyObject(final K key, final PooledObject<Waiter> obj) {
111 destroyObject(obj);
112 synchronized (this) {
113 activeCounts.computeIfPresent(key, (k, v) -> Integer.valueOf(v.intValue() - 1));
114 }
115 }
116
117 @Override
118 public void destroyObject(final PooledObject<Waiter> obj) {
119 doWait(destroyLatency);
120 obj.getObject().setValid(false);
121 obj.getObject().setActive(false);
122
123 synchronized (this) {
124 activeCount--;
125 }
126 }
127
128 protected void doWait(final long latency) {
129 if (latency == 0) {
130 return;
131 }
132 Waiter.sleepQuietly(latency);
133 }
134
135
136
137
138 public synchronized long getMaxActive() {
139 return maxActive;
140 }
141
142 @Override
143 public PooledObject<Waiter> makeObject() {
144
145 synchronized (this) {
146 if (activeCount >= maxActive) {
147 throw new IllegalStateException("Too many active instances: " +
148 activeCount + " in circulation with maxActive = " + maxActive);
149 }
150 activeCount++;
151 }
152 doWait(makeLatency);
153 return new DefaultPooledObject<>(new Waiter(false, true, waiterLatency));
154 }
155
156 @Override
157 public PooledObject<Waiter> makeObject(final K key) {
158 synchronized (this) {
159 activeCounts.merge(key, ONE, (v1, v2) -> {
160 if (v1.intValue() >= maxActivePerKey) {
161 throw new IllegalStateException("Too many active " +
162 "instances for key = " + key + ": " + v1.intValue() +
163 " in circulation " + "with maxActivePerKey = " +
164 maxActivePerKey);
165 }
166 return Integer.valueOf(v1.intValue() + 1);
167 });
168 }
169 return makeObject();
170 }
171
172 @Override
173 public void passivateObject(final K key, final PooledObject<Waiter> obj) {
174 passivateObject(obj);
175 }
176
177 @Override
178 public void passivateObject(final PooledObject<Waiter> obj) {
179 obj.getObject().setActive(false);
180 doWait(passivateLatency);
181 if (Math.random() < passivateInvalidationProbability) {
182 obj.getObject().setValid(false);
183 }
184 }
185
186 public synchronized void reset() {
187 activeCount = 0;
188 if (activeCounts.isEmpty()) {
189 return;
190 }
191 for (K key : activeCounts.keySet()) {
192 activeCounts.put(key, ZERO);
193 }
194 }
195
196 @Override
197 public boolean validateObject(final K key, final PooledObject<Waiter> obj) {
198 return validateObject(obj);
199 }
200
201 @Override
202 public boolean validateObject(final PooledObject<Waiter> obj) {
203 doWait(validateLatency);
204 return obj.getObject().isValid();
205 }
206
207 }