1 /***
2 * CremeDriver.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 package org.jcreme.sql;
28
29 import java.sql.Connection;
30 import java.sql.Driver;
31 import java.sql.DriverManager;
32 import java.sql.DriverPropertyInfo;
33 import java.sql.SQLException;
34 import java.util.Enumeration;
35 import java.util.Hashtable;
36 import java.util.Iterator;
37
38 /***
39 * This driver enables to use ConnectionPools to avoid useless creation and
40 * close of Connections. It also wrapped the connections in a WrappedConnection
41 * that provide fine error reporting and logging.
42 *
43 * @author $Author: dbregeon $
44 * @version $Revision: 1.2 $
45 */
46 public class CremeDriver implements Driver {
47 protected static final int MAJOR_VERSION = 1;
48
49 protected static final int MINOR_VERSION = 0;
50
51 /***
52 * The pools associated to the various connection parameters.
53 */
54 private final Hashtable connectionPools = new Hashtable();
55
56 /***
57 * The minimum size for the pools in this driver.
58 */
59 private int minPoolSize = 0;
60
61 /***
62 * The maximum size for the pools in this driver.
63 */
64 private int maxPoolSize = 10;
65
66 /***
67 * The isolation level for the pools in this driver.
68 */
69 private IsolationLevel isolationLevel = IsolationLevel.READ_COMMITTED;
70
71 /***
72 * A flag that signals whether the Connections provided by this driver
73 * should be auto committed or not.
74 */
75 private boolean autoCommit = false;
76
77 /***
78 * Creates a new instance of PoolingDriver
79 *
80 * @param minPoolSize
81 * the minimum size for the pools in this Driver.
82 * @param maxPoolSize
83 * the maximum size for the pools in this Driver.
84 * @param isolationLevel
85 * the isolation level for the pools in this driver.
86 */
87 public CremeDriver(int minPoolSize, int maxPoolSize,
88 IsolationLevel isolationLevel) {
89 this.minPoolSize = minPoolSize;
90 this.maxPoolSize = maxPoolSize;
91 this.isolationLevel = isolationLevel;
92 }
93
94 /***
95 * Retrieves whether the driver thinks that it can open a connection to the
96 * given URL. Typically drivers will return <code>true</code> if they
97 * understand the subprotocol specified in the URL and <code>false</code>
98 * if they do not.
99 *
100 * @param url
101 * the URL of the database
102 * @return <code>true</code> if this driver understands the given URL;
103 * <code>false</code> otherwise
104 * @exception SQLException
105 * if a database access error occurs
106 *
107 */
108 public boolean acceptsURL(String url) throws SQLException {
109 Enumeration drivers = DriverManager.getDrivers();
110 boolean result = false;
111 while ((drivers.hasMoreElements()) && (!result)) {
112 result = ((Driver) drivers.nextElement()).acceptsURL(url);
113 }
114 return result;
115 }
116
117 /***
118 * Attempts to make a database connection to the given URL. The driver
119 * should return "null" if it realizes it is the wrong kind of driver to
120 * connect to the given URL. This will be common, as when the JDBC driver
121 * manager is asked to connect to a given URL it passes the URL to each
122 * loaded driver in turn.
123 *
124 * <P>
125 * The driver should throw an <code>SQLException</code> if it is the right
126 * driver to connect to the given URL but has trouble connecting to the
127 * database.
128 *
129 * <P>
130 * The <code>java.util.Properties</code> argument can be used to pass
131 * arbitrary string tag/value pairs as connection arguments. Normally at
132 * least "user" and "password" properties should be included in the
133 * <code>Properties</code> object.
134 *
135 * @param url
136 * the URL of the database to which to connect
137 * @param info
138 * a list of arbitrary string tag/value pairs as connection
139 * arguments. Normally at least a "user" and "password" property
140 * should be included.
141 * @return a <code>Connection</code> object that represents a connection
142 * to the URL
143 * @exception SQLException
144 * if a database access error occurs
145 *
146 */
147 public Connection connect(String url, java.util.Properties info)
148 throws SQLException {
149 ConnectionPool urlInfoPool = null;
150 Connection conn = null;
151 if ((url != null) && (info != null)) {
152 Hashtable urlPools = (Hashtable) this.connectionPools.get(url);
153 if (urlPools == null) {
154 urlPools = new Hashtable();
155 this.connectionPools.put(url, urlPools);
156 }
157 urlInfoPool = (ConnectionPool) urlPools.get(info);
158 if (urlInfoPool == null) {
159 urlInfoPool = new WrappedConnectionPool(this.minPoolSize,
160 this.maxPoolSize, url, info, this.isolationLevel);
161 urlPools.put(info, urlInfoPool);
162 }
163 }
164 if (urlInfoPool != null) {
165 conn = urlInfoPool.getConnection();
166 } else {
167 conn = DriverManager.getConnection(url, info);
168 }
169 return conn;
170 }
171
172 /***
173 * Retrieves the driver's major version number. Initially this should be 1.
174 *
175 * @return this driver's major version number
176 *
177 */
178 public int getMajorVersion() {
179 return MAJOR_VERSION;
180 }
181
182 /***
183 * Gets the driver's minor version number. Initially this should be 0.
184 *
185 * @return this driver's minor version number
186 *
187 */
188 public int getMinorVersion() {
189 return MINOR_VERSION;
190 }
191
192 /***
193 * Gets information about the possible properties for this driver.
194 * <P>
195 * The <code>getPropertyInfo</code> method is intended to allow a generic
196 * GUI tool to discover what properties it should prompt a human for in
197 * order to get enough information to connect to a database. Note that
198 * depending on the values the human has supplied so far, additional values
199 * may become necessary, so it may be necessary to iterate though several
200 * calls to the <code>getPropertyInfo</code> method.
201 *
202 * @param url
203 * the URL of the database to which to connect
204 * @param info
205 * a proposed list of tag/value pairs that will be sent on
206 * connect open
207 * @return an array of <code>DriverPropertyInfo</code> objects describing
208 * possible properties. This array may be an empty array if no
209 * properties are required.
210 * @exception SQLException
211 * if a database access error occurs
212 *
213 */
214 public DriverPropertyInfo[] getPropertyInfo(String url,
215 java.util.Properties info) {
216 return new DriverPropertyInfo[0];
217 }
218
219 /***
220 * Reports whether this driver is a genuine JDBC Compliant <sup><font
221 * size=-2>TM </font> </sup> driver. A driver may only report
222 * <code>true</code> here if it passes the JDBC compliance tests;
223 * otherwise it is required to return <code>false</code>.
224 * <P>
225 * JDBC compliance requires full support for the JDBC API and full support
226 * for SQL 92 Entry Level. It is expected that JDBC compliant drivers will
227 * be available for all the major commercial databases.
228 * <P>
229 * This method is not intended to encourage the development of non-JDBC
230 * compliant drivers, but is a recognition of the fact that some vendors are
231 * interested in using the JDBC API and framework for lightweight databases
232 * that do not support full database functionality, or for special databases
233 * such as document information retrieval where a SQL implementation may not
234 * be feasible.
235 *
236 * @return <code>true</code> if this driver is JDBC Compliant;
237 * <code>false</code> otherwise
238 *
239 */
240 public boolean jdbcCompliant() {
241 return false;
242 }
243
244 /***
245 *
246 * @param isolationLevel
247 * @throws SQLException
248 */
249 public void setTransactionIsolation(IsolationLevel isolationLevel)
250 throws SQLException {
251 SQLException exception = null;
252 synchronized (this.connectionPools) {
253 this.isolationLevel = isolationLevel;
254 Iterator urlPropertiesPools = this.connectionPools.values()
255 .iterator();
256 Iterator current = null;
257 while (urlPropertiesPools.hasNext()) {
258 current = ((Hashtable) urlPropertiesPools.next()).values()
259 .iterator();
260 while (current.hasNext()) {
261 try {
262 ((ConnectionPool) current.next())
263 .setTransactionIsolation(isolationLevel);
264 } catch (SQLException e) {
265 if (exception != null) {
266 e.setNextException(exception);
267 }
268 exception = e;
269 }
270 }
271 }
272 if (exception != null) {
273 throw exception;
274 }
275 }
276 }
277
278 /***
279 *
280 * @param minimumSize
281 * @throws SQLException
282 */
283 public void setMinimumSize(int minimumSize) throws SQLException {
284 SQLException exception = null;
285 synchronized (this.connectionPools) {
286 this.minPoolSize = minimumSize;
287 Iterator urlPropertiesPools = this.connectionPools.values()
288 .iterator();
289 Iterator current = null;
290 while (urlPropertiesPools.hasNext()) {
291 current = ((Hashtable) urlPropertiesPools.next()).values()
292 .iterator();
293 while (current.hasNext()) {
294 try {
295 ((ConnectionPool) current.next())
296 .setMinimumSize(this.minPoolSize);
297 } catch (SQLException e) {
298 if (exception != null) {
299 e.setNextException(exception);
300 }
301 exception = e;
302 }
303 }
304 }
305 if (exception != null) {
306 throw exception;
307 }
308 }
309 }
310
311 /***
312 *
313 * @param maximumSize
314 * @throws SQLException
315 */
316 public void setMaximumSize(int maximumSize) throws SQLException {
317 SQLException exception = null;
318 synchronized (this.connectionPools) {
319 this.maxPoolSize = maximumSize;
320 Iterator urlPropertiesPools = this.connectionPools.values()
321 .iterator();
322 Iterator current = null;
323 while (urlPropertiesPools.hasNext()) {
324 current = ((Hashtable) urlPropertiesPools.next()).values()
325 .iterator();
326 while (current.hasNext()) {
327 try {
328 ((ConnectionPool) current.next())
329 .setMaximumSize(this.maxPoolSize);
330 } catch (SQLException e) {
331 if (exception != null) {
332 e.setNextException(exception);
333 }
334 exception = e;
335 }
336 }
337 }
338 if (exception != null) {
339 throw exception;
340 }
341 }
342 }
343
344 /***
345 *
346 * @param autoCommit
347 * @throws SQLException
348 */
349 public void setAutoCommit(boolean autoCommit) throws SQLException {
350 SQLException exception = null;
351 synchronized (this.connectionPools) {
352 this.autoCommit = autoCommit;
353 Iterator urlPropertiesPools = this.connectionPools.values()
354 .iterator();
355 Iterator current = null;
356 while (urlPropertiesPools.hasNext()) {
357 current = ((Hashtable) urlPropertiesPools.next()).values()
358 .iterator();
359 while (current.hasNext()) {
360 try {
361 ((ConnectionPool) current.next())
362 .setAutoCommit(this.autoCommit);
363 } catch (SQLException e) {
364 if (exception != null) {
365 e.setNextException(exception);
366 }
367 exception = e;
368 }
369 }
370 }
371 if (exception != null) {
372 throw exception;
373 }
374 }
375 }
376 }