View Javadoc

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 }