1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbcp2.datasources;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.time.Duration;
23 import java.util.ArrayList;
24 import java.util.Hashtable;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.concurrent.ConcurrentHashMap;
29
30 import javax.naming.Context;
31 import javax.naming.Name;
32 import javax.naming.RefAddr;
33 import javax.naming.Reference;
34 import javax.naming.spi.ObjectFactory;
35
36 import org.apache.commons.dbcp2.ListException;
37 import org.apache.commons.dbcp2.Utils;
38
39
40
41
42
43
44 abstract class InstanceKeyDataSourceFactory implements ObjectFactory {
45
46 private static final Map<String, InstanceKeyDataSource> INSTANCE_MAP = new ConcurrentHashMap<>();
47
48
49
50
51
52
53
54
55
56
57 public static void closeAll() throws ListException {
58
59 final List<Throwable> exceptionList = new ArrayList<>(INSTANCE_MAP.size());
60 INSTANCE_MAP.entrySet().forEach(entry -> {
61
62 if (entry != null) {
63 @SuppressWarnings("resource")
64 final InstanceKeyDataSource value = entry.getValue();
65 Utils.close(value, exceptionList::add);
66 }
67 });
68 INSTANCE_MAP.clear();
69 if (!exceptionList.isEmpty()) {
70 throw new ListException("Could not close all InstanceKeyDataSource instances.", exceptionList);
71 }
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
88 ObjectInputStream in = null;
89 try {
90 in = new ObjectInputStream(new ByteArrayInputStream(data));
91 return in.readObject();
92 } finally {
93 Utils.closeQuietly(in);
94 }
95 }
96
97 static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
98 int max = 0;
99 for (final String s : INSTANCE_MAP.keySet()) {
100 if (s != null) {
101 try {
102 max = Math.max(max, Integer.parseInt(s));
103 } catch (final NumberFormatException ignored) {
104
105 }
106 }
107 }
108 final String instanceKey = String.valueOf(max + 1);
109
110
111 INSTANCE_MAP.put(instanceKey, ds);
112 return instanceKey;
113 }
114
115 static void removeInstance(final String key) {
116 if (key != null) {
117 INSTANCE_MAP.remove(key);
118 }
119 }
120
121 private Boolean booleanValueOf(RefAddr refAddr) {
122 return Boolean.valueOf(toString(refAddr));
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
139
140
141
142
143 @Override
144 public Object getObjectInstance(final Object refObj, final Name name, final Context context,
145 final Hashtable<?, ?> env) throws IOException, ClassNotFoundException {
146
147
148 Object obj = null;
149 if (refObj instanceof Reference) {
150 final Reference ref = (Reference) refObj;
151 if (isCorrectClass(ref.getClassName())) {
152 final RefAddr refAddr = ref.get("instanceKey");
153 if (hasContent(refAddr)) {
154
155 obj = INSTANCE_MAP.get(refAddr.getContent());
156 } else {
157
158
159
160 String key = null;
161 if (name != null) {
162 key = name.toString();
163 obj = INSTANCE_MAP.get(key);
164 }
165 if (obj == null) {
166 final InstanceKeyDataSource ds = getNewInstance(ref);
167 setCommonProperties(ref, ds);
168 obj = ds;
169 if (key != null) {
170 INSTANCE_MAP.put(key, ds);
171 }
172 }
173 }
174 }
175 }
176 return obj;
177 }
178
179 private boolean hasContent(final RefAddr refAddr) {
180 return refAddr != null && refAddr.getContent() != null;
181 }
182
183
184
185
186
187
188
189
190
191 protected abstract boolean isCorrectClass(String className);
192
193 boolean parseBoolean(final RefAddr refAddr) {
194 return Boolean.parseBoolean(toString(refAddr));
195 }
196
197 int parseInt(final RefAddr refAddr) {
198 return Integer.parseInt(toString(refAddr));
199 }
200
201 long parseLong(final RefAddr refAddr) {
202 return Long.parseLong(toString(refAddr));
203 }
204
205 private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds)
206 throws IOException, ClassNotFoundException {
207
208 RefAddr refAddr = ref.get("dataSourceName");
209 if (hasContent(refAddr)) {
210 ikds.setDataSourceName(toString(refAddr));
211 }
212
213 refAddr = ref.get("description");
214 if (hasContent(refAddr)) {
215 ikds.setDescription(toString(refAddr));
216 }
217
218 refAddr = ref.get("jndiEnvironment");
219 if (hasContent(refAddr)) {
220 final byte[] serialized = (byte[]) refAddr.getContent();
221 ikds.setJndiEnvironment((Properties) deserialize(serialized));
222 }
223
224 refAddr = ref.get("loginTimeout");
225 if (hasContent(refAddr)) {
226 ikds.setLoginTimeout(toDurationFromSeconds(refAddr));
227 }
228
229
230 refAddr = ref.get("blockWhenExhausted");
231 if (hasContent(refAddr)) {
232 ikds.setDefaultBlockWhenExhausted(parseBoolean(refAddr));
233 }
234
235 refAddr = ref.get("evictionPolicyClassName");
236 if (hasContent(refAddr)) {
237 ikds.setDefaultEvictionPolicyClassName(toString(refAddr));
238 }
239
240
241 refAddr = ref.get("lifo");
242 if (hasContent(refAddr)) {
243 ikds.setDefaultLifo(parseBoolean(refAddr));
244 }
245
246 refAddr = ref.get("maxIdlePerKey");
247 if (hasContent(refAddr)) {
248 ikds.setDefaultMaxIdle(parseInt(refAddr));
249 }
250
251 refAddr = ref.get("maxTotalPerKey");
252 if (hasContent(refAddr)) {
253 ikds.setDefaultMaxTotal(parseInt(refAddr));
254 }
255
256 refAddr = ref.get("maxWaitMillis");
257 if (hasContent(refAddr)) {
258 ikds.setDefaultMaxWait(toDurationFromMillis(refAddr));
259 }
260
261 refAddr = ref.get("minEvictableIdleTimeMillis");
262 if (hasContent(refAddr)) {
263 ikds.setDefaultMinEvictableIdle(toDurationFromMillis(refAddr));
264 }
265
266 refAddr = ref.get("minIdlePerKey");
267 if (hasContent(refAddr)) {
268 ikds.setDefaultMinIdle(parseInt(refAddr));
269 }
270
271 refAddr = ref.get("numTestsPerEvictionRun");
272 if (hasContent(refAddr)) {
273 ikds.setDefaultNumTestsPerEvictionRun(parseInt(refAddr));
274 }
275
276 refAddr = ref.get("softMinEvictableIdleTimeMillis");
277 if (hasContent(refAddr)) {
278 ikds.setDefaultSoftMinEvictableIdle(toDurationFromMillis(refAddr));
279 }
280
281 refAddr = ref.get("testOnCreate");
282 if (hasContent(refAddr)) {
283 ikds.setDefaultTestOnCreate(parseBoolean(refAddr));
284 }
285
286 refAddr = ref.get("testOnBorrow");
287 if (hasContent(refAddr)) {
288 ikds.setDefaultTestOnBorrow(parseBoolean(refAddr));
289 }
290
291 refAddr = ref.get("testOnReturn");
292 if (hasContent(refAddr)) {
293 ikds.setDefaultTestOnReturn(parseBoolean(refAddr));
294 }
295
296 refAddr = ref.get("testWhileIdle");
297 if (hasContent(refAddr)) {
298 ikds.setDefaultTestWhileIdle(parseBoolean(refAddr));
299 }
300
301 refAddr = ref.get("timeBetweenEvictionRunsMillis");
302 if (hasContent(refAddr)) {
303 ikds.setDefaultDurationBetweenEvictionRuns(toDurationFromMillis(refAddr));
304 }
305
306
307
308 refAddr = ref.get("validationQuery");
309 if (hasContent(refAddr)) {
310 ikds.setValidationQuery(toString(refAddr));
311 }
312
313 refAddr = ref.get("validationQueryTimeout");
314 if (hasContent(refAddr)) {
315 ikds.setValidationQueryTimeout(toDurationFromSeconds(refAddr));
316 }
317
318 refAddr = ref.get("rollbackAfterValidation");
319 if (hasContent(refAddr)) {
320 ikds.setRollbackAfterValidation(parseBoolean(refAddr));
321 }
322
323 refAddr = ref.get("maxConnLifetimeMillis");
324 if (hasContent(refAddr)) {
325 ikds.setMaxConnLifetime(toDurationFromMillis(refAddr));
326 }
327
328
329
330 refAddr = ref.get("defaultAutoCommit");
331 if (hasContent(refAddr)) {
332 ikds.setDefaultAutoCommit(booleanValueOf(refAddr));
333 }
334
335 refAddr = ref.get("defaultTransactionIsolation");
336 if (hasContent(refAddr)) {
337 ikds.setDefaultTransactionIsolation(parseInt(refAddr));
338 }
339
340 refAddr = ref.get("defaultReadOnly");
341 if (hasContent(refAddr)) {
342 ikds.setDefaultReadOnly(booleanValueOf(refAddr));
343 }
344 }
345
346 private Duration toDurationFromMillis(RefAddr refAddr) {
347 return Duration.ofMillis(parseLong(refAddr));
348 }
349
350 private Duration toDurationFromSeconds(RefAddr refAddr) {
351 return Duration.ofSeconds(parseInt(refAddr));
352 }
353
354 String toString(final RefAddr refAddr) {
355 return refAddr.getContent().toString();
356 }
357 }