Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/xpn/xwiki/store/DBCPConnectionProvider.java


1   /**
2    * ===================================================================
3    *
4    * Copyright (c) 2003,2004 Ludovic Dubost, All rights reserved.
5    *
6    * This program is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public License
8    * as published by the Free Software Foundation; either version 2
9    * of the License, or (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU Lesser General Public License for more details, published at 
15   * http://www.gnu.org/copyleft/lesser.html or in lesser.txt in the
16   * root folder of this distribution.
17  
18   * Created by
19   * User: Ludovic Dubost
20   * Date: 10 mai 2005
21   * Time: 23:37:10
22  
23    * Copyright 2004 The Apache Software Foundation.
24    *
25    * Licensed under the Apache License, Version 2.0 (the "License");
26    * you may not use this file except in compliance with the License.
27    * You may obtain a copy of the License at
28    *
29    *      http://www.apache.org/licenses/LICENSE-2.0
30    *
31    * Unless required by applicable law or agreed to in writing, software
32    * distributed under the License is distributed on an "AS IS" BASIS,
33    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34    * See the License for the specific language governing permissions and
35    * limitations under the License.
36  
37   */
38  
39  package com.xpn.xwiki.store;
40  
41  import java.io.PrintWriter;
42  import java.io.StringWriter;
43  import java.sql.Connection;
44  import java.sql.SQLException;
45  import java.util.Iterator;
46  import java.util.Properties;
47  
48  import org.apache.commons.dbcp.BasicDataSource;
49  import org.apache.commons.dbcp.BasicDataSourceFactory;
50  import org.apache.commons.logging.Log;
51  import org.apache.commons.logging.LogFactory;
52  import org.hibernate.HibernateException;
53  import org.hibernate.connection.ConnectionProvider;
54  import org.hibernate.connection.ConnectionProviderFactory;
55  import org.hibernate.cfg.Environment;
56  
57  /**
58   * <p>A connection provider that uses an Apache commons DBCP connection pool.</p>
59   *
60   * <p>To use this connection provider set:<br>
61   * <code>hibernate.connection.provider_class&nbsp;org.hibernate.connection.DBCPConnectionProvider</code></p>
62   *
63   * <pre>Supported Hibernate properties:
64   *   hibernate.connection.driver_class
65   *   hibernate.connection.url
66   *   hibernate.connection.username
67   *   hibernate.connection.password
68   *   hibernate.connection.isolation
69   *   hibernate.connection.autocommit
70   *   hibernate.connection.pool_size
71   *   hibernate.connection (JDBC driver properties)</pre>
72   * <br>
73   * All DBCP properties are also supported by using the hibernate.dbcp prefix.
74   * A complete list can be found on the DBCP configuration page:
75   * <a href="http://jakarta.apache.org/commons/dbcp/configuration.html">http://jakarta.apache.org/commons/dbcp/configuration.html</a>.
76   * <br>
77   * <pre>Example:
78   *   hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider
79   *   hibernate.connection.driver_class org.hsqldb.jdbcDriver
80   *   hibernate.connection.username sa
81   *   hibernate.connection.password
82   *   hibernate.connection.url jdbc:hsqldb:test
83   *   hibernate.connection.pool_size 20
84   *   hibernate.dbcp.initialSize 10
85   *   hibernate.dbcp.maxWait 3000
86   *   hibernate.dbcp.validationQuery select 1 from dual</pre>
87   *
88   * <p>More information about configuring/using DBCP can be found on the
89   * <a href="http://jakarta.apache.org/commons/dbcp/">DBCP website</a>.
90   * There you will also find the DBCP wiki, mailing lists, issue tracking
91   * and other support facilities</p>
92   *
93   * @see org.hibernate.connection.ConnectionProvider
94   * @author Dirk Verbeeck
95   */
96  public class DBCPConnectionProvider implements ConnectionProvider {
97  
98      private static final Log log = LogFactory.getLog(DBCPConnectionProvider.class);
99      private static final String PREFIX = "hibernate.dbcp.";
100     private BasicDataSource ds;
101 
102     // Old Environment property for backward-compatibility (property removed in Hibernate3)
103     private static final String DBCP_PS_MAXACTIVE = "hibernate.dbcp.ps.maxActive";
104 
105     // Property doesn't exists in Hibernate2
106     private static final String AUTOCOMMIT = "hibernate.connection.autocommit";
107 
108     public void configure(Properties props) throws HibernateException {
109         try {
110             log.debug("Configure DBCPConnectionProvider");
111 
112             // DBCP properties used to create the BasicDataSource
113             Properties dbcpProperties = new Properties();
114 
115             // DriverClass & url
116             String jdbcDriverClass = props.getProperty(Environment.DRIVER);
117             String jdbcUrl = props.getProperty(Environment.URL);
118             dbcpProperties.put("driverClassName", jdbcDriverClass);
119             dbcpProperties.put("url", jdbcUrl);
120 
121             // Username / password
122             String username = props.getProperty(Environment.USER);
123             String password = props.getProperty(Environment.PASS);
124             dbcpProperties.put("username", username);
125             dbcpProperties.put("password", password);
126 
127             // Isolation level
128             String isolationLevel = props.getProperty(Environment.ISOLATION);
129             if ((isolationLevel != null) && (isolationLevel.trim().length() > 0)) {
130                 dbcpProperties.put("defaultTransactionIsolation", isolationLevel);
131             }
132 
133             // Turn off autocommit (unless autocommit property is set)
134             String autocommit = props.getProperty(AUTOCOMMIT);
135             if ((autocommit != null) && (autocommit.trim().length() > 0)) {
136                 dbcpProperties.put("defaultAutoCommit", autocommit);
137             } else {
138                 dbcpProperties.put("defaultAutoCommit", String.valueOf(Boolean.FALSE));
139             }
140 
141             // Pool size
142             String poolSize = props.getProperty(Environment.POOL_SIZE);
143             if ((poolSize != null) && (poolSize.trim().length() > 0)
144                 && (Integer.parseInt(poolSize) > 0))  {
145                 dbcpProperties.put("maxActive", poolSize);
146             }
147 
148             // Copy all "driver" properties into "connectionProperties"
149             Properties driverProps = ConnectionProviderFactory.getConnectionProperties(props);
150             if (driverProps.size() > 0) {
151                 StringBuffer connectionProperties = new StringBuffer();
152                 for (Iterator iter = driverProps.keySet().iterator(); iter.hasNext();) {
153                     String key = (String) iter.next();
154                     String value = driverProps.getProperty(key);
155                     connectionProperties.append(key).append('=').append(value);
156                     if (iter.hasNext()) {
157                         connectionProperties.append(';');
158                     }
159                 }
160                 dbcpProperties.put("connectionProperties", connectionProperties.toString());
161             }
162 
163             // Copy all DBCP properties removing the prefix
164             for (Iterator iter = props.keySet().iterator() ; iter.hasNext() ;) {
165                 String key = String.valueOf(iter.next());
166                 if (key.startsWith(PREFIX)) {
167                     String property = key.substring(PREFIX.length());
168                     String value = props.getProperty(key);
169                     dbcpProperties.put(property, value);
170                 }
171             }
172 
173             // Backward-compatibility
174             if (props.getProperty(DBCP_PS_MAXACTIVE) != null) {
175                 dbcpProperties.put("poolPreparedStatements", String.valueOf(Boolean.TRUE));
176                 dbcpProperties.put("maxOpenPreparedStatements", props.getProperty(DBCP_PS_MAXACTIVE));
177             }
178 
179             // Some debug info
180             if (log.isDebugEnabled()) {
181                 log.debug("Creating a DBCP BasicDataSource with the following DBCP factory properties:");
182                 StringWriter sw = new StringWriter();
183                 dbcpProperties.list(new PrintWriter(sw, true));
184                 log.debug(sw.toString());
185             }
186 
187             // Let the factory create the pool
188             ds = (BasicDataSource) BasicDataSourceFactory.createDataSource(dbcpProperties);
189 
190             // The BasicDataSource has lazy initialization
191             // borrowing a connection will start the DataSource
192             // and make sure it is configured correctly.
193             Connection conn = ds.getConnection();
194             conn.close();
195 
196             // Log pool statistics before continuing.
197             logStatistics();
198         }
199         catch (Exception e) {
200             String message = "Could not create a DBCP pool";
201             log.fatal(message, e);
202             if (ds != null) {
203                 try {
204                     ds.close();
205                 }
206                 catch (Exception e2) {
207                     // ignore
208                 }
209                 ds = null;
210             }
211             throw new HibernateException(message, e);
212         }
213         log.debug("Configure DBCPConnectionProvider complete");
214     }
215 
216     public Connection getConnection() throws SQLException {
217         Connection conn = null;
218         try {
219                 conn = ds.getConnection();
220         }
221         finally {
222             logStatistics();
223         }
224         return conn;
225     }
226 
227     public void closeConnection(Connection conn) throws SQLException {
228         try {
229             conn.close();
230         }
231         finally {
232             logStatistics();
233         }
234     }
235 
236     public void close() throws HibernateException {
237         log.debug("Close DBCPConnectionProvider");
238         logStatistics();
239         try {
240             if (ds != null) {
241                 ds.close();
242                     ds = null;
243             }
244             else {
245                 log.warn("Cannot close DBCP pool (not initialized)");
246             }
247         }
248         catch (Exception e) {
249             throw new HibernateException("Could not close DBCP pool", e);
250         }
251         log.debug("Close DBCPConnectionProvider complete");
252     }
253 
254     /**
255      * Does this connection provider support aggressive release of JDBC
256      * connections and re-acquistion of those connections (if need be) later?
257      * <p/>
258      * This is used in conjunction with {@link org.hibernate.cfg.Environment.RELEASE_CONNECTIONS}
259      * to aggressively release JDBC connections.  However, the configured ConnectionProvider
260      * must support re-acquisition of the same underlying connection for that semantic to work.
261      * <p/>
262      * Typically, this is only true in managed environments where a container
263      * tracks connections by transaction or thread.
264      */
265     public boolean supportsAggressiveRelease() {
266         return false;
267     }
268 
269     protected void logStatistics() {
270         if (log.isInfoEnabled()) {
271             log.info("active: " + ds.getNumActive() + " (max: " + ds.getMaxActive() + ")   "
272                     + "idle: " + ds.getNumIdle() + "(max: " + ds.getMaxIdle() + ")");
273         }
274     }
275 }