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.IOException;
20 import java.io.ObjectInputStream;
21 import java.sql.Connection;
22 import java.sql.SQLException;
23
24 import javax.naming.NamingException;
25 import javax.naming.Reference;
26 import javax.naming.StringRefAddr;
27 import javax.sql.ConnectionPoolDataSource;
28 import javax.sql.DataSource;
29
30 import org.apache.commons.dbcp2.PoolableConnection;
31 import org.apache.commons.pool2.KeyedObjectPool;
32 import org.apache.commons.pool2.KeyedPooledObjectFactory;
33 import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
34 import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class SharedPoolDataSource extends InstanceKeyDataSource {
54
55 private static final long serialVersionUID = -1458539734480586454L;
56
57
58
59
60 private volatile int maxTotal = GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
61
62
63
64
65 private transient KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> pool;
66
67
68
69
70 private transient KeyedCPDSConnectionFactory factory;
71
72
73
74
75 public SharedPoolDataSource() {
76
77 }
78
79
80
81
82 @Override
83 public void close() throws SQLException {
84 if (pool != null) {
85 pool.close();
86 }
87 InstanceKeyDataSourceFactory.removeInstance(getInstanceKey());
88 }
89
90 @Override
91 protected PooledConnectionManager getConnectionManager(final UserPassKey userPassKey) {
92 return factory;
93 }
94
95
96
97
98
99
100 public int getMaxTotal() {
101 return this.maxTotal;
102 }
103
104
105
106
107
108
109 public int getNumActive() {
110 return pool == null ? 0 : pool.getNumActive();
111 }
112
113
114
115
116
117
118 public int getNumIdle() {
119 return pool == null ? 0 : pool.getNumIdle();
120 }
121
122 @Override
123 protected PooledConnectionAndInfo getPooledConnectionAndInfo(final String userName, final String userPassword)
124 throws SQLException {
125
126 synchronized (this) {
127 if (pool == null) {
128 try {
129 registerPool(userName, userPassword);
130 } catch (final NamingException e) {
131 throw new SQLException("registerPool failed", e);
132 }
133 }
134 }
135
136 try {
137 return pool.borrowObject(new UserPassKey(userName, userPassword));
138 } catch (final Exception e) {
139 throw new SQLException("Could not retrieve connection info from pool", e);
140 }
141 }
142
143
144
145
146 @Override
147 public Reference getReference() throws NamingException {
148 final Reference ref = new Reference(getClass().getName(), SharedPoolDataSourceFactory.class.getName(), null);
149 ref.add(new StringRefAddr("instanceKey", getInstanceKey()));
150 return ref;
151 }
152
153
154
155
156
157
158
159
160 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
161 in.defaultReadObject();
162 this.pool = readObjectImpl();
163 }
164
165 private KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> readObjectImpl() throws IOException, ClassNotFoundException {
166 try {
167 return ((SharedPoolDataSource) new SharedPoolDataSourceFactory().getObjectInstance(getReference(), null, null, null)).pool;
168 } catch (final NamingException e) {
169 throw new IOException("NamingException: " + e);
170 }
171 }
172
173 private void registerPool(final String userName, final String password) throws NamingException, SQLException {
174
175 final ConnectionPoolDataSource cpds = testCPDS(userName, password);
176
177
178 factory = new KeyedCPDSConnectionFactory(cpds, getValidationQuery(), getValidationQueryTimeoutDuration(), isRollbackAfterValidation());
179 factory.setMaxConn(getMaxConnDuration());
180
181 final GenericKeyedObjectPoolConfig<PooledConnectionAndInfo> config = new GenericKeyedObjectPoolConfig<>();
182 config.setBlockWhenExhausted(getDefaultBlockWhenExhausted());
183 config.setEvictionPolicyClassName(getDefaultEvictionPolicyClassName());
184 config.setLifo(getDefaultLifo());
185 config.setMaxIdlePerKey(getDefaultMaxIdle());
186 config.setMaxTotal(getMaxTotal());
187 config.setMaxTotalPerKey(getDefaultMaxTotal());
188 config.setMaxWait(getDefaultMaxWait());
189 config.setMinEvictableIdleDuration(getDefaultMinEvictableIdleDuration());
190 config.setMinIdlePerKey(getDefaultMinIdle());
191 config.setNumTestsPerEvictionRun(getDefaultNumTestsPerEvictionRun());
192 config.setSoftMinEvictableIdleDuration(getDefaultSoftMinEvictableIdleDuration());
193 config.setTestOnCreate(getDefaultTestOnCreate());
194 config.setTestOnBorrow(getDefaultTestOnBorrow());
195 config.setTestOnReturn(getDefaultTestOnReturn());
196 config.setTestWhileIdle(getDefaultTestWhileIdle());
197 config.setTimeBetweenEvictionRuns(getDefaultDurationBetweenEvictionRuns());
198
199 final KeyedObjectPool<UserPassKey, PooledConnectionAndInfo> tmpPool = new GenericKeyedObjectPool<>(factory, config);
200 factory.setPool(tmpPool);
201 pool = tmpPool;
202 }
203
204
205
206
207
208
209
210 public void setMaxTotal(final int maxTotal) {
211 assertInitializationAllowed();
212 this.maxTotal = maxTotal;
213 }
214
215 @Override
216 protected void setupDefaults(final Connection connection, final String userName) throws SQLException {
217 final Boolean defaultAutoCommit = isDefaultAutoCommit();
218 if (defaultAutoCommit != null && connection.getAutoCommit() != defaultAutoCommit) {
219 connection.setAutoCommit(defaultAutoCommit);
220 }
221
222 final int defaultTransactionIsolation = getDefaultTransactionIsolation();
223 if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
224 connection.setTransactionIsolation(defaultTransactionIsolation);
225 }
226
227 final Boolean defaultReadOnly = isDefaultReadOnly();
228 if (defaultReadOnly != null && connection.isReadOnly() != defaultReadOnly) {
229 connection.setReadOnly(defaultReadOnly);
230 }
231 }
232
233 @Override
234 protected void toStringFields(final StringBuilder builder) {
235 super.toStringFields(builder);
236 builder.append(", maxTotal=");
237 builder.append(maxTotal);
238 }
239 }