View Javadoc

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 }