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 protected static final Object deserialize(final byte[] data) throws IOException, ClassNotFoundException {
87 ObjectInputStream in = null;
88 try {
89 in = new ObjectInputStream(new ByteArrayInputStream(data));
90 return in.readObject();
91 } finally {
92 Utils.closeQuietly(in);
93 }
94 }
95
96 static synchronized String registerNewInstance(final InstanceKeyDataSource ds) {
97 int max = 0;
98 for (final String s : INSTANCE_MAP.keySet()) {
99 if (s != null) {
100 try {
101 max = Math.max(max, Integer.parseInt(s));
102 } catch (final NumberFormatException ignored) {
103
104 }
105 }
106 }
107 final String instanceKey = String.valueOf(max + 1);
108
109
110 INSTANCE_MAP.put(instanceKey, ds);
111 return instanceKey;
112 }
113
114 static void removeInstance(final String key) {
115 if (key != null) {
116 INSTANCE_MAP.remove(key);
117 }
118 }
119
120 private Boolean booleanValueOf(final RefAddr refAddr) {
121 return Boolean.valueOf(toString(refAddr));
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136 protected abstract InstanceKeyDataSource getNewInstance(Reference ref) throws IOException, ClassNotFoundException;
137
138
139
140
141 @Override
142 public Object getObjectInstance(final Object refObj, final Name name, final Context context,
143 final Hashtable<?, ?> env) throws IOException, ClassNotFoundException {
144
145
146 Object obj = null;
147 if (refObj instanceof Reference) {
148 final Reference ref = (Reference) refObj;
149 if (isCorrectClass(ref.getClassName())) {
150 final RefAddr refAddr = ref.get("instanceKey");
151 if (hasContent(refAddr)) {
152
153 obj = INSTANCE_MAP.get(refAddr.getContent());
154 } else {
155
156
157
158 String key = null;
159 if (name != null) {
160 key = name.toString();
161 obj = INSTANCE_MAP.get(key);
162 }
163 if (obj == null) {
164 final InstanceKeyDataSource ds = getNewInstance(ref);
165 setCommonProperties(ref, ds);
166 obj = ds;
167 if (key != null) {
168 INSTANCE_MAP.put(key, ds);
169 }
170 }
171 }
172 }
173 }
174 return obj;
175 }
176
177 private boolean hasContent(final RefAddr refAddr) {
178 return refAddr != null && refAddr.getContent() != null;
179 }
180
181
182
183
184
185
186
187
188
189 protected abstract boolean isCorrectClass(String className);
190
191 boolean parseBoolean(final RefAddr refAddr) {
192 return Boolean.parseBoolean(toString(refAddr));
193 }
194
195 int parseInt(final RefAddr refAddr) {
196 return Integer.parseInt(toString(refAddr));
197 }
198
199 long parseLong(final RefAddr refAddr) {
200 return Long.parseLong(toString(refAddr));
201 }
202
203 private void setCommonProperties(final Reference ref, final InstanceKeyDataSource ikds)
204 throws IOException, ClassNotFoundException {
205
206 RefAddr refAddr = ref.get("dataSourceName");
207 if (hasContent(refAddr)) {
208 ikds.setDataSourceName(toString(refAddr));
209 }
210
211 refAddr = ref.get("description");
212 if (hasContent(refAddr)) {
213 ikds.setDescription(toString(refAddr));
214 }
215
216 refAddr = ref.get("jndiEnvironment");
217 if (hasContent(refAddr)) {
218 final byte[] serialized = (byte[]) refAddr.getContent();
219 ikds.setJndiEnvironment((Properties) deserialize(serialized));
220 }
221
222 refAddr = ref.get("loginTimeout");
223 if (hasContent(refAddr)) {
224 ikds.setLoginTimeout(toDurationFromSeconds(refAddr));
225 }
226
227
228 refAddr = ref.get("blockWhenExhausted");
229 if (hasContent(refAddr)) {
230 ikds.setDefaultBlockWhenExhausted(parseBoolean(refAddr));
231 }
232
233 refAddr = ref.get("evictionPolicyClassName");
234 if (hasContent(refAddr)) {
235 ikds.setDefaultEvictionPolicyClassName(toString(refAddr));
236 }
237
238
239 refAddr = ref.get("lifo");
240 if (hasContent(refAddr)) {
241 ikds.setDefaultLifo(parseBoolean(refAddr));
242 }
243
244 refAddr = ref.get("maxIdlePerKey");
245 if (hasContent(refAddr)) {
246 ikds.setDefaultMaxIdle(parseInt(refAddr));
247 }
248
249 refAddr = ref.get("maxTotalPerKey");
250 if (hasContent(refAddr)) {
251 ikds.setDefaultMaxTotal(parseInt(refAddr));
252 }
253
254 refAddr = ref.get("maxWaitMillis");
255 if (hasContent(refAddr)) {
256 ikds.setDefaultMaxWait(toDurationFromMillis(refAddr));
257 }
258
259 refAddr = ref.get("minEvictableIdleTimeMillis");
260 if (hasContent(refAddr)) {
261 ikds.setDefaultMinEvictableIdle(toDurationFromMillis(refAddr));
262 }
263
264 refAddr = ref.get("minIdlePerKey");
265 if (hasContent(refAddr)) {
266 ikds.setDefaultMinIdle(parseInt(refAddr));
267 }
268
269 refAddr = ref.get("numTestsPerEvictionRun");
270 if (hasContent(refAddr)) {
271 ikds.setDefaultNumTestsPerEvictionRun(parseInt(refAddr));
272 }
273
274 refAddr = ref.get("softMinEvictableIdleTimeMillis");
275 if (hasContent(refAddr)) {
276 ikds.setDefaultSoftMinEvictableIdle(toDurationFromMillis(refAddr));
277 }
278
279 refAddr = ref.get("testOnCreate");
280 if (hasContent(refAddr)) {
281 ikds.setDefaultTestOnCreate(parseBoolean(refAddr));
282 }
283
284 refAddr = ref.get("testOnBorrow");
285 if (hasContent(refAddr)) {
286 ikds.setDefaultTestOnBorrow(parseBoolean(refAddr));
287 }
288
289 refAddr = ref.get("testOnReturn");
290 if (hasContent(refAddr)) {
291 ikds.setDefaultTestOnReturn(parseBoolean(refAddr));
292 }
293
294 refAddr = ref.get("testWhileIdle");
295 if (hasContent(refAddr)) {
296 ikds.setDefaultTestWhileIdle(parseBoolean(refAddr));
297 }
298
299 refAddr = ref.get("timeBetweenEvictionRunsMillis");
300 if (hasContent(refAddr)) {
301 ikds.setDefaultDurationBetweenEvictionRuns(toDurationFromMillis(refAddr));
302 }
303
304
305
306 refAddr = ref.get("validationQuery");
307 if (hasContent(refAddr)) {
308 ikds.setValidationQuery(toString(refAddr));
309 }
310
311 refAddr = ref.get("validationQueryTimeout");
312 if (hasContent(refAddr)) {
313 ikds.setValidationQueryTimeout(toDurationFromSeconds(refAddr));
314 }
315
316 refAddr = ref.get("rollbackAfterValidation");
317 if (hasContent(refAddr)) {
318 ikds.setRollbackAfterValidation(parseBoolean(refAddr));
319 }
320
321 refAddr = ref.get("maxConnLifetimeMillis");
322 if (hasContent(refAddr)) {
323 ikds.setMaxConnLifetime(toDurationFromMillis(refAddr));
324 }
325
326
327
328 refAddr = ref.get("defaultAutoCommit");
329 if (hasContent(refAddr)) {
330 ikds.setDefaultAutoCommit(booleanValueOf(refAddr));
331 }
332
333 refAddr = ref.get("defaultTransactionIsolation");
334 if (hasContent(refAddr)) {
335 ikds.setDefaultTransactionIsolation(parseInt(refAddr));
336 }
337
338 refAddr = ref.get("defaultReadOnly");
339 if (hasContent(refAddr)) {
340 ikds.setDefaultReadOnly(booleanValueOf(refAddr));
341 }
342 }
343
344 private Duration toDurationFromMillis(final RefAddr refAddr) {
345 return Duration.ofMillis(parseLong(refAddr));
346 }
347
348 private Duration toDurationFromSeconds(final RefAddr refAddr) {
349 return Duration.ofSeconds(parseInt(refAddr));
350 }
351
352 String toString(final RefAddr refAddr) {
353 return refAddr.getContent().toString();
354 }
355 }