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