1 /***
2 * WrappedConnectionPool.java
3 *
4 * This file is part of the creme library.
5 * The creme library intends to ease the development effort of large
6 * applications by providing easy to use support classes.
7 *
8 * Copyright (C) 2002 Denis Bregeon
9 *
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * contact information: dbregeon@sourceforge.net
26 */
27
28 package org.jcreme.sql;
29
30 import java.sql.Connection;
31 import java.sql.DriverManager;
32 import java.sql.SQLException;
33 import java.util.Collection;
34 import java.util.Iterator;
35 import java.util.Properties;
36
37 import org.jcreme.pool.ObjectPool;
38
39 /***
40 * This implementation of the ConnectionPool interface enables to pool
41 * WrappedConnection instances.
42 *
43 * @author $Author: dbregeon $
44 * @version $Revision: 1.2 $
45 */
46 public class WrappedConnectionPool extends ObjectPool implements ConnectionPool {
47 /***
48 * The URL of the database to which the Connections of this ConnectionPool
49 * are connected.
50 */
51 private String url = null;
52
53 /***
54 * The properties passed to the driver to create new database connections.
55 */
56 private Properties driverProperties = null;
57
58 /***
59 * The ConnectionPool's Connection's default transaction isolation level.
60 */
61 private IsolationLevel defaultIsolation = null;
62
63 /***
64 * The default AutoCommit setting for WrappedConnections.
65 */
66 private Boolean defaultAutoCommit = null;
67
68 /***
69 *
70 * @param minSize
71 * @param maxSize
72 * @param url
73 * @param properties
74 * @param isolationLevel
75 */
76 public WrappedConnectionPool(int minSize, int maxSize, String url,
77 Properties properties, IsolationLevel isolationLevel) {
78 super(minSize, maxSize);
79 this.driverProperties = properties;
80 this.url = url;
81 this.defaultIsolation = isolationLevel;
82 }
83
84 /***
85 * This method provides a Connection to the database from the pool. The
86 * Connection may be created on the spot or already exists. The pool
87 * guarantees that the Connection was released by its previous user, not
88 * that the previous user actually ceased to use it.
89 *
90 * @return a ready to use Connection.
91 * @throws SQLException
92 * if a problem occurs while trying to get a Connection.
93 */
94 public Connection getConnection() throws SQLException {
95 try {
96 return (Connection) getObject();
97 } catch (Exception e) {
98 throw getSQLException(e);
99 }
100 }
101
102 /***
103 * This method provides a Connection to the database from the pool. The
104 * Connection may be created on the spot or already exists. The pool
105 * guarantees that the Connection was released by its previous user, not
106 * that the previous user actually ceased to use it. If the waiting period
107 * expires and no connection was available, it will return null.
108 *
109 * @param waitingPeriod
110 * the number of milliseconds for which the method call will be
111 * blocked waiting for an available connection.
112 * @return a ready to use Connection or null if the waiting period expired.
113 * @throws SQLException
114 * if a problem occurs while trying to get a Connection.
115 */
116 public Connection getConnection(int waitingPeriod) throws SQLException {
117 try {
118 return (Connection) getObject(waitingPeriod);
119 } catch (Exception e) {
120 throw getSQLException(e);
121 }
122 }
123
124 private final SQLException getSQLException(Exception e) {
125 SQLException ex = null;
126 if (e instanceof SQLException) {
127 ex = (SQLException) e;
128 } else {
129 ex = new SQLException(e.getMessage());
130 }
131 return ex;
132 }
133
134 /***
135 * This method enables to return a Connection to the pool. Nothing is done
136 * if the Connection does not belong to the pool. The Connection should not
137 * be used after being released.
138 *
139 * @param conn
140 * the Connection to be returned.
141 * @throws SQLException
142 * if a problem occurs while trying to release a Connection.
143 */
144 public void releaseConnection(Connection conn) throws SQLException {
145 try {
146 releaseObject(conn);
147 } catch (Exception e) {
148 throw getSQLException(e);
149 }
150 }
151
152 /***
153 * This method signals the pool it should close all the available
154 * connections. This method usually is called when exiting an application.
155 * Connections provided by this pool should not be used after the close
156 * method has been called.
157 *
158 * @throws SQLException
159 * if an error occurs while closing the pool.
160 */
161 public void close() throws SQLException {
162 SQLException exception = null;
163 Collection freeObjects = getFreeObjects();
164 synchronized (freeObjects) {
165 Iterator iter = freeObjects.iterator();
166 WrappedConnection current = null;
167 while (iter.hasNext()) {
168 current = (WrappedConnection) iter.next();
169 current.setParentPool(null);
170 try {
171 current.close();
172 } catch (SQLException e) {
173 e.setNextException(exception);
174 exception = e;
175 }
176 iter.remove();
177 }
178 }
179 Collection usedObjects = getUsedObjects();
180 synchronized (usedObjects) {
181 Iterator iter = usedObjects.iterator();
182 WrappedConnection current = null;
183 while (iter.hasNext()) {
184 current = (WrappedConnection) iter.next();
185 current.setParentPool(null);
186 try {
187 current.close();
188 } catch (SQLException e) {
189 e.setNextException(exception);
190 exception = e;
191 }
192 iter.remove();
193 }
194 }
195 if (exception != null) {
196 throw exception;
197 }
198 }
199
200 /***
201 * This method enabled to build a new object when needed. Any parameters
202 * needed should be provided by the actual ObjectPool implementation.
203 *
204 * @return an new object for the pool.
205 */
206 protected final Object buildNew() {
207 WrappedConnection newConnection = null;
208 try {
209 WrappedConnection.getInstance(DriverManager.getConnection(this.url,
210 this.driverProperties));
211 if (this.defaultAutoCommit != null) {
212 newConnection.setAutoCommit(this.defaultAutoCommit
213 .booleanValue());
214 }
215 if (this.defaultIsolation != null) {
216 newConnection.setTransactionIsolation(this.defaultIsolation
217 .getValue().intValue());
218 }
219 newConnection.setParentPool(this);
220 newConnection.setExceptionHandler(SQLExceptionHandlerFactory
221 .getInstance().buildSQLExceptionHandler(
222 newConnection.getMetaData()
223 .getDatabaseProductName()));
224 } catch (SQLException e) {
225 e.printStackTrace();
226 if (newConnection != null) {
227 try {
228 newConnection.close();
229 } catch (SQLException ex) {
230 ex.printStackTrace();
231 }
232 newConnection = null;
233 }
234 }
235 return newConnection;
236 }
237
238 /***
239 * This method enables to change the isolation level used in the
240 * ConnectionPool.
241 *
242 * @param isolationLevel
243 * the new isolation level to apply.
244 * @throws SQLException
245 * if a problem occurs while changing the isolation level.
246 */
247 public void setTransactionIsolation(IsolationLevel isolationLevel)
248 throws SQLException {
249 this.defaultIsolation = isolationLevel;
250 SQLException exception = null;
251 Collection freeObjects = getFreeObjects();
252 synchronized (freeObjects) {
253 Iterator iter = freeObjects.iterator();
254 WrappedConnection current = null;
255 while (iter.hasNext()) {
256 current = (WrappedConnection) iter.next();
257 try {
258 current.setTransactionIsolation(this.defaultIsolation
259 .getValue().intValue());
260 } catch (SQLException e) {
261 e.setNextException(exception);
262 exception = e;
263 }
264 }
265 }
266 Collection usedObjects = getUsedObjects();
267 synchronized (usedObjects) {
268 Iterator iter = usedObjects.iterator();
269 WrappedConnection current = null;
270 while (iter.hasNext()) {
271 current = (WrappedConnection) iter.next();
272 try {
273 current.setTransactionIsolation(this.defaultIsolation
274 .getValue().intValue());
275 } catch (SQLException e) {
276 e.setNextException(exception);
277 exception = e;
278 }
279 }
280 }
281 if (exception != null) {
282 throw exception;
283 }
284 }
285
286 /***
287 * This method enables to change the commit policy of the ConnectionPool.
288 *
289 * @param autoCommit
290 * the new commit policy to apply.
291 * @throws SQLException
292 * if a problem occurs while changing the commit policy.
293 *
294 */
295 public void setAutoCommit(boolean autoCommit) throws SQLException {
296 this.defaultAutoCommit = new Boolean(autoCommit);
297 SQLException exception = null;
298 Collection freeObjects = getFreeObjects();
299 synchronized (freeObjects) {
300 Iterator iter = freeObjects.iterator();
301 WrappedConnection current = null;
302 while (iter.hasNext()) {
303 current = (WrappedConnection) iter.next();
304 try {
305 current.setAutoCommit(autoCommit);
306 } catch (SQLException e) {
307 e.setNextException(exception);
308 exception = e;
309 }
310 }
311 }
312 Collection usedObjects = getUsedObjects();
313 synchronized (usedObjects) {
314 Iterator iter = usedObjects.iterator();
315 WrappedConnection current = null;
316 while (iter.hasNext()) {
317 current = (WrappedConnection) iter.next();
318 try {
319 current.setAutoCommit(autoCommit);
320 } catch (SQLException e) {
321 e.setNextException(exception);
322 exception = e;
323 }
324 }
325 }
326 if (exception != null) {
327 throw exception;
328 }
329 }
330
331 /***
332 * This method enabled to remove an old object when needed. It enables to
333 * free resources when an object is permanently removed from the ObjectPool.
334 *
335 * @param obj
336 * the object to remove.
337 */
338 protected void removeOld(Object obj) {
339 try {
340 WrappedConnection conn = (WrappedConnection) obj;
341 conn.setParentPool(null);
342 conn.close();
343 } catch (SQLException e) {
344 e.printStackTrace();
345 }
346 }
347 }