1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.dbcp;
19
20 import java.sql.Connection;
21 import java.sql.Statement;
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import org.apache.commons.pool.KeyedObjectPool;
25 import org.apache.commons.pool.KeyedObjectPoolFactory;
26 import org.apache.commons.pool.PoolableObjectFactory;
27 import org.apache.commons.pool.ObjectPool;
28
29 /**
30 * A {@link PoolableObjectFactory} that creates
31 * {@link PoolableConnection}s.
32 *
33 * @author Rodney Waldhoff
34 * @author Glenn L. Nielsen
35 * @author James House
36 * @author Dirk Verbeeck
37 * @version $Revision: 479187 $ $Date: 2006-11-25 13:13:45 -0700 (Sat, 25 Nov 2006) $
38 */
39 public class PoolableConnectionFactory implements PoolableObjectFactory {
40 /**
41 * Create a new <tt>PoolableConnectionFactory</tt>.
42 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
43 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
44 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
45 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
46 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
47 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
48 */
49 public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit) {
50 _connFactory = connFactory;
51 _pool = pool;
52 _pool.setFactory(this);
53 _stmtPoolFactory = stmtPoolFactory;
54 _validationQuery = validationQuery;
55 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
56 _defaultAutoCommit = defaultAutoCommit;
57 }
58
59 /**
60 * Create a new <tt>PoolableConnectionFactory</tt>.
61 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
62 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
63 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
64 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
65 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
66 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
67 * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
68 */
69 public PoolableConnectionFactory(ConnectionFactory connFactory, ObjectPool pool, KeyedObjectPoolFactory stmtPoolFactory, String validationQuery, boolean defaultReadOnly, boolean defaultAutoCommit, int defaultTransactionIsolation) {
70 _connFactory = connFactory;
71 _pool = pool;
72 _pool.setFactory(this);
73 _stmtPoolFactory = stmtPoolFactory;
74 _validationQuery = validationQuery;
75 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
76 _defaultAutoCommit = defaultAutoCommit;
77 _defaultTransactionIsolation = defaultTransactionIsolation;
78 }
79
80 /**
81 * Create a new <tt>PoolableConnectionFactory</tt>.
82 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
83 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
84 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
85 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
86 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
87 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
88 * @param config the AbandonedConfig if tracing SQL objects
89 * @deprecated AbandonedConfig is now deprecated.
90 */
91 public PoolableConnectionFactory(
92 ConnectionFactory connFactory,
93 ObjectPool pool,
94 KeyedObjectPoolFactory stmtPoolFactory,
95 String validationQuery,
96 boolean defaultReadOnly,
97 boolean defaultAutoCommit,
98 AbandonedConfig config) {
99
100 _connFactory = connFactory;
101 _pool = pool;
102 _config = config;
103 _pool.setFactory(this);
104 _stmtPoolFactory = stmtPoolFactory;
105 _validationQuery = validationQuery;
106 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
107 _defaultAutoCommit = defaultAutoCommit;
108 }
109
110 /**
111 * Create a new <tt>PoolableConnectionFactory</tt>.
112 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
113 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
114 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
115 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
116 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
117 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
118 * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
119 * @param config the AbandonedConfig if tracing SQL objects
120 * @deprecated AbandonedConfig is now deprecated.
121 */
122 public PoolableConnectionFactory(
123 ConnectionFactory connFactory,
124 ObjectPool pool,
125 KeyedObjectPoolFactory stmtPoolFactory,
126 String validationQuery,
127 boolean defaultReadOnly,
128 boolean defaultAutoCommit,
129 int defaultTransactionIsolation,
130 AbandonedConfig config) {
131
132 _connFactory = connFactory;
133 _pool = pool;
134 _config = config;
135 _pool.setFactory(this);
136 _stmtPoolFactory = stmtPoolFactory;
137 _validationQuery = validationQuery;
138 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
139 _defaultAutoCommit = defaultAutoCommit;
140 _defaultTransactionIsolation = defaultTransactionIsolation;
141 }
142
143 /**
144 * Create a new <tt>PoolableConnectionFactory</tt>.
145 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
146 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
147 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
148 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
149 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
150 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
151 * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
152 * @param defaultCatalog the default "catalog" setting for returned {@link Connection}s
153 * @param config the AbandonedConfig if tracing SQL objects
154 * @deprecated AbandonedConfig is now deprecated.
155 */
156 public PoolableConnectionFactory(
157 ConnectionFactory connFactory,
158 ObjectPool pool,
159 KeyedObjectPoolFactory stmtPoolFactory,
160 String validationQuery,
161 boolean defaultReadOnly,
162 boolean defaultAutoCommit,
163 int defaultTransactionIsolation,
164 String defaultCatalog,
165 AbandonedConfig config) {
166
167 _connFactory = connFactory;
168 _pool = pool;
169 _config = config;
170 _pool.setFactory(this);
171 _stmtPoolFactory = stmtPoolFactory;
172 _validationQuery = validationQuery;
173 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
174 _defaultAutoCommit = defaultAutoCommit;
175 _defaultTransactionIsolation = defaultTransactionIsolation;
176 _defaultCatalog = defaultCatalog;
177 }
178
179 /**
180 * Create a new <tt>PoolableConnectionFactory</tt>.
181 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
182 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
183 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s, or <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling
184 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s. Should return at least one row. Using <tt>null</tt> turns off validation.
185 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
186 * @param defaultAutoCommit the default "auto commit" setting for returned {@link Connection}s
187 * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
188 * @param defaultCatalog the default "catalog" setting for returned {@link Connection}s
189 * @param config the AbandonedConfig if tracing SQL objects
190 */
191 public PoolableConnectionFactory(
192 ConnectionFactory connFactory,
193 ObjectPool pool,
194 KeyedObjectPoolFactory stmtPoolFactory,
195 String validationQuery,
196 Boolean defaultReadOnly,
197 boolean defaultAutoCommit,
198 int defaultTransactionIsolation,
199 String defaultCatalog,
200 AbandonedConfig config) {
201
202 _connFactory = connFactory;
203 _pool = pool;
204 _config = config;
205 _pool.setFactory(this);
206 _stmtPoolFactory = stmtPoolFactory;
207 _validationQuery = validationQuery;
208 _defaultReadOnly = defaultReadOnly;
209 _defaultAutoCommit = defaultAutoCommit;
210 _defaultTransactionIsolation = defaultTransactionIsolation;
211 _defaultCatalog = defaultCatalog;
212 }
213
214 /**
215 * Sets the {@link ConnectionFactory} from which to obtain base {@link Connection}s.
216 * @param connFactory the {@link ConnectionFactory} from which to obtain base {@link Connection}s
217 */
218 synchronized public void setConnectionFactory(ConnectionFactory connFactory) {
219 _connFactory = connFactory;
220 }
221
222 /**
223 * Sets the query I use to {@link #validateObject validate} {@link Connection}s.
224 * Should return at least one row.
225 * Using <tt>null</tt> turns off validation.
226 * @param validationQuery a query to use to {@link #validateObject validate} {@link Connection}s.
227 */
228 synchronized public void setValidationQuery(String validationQuery) {
229 _validationQuery = validationQuery;
230 }
231
232 /**
233 * Sets the {@link ObjectPool} in which to pool {@link Connection}s.
234 * @param pool the {@link ObjectPool} in which to pool those {@link Connection}s
235 */
236 synchronized public void setPool(ObjectPool pool) {
237 if(null != _pool && pool != _pool) {
238 try {
239 _pool.close();
240 } catch(Exception e) {
241 // ignored !?!
242 }
243 }
244 _pool = pool;
245 }
246
247 public ObjectPool getPool() {
248 return _pool;
249 }
250
251 /**
252 * Sets the {@link KeyedObjectPoolFactory} I use to create {@link KeyedObjectPool}s
253 * for pooling {@link java.sql.PreparedStatement}s.
254 * Set to <tt>null</tt> to disable {@link java.sql.PreparedStatement} pooling.
255 * @param stmtPoolFactory the {@link KeyedObjectPoolFactory} to use to create {@link KeyedObjectPool}s for pooling {@link java.sql.PreparedStatement}s
256 */
257 synchronized public void setStatementPoolFactory(KeyedObjectPoolFactory stmtPoolFactory) {
258 _stmtPoolFactory = stmtPoolFactory;
259 }
260
261 /**
262 * Sets the default "read only" setting for borrowed {@link Connection}s
263 * @param defaultReadOnly the default "read only" setting for borrowed {@link Connection}s
264 */
265 public void setDefaultReadOnly(boolean defaultReadOnly) {
266 _defaultReadOnly = defaultReadOnly ? Boolean.TRUE : Boolean.FALSE;
267 }
268
269 /**
270 * Sets the default "auto commit" setting for borrowed {@link Connection}s
271 * @param defaultAutoCommit the default "auto commit" setting for borrowed {@link Connection}s
272 */
273 public void setDefaultAutoCommit(boolean defaultAutoCommit) {
274 _defaultAutoCommit = defaultAutoCommit;
275 }
276
277 /**
278 * Sets the default "Transaction Isolation" setting for borrowed {@link Connection}s
279 * @param defaultTransactionIsolation the default "Transaction Isolation" setting for returned {@link Connection}s
280 */
281 public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
282 _defaultTransactionIsolation = defaultTransactionIsolation;
283 }
284
285 /**
286 * Sets the default "catalog" setting for borrowed {@link Connection}s
287 * @param defaultCatalog the default "catalog" setting for borrowed {@link Connection}s
288 */
289 public void setDefaultCatalog(String defaultCatalog) {
290 _defaultCatalog = defaultCatalog;
291 }
292
293 synchronized public Object makeObject() throws Exception {
294 Connection conn = _connFactory.createConnection();
295 if(null != _stmtPoolFactory) {
296 KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
297 conn = new PoolingConnection(conn,stmtpool);
298 stmtpool.setFactory((PoolingConnection)conn);
299 }
300 return new PoolableConnection(conn,_pool,_config);
301 }
302
303 public void destroyObject(Object obj) throws Exception {
304 if(obj instanceof PoolableConnection) {
305 ((PoolableConnection)obj).reallyClose();
306 }
307 }
308
309 public boolean validateObject(Object obj) {
310 if(obj instanceof Connection) {
311 try {
312 validateConnection((Connection) obj);
313 return true;
314 } catch(Exception e) {
315 return false;
316 }
317 } else {
318 return false;
319 }
320 }
321
322 public void validateConnection(Connection conn) throws SQLException {
323 String query = _validationQuery;
324 if(conn.isClosed()) {
325 throw new SQLException("validateConnection: connection closed");
326 }
327 if(null != query) {
328 Statement stmt = null;
329 ResultSet rset = null;
330 try {
331 stmt = conn.createStatement();
332 rset = stmt.executeQuery(query);
333 if(!rset.next()) {
334 throw new SQLException("validationQuery didn't return a row");
335 }
336 } finally {
337 if (rset != null) {
338 try {
339 rset.close();
340 } catch(Exception t) {
341 // ignored
342 }
343 }
344 if (stmt != null) {
345 try {
346 stmt.close();
347 } catch(Exception t) {
348 // ignored
349 }
350 }
351 }
352 }
353 }
354
355 public void passivateObject(Object obj) throws Exception {
356 if(obj instanceof Connection) {
357 Connection conn = (Connection)obj;
358 if(!conn.getAutoCommit() && !conn.isReadOnly()) {
359 conn.rollback();
360 }
361 conn.clearWarnings();
362 if(!conn.getAutoCommit()) {
363 conn.setAutoCommit(true);
364 }
365 }
366 if(obj instanceof DelegatingConnection) {
367 ((DelegatingConnection)obj).passivate();
368 }
369 }
370
371 public void activateObject(Object obj) throws Exception {
372 if(obj instanceof DelegatingConnection) {
373 ((DelegatingConnection)obj).activate();
374 }
375 if(obj instanceof Connection) {
376 Connection conn = (Connection)obj;
377 if (conn.getAutoCommit() != _defaultAutoCommit) {
378 conn.setAutoCommit(_defaultAutoCommit);
379 }
380 if ((_defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION)
381 && (conn.getTransactionIsolation() !=
382 _defaultTransactionIsolation)) {
383 conn.setTransactionIsolation(_defaultTransactionIsolation);
384 }
385 if ((_defaultReadOnly != null) &&
386 (conn.isReadOnly() != _defaultReadOnly.booleanValue())) {
387 conn.setReadOnly(_defaultReadOnly.booleanValue());
388 }
389 if ((_defaultCatalog != null) &&
390 (!_defaultCatalog.equals(conn.getCatalog()))) {
391 conn.setCatalog(_defaultCatalog);
392 }
393 }
394 }
395
396 protected ConnectionFactory _connFactory = null;
397 protected String _validationQuery = null;
398 protected ObjectPool _pool = null;
399 protected KeyedObjectPoolFactory _stmtPoolFactory = null;
400 protected Boolean _defaultReadOnly = null;
401 protected boolean _defaultAutoCommit = true;
402 protected int _defaultTransactionIsolation = UNKNOWN_TRANSACTIONISOLATION;
403 protected String _defaultCatalog;
404
405 /**
406 * @deprecated AbandonedConfig is now deprecated.
407 */
408 protected AbandonedConfig _config = null;
409
410 /**
411 * Internal constant to indicate the level is not set.
412 */
413 static final int UNKNOWN_TRANSACTIONISOLATION = -1;
414 }