View Javadoc

1   /*
2    * Hibernate, Relational Persistence for Idiomatic Java
3    *
4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5    * indicated by the @author tags or express copyright attribution
6    * statements applied by the authors.  All third-party contributions are
7    * distributed under license by Red Hat Middleware LLC.
8    *
9    * This copyrighted material is made available to anyone wishing to use, modify,
10   * copy, or redistribute it subject to the terms and conditions of the GNU
11   * Lesser General Public License, as published by the Free Software Foundation.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15   * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
16   * for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with this distribution; if not, write to:
20   * Free Software Foundation, Inc.
21   * 51 Franklin Street, Fifth Floor
22   * Boston, MA  02110-1301  USA
23   *
24   */
25  package org.hibernate.connection;
26  
27  
28  import java.sql.Connection;
29  import java.sql.Driver;
30  import java.sql.SQLException;
31  import java.util.ArrayList;
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Properties;
35  
36  import org.hibernate.HibernateException;
37  import org.hibernate.cfg.Environment;
38  import org.hibernate.util.ReflectHelper;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  /**
43   * This is the Hibernate class org.hibernate.connection.connection.DriverManagerConnectionProvider, 
44   * tweaked in order to work with Mule's hot deployment.
45   * 
46   * A very simple connection provider which does <u>not</u> use <tt>java.sql.DriverManager</tt>. This provider
47   * also implements a very rudimentary connection pool.
48   * @see ConnectionProvider
49   * @author Gavin King
50   */
51  public class SimpleConnectionProvider implements ConnectionProvider {
52  
53  	private String url;
54  	private Properties connectionProps;
55  	private Integer isolation;
56  	private final ArrayList pool = new ArrayList();
57  	private int poolSize;
58  	private int checkedOut = 0;
59  	private boolean autocommit;
60  	private Driver driver;
61  
62  	private static final Logger log = LoggerFactory.getLogger(SimpleConnectionProvider.class);
63  
64  	public void configure(Properties props) throws HibernateException {
65  
66  		String driverClass = props.getProperty(Environment.DRIVER);
67  
68  		poolSize = getInt(Environment.POOL_SIZE, props, 20); //default pool size 20
69  		log.info("Using Hibernate built-in connection pool (not for production use!)");
70  		log.info("Hibernate connection pool size: " + poolSize);
71  		
72  		autocommit = getBoolean(Environment.AUTOCOMMIT, props);
73  		log.info("autocommit mode: " + autocommit);
74  
75  		isolation = getInteger(Environment.ISOLATION, props);
76  		if (isolation!=null)
77  		log.info( "JDBC isolation level: " + Environment.isolationLevelToString( isolation.intValue() ) );
78  
79  		if (driverClass==null) {
80  			log.warn("no JDBC Driver class was specified by property " + Environment.DRIVER);
81  		}
82  		else {		    
83  			try {
84  				// trying via forName() first to be as close to DriverManager's semantics
85  				driver = (Driver) Class.forName(driverClass, true, Thread.currentThread().getContextClassLoader()).newInstance();
86  			}
87  			catch (Exception e) {
88  				try {
89  				    driver = (Driver) ReflectHelper.classForName(driverClass).newInstance();
90  				}
91  				catch (Exception e1) {
92  					log.error(e1.getMessage());
93  					throw new HibernateException(e1);
94  				}
95  			}
96  		}
97  
98  		url = props.getProperty( Environment.URL );
99  		if ( url == null ) {
100 			String msg = "JDBC URL was not specified by property " + Environment.URL;
101 			log.error( msg );
102 			throw new HibernateException( msg );
103 		}
104 
105 		connectionProps = ConnectionProviderFactory.getConnectionProperties( props );
106 
107 		log.info( "using driver: " + driverClass + " at URL: " + url );
108 		// if debug level is enabled, then log the password, otherwise mask it
109 		if ( log.isDebugEnabled() ) {
110 			log.info( "connection properties: " + connectionProps );
111 		} 
112 		else if ( log.isInfoEnabled() ) {
113 			log.info( "connection properties: " + maskOut(connectionProps, "password") );
114 		}
115 
116 	}
117 
118 	public Connection getConnection() throws SQLException {
119 
120 		if ( log.isTraceEnabled() ) log.trace( "total checked-out connections: " + checkedOut );
121 
122 		synchronized (pool) {
123 			if ( !pool.isEmpty() ) {
124 				int last = pool.size() - 1;
125 				if ( log.isTraceEnabled() ) {
126 					log.trace("using pooled JDBC connection, pool size: " + last);
127 					checkedOut++;
128 				}
129 				Connection pooled = (Connection) pool.remove(last);
130 				if (isolation!=null) pooled.setTransactionIsolation( isolation.intValue() );
131 				if ( pooled.getAutoCommit()!=autocommit ) pooled.setAutoCommit(autocommit);
132 				return pooled;
133 			}
134 		}
135 
136         log.debug("opening new JDBC connection");
137 		Connection conn = driver.connect(url, connectionProps);
138 		if (isolation!=null) conn.setTransactionIsolation( isolation.intValue() );
139 		if ( conn.getAutoCommit()!=autocommit ) conn.setAutoCommit(autocommit);
140 
141 		if ( log.isDebugEnabled() ) {
142 			log.debug( "created connection to: " + url + ", Isolation Level: " + conn.getTransactionIsolation() );
143 		}
144 		if ( log.isTraceEnabled() ) checkedOut++;
145 
146 		return conn;
147 	}
148 
149 	public void closeConnection(Connection conn) throws SQLException {
150 
151 		if ( log.isDebugEnabled() ) checkedOut--;
152 
153 		synchronized (pool) {
154 			int currentSize = pool.size();
155 			if ( currentSize < poolSize ) {
156 				if ( log.isTraceEnabled() ) log.trace("returning connection to pool, pool size: " + (currentSize + 1) );
157 				pool.add(conn);
158 				return;
159 			}
160 		}
161 
162 		log.debug("closing JDBC connection");
163 
164 		conn.close();
165 
166 	}
167 
168 	protected void finalize() {
169 		close();
170 	}
171 
172 	public void close() {
173 
174 		log.info("cleaning up connection pool: " + url);
175 
176 		Iterator iter = pool.iterator();
177 		while ( iter.hasNext() ) {
178 			try {
179 				( (Connection) iter.next() ).close();
180 			}
181 			catch (SQLException sqle) {
182 				log.warn("problem closing pooled connection", sqle);
183 			}
184 		}
185 		pool.clear();
186 
187 	}
188 
189 	/**
190 	 * @see ConnectionProvider#supportsAggressiveRelease()
191 	 */
192 	public boolean supportsAggressiveRelease() {
193 		return false;
194 	}
195 	
196 	//////////////////////////////////////////////////////////////////////////
197 	// The following utility methods are copied from ConfigurationHelper.java
198     //////////////////////////////////////////////////////////////////////////
199 	
200     /**
201      * Get the config value as a boolean (default of false)
202      *
203      * @param name The config setting name.
204      * @param values The map of config values
205      *
206      * @return The value.
207      */
208     public static boolean getBoolean(String name, Map values) {
209         return getBoolean( name, values, false );
210     }
211 
212     /**
213      * Get the config value as a boolean.
214      *
215      * @param name The config setting name.
216      * @param values The map of config values
217      * @param defaultValue The default value to use if not found
218      *
219      * @return The value.
220      */
221     public static boolean getBoolean(String name, Map values, boolean defaultValue) {
222         Object value = values.get( name );
223         if ( value == null ) {
224             return defaultValue;
225         }
226         if ( Boolean.class.isInstance( value ) ) {
227             return ( (Boolean) value ).booleanValue();
228         }
229         if ( String.class.isInstance( value ) ) {
230             return Boolean.parseBoolean( (String) value );
231         }
232         throw new HibernateException(
233                 "Could not determine how to handle configuration value [name=" + name + ", value=" + value + "] as boolean"
234         );
235     }
236 
237     /**
238      * Get the config value as an int
239      *
240      * @param name The config setting name.
241      * @param values The map of config values
242      * @param defaultValue The default value to use if not found
243      *
244      * @return The value.
245      */
246     public static int getInt(String name, Map values, int defaultValue) {
247         Object value = values.get( name );
248         if ( value == null ) {
249             return defaultValue;
250         }
251         if ( Integer.class.isInstance( value ) ) {
252             return ( (Integer) value ).intValue();
253         }
254         if ( String.class.isInstance( value ) ) {
255             return Integer.parseInt( (String) value );
256         }
257         throw new HibernateException(
258                 "Could not determine how to handle configuration value [name=" + name +
259                         ", value=" + value + "(" + value.getClass().getName() + ")] as int"
260         );
261     }
262 
263     /**
264      * Get the config value as an {@link Integer}
265      *
266      * @param name The config setting name.
267      * @param values The map of config values
268      *
269      * @return The value, or null if not found
270      */
271     public static Integer getInteger(String name, Map values) {
272         Object value = values.get( name );
273         if ( value == null ) {
274             return null;
275         }
276         if ( Integer.class.isInstance( value ) ) {
277             return (Integer) value;
278         }
279         if ( String.class.isInstance( value ) ) {
280             return Integer.valueOf( (String) value );
281         }
282         throw new HibernateException(
283                 "Could not determine how to handle configuration value [name=" + name +
284                         ", value=" + value + "(" + value.getClass().getName() + ")] as Integer"
285         );
286     }
287 
288     /**
289      * replace a property by a starred version
290      *
291      * @param props properties to check
292      * @param key proeprty to mask
293      *
294      * @return cloned and masked properties
295      */
296     public static Properties maskOut(Properties props, String key) {
297         Properties clone = ( Properties ) props.clone();
298         if ( clone.get( key ) != null ) {
299             clone.setProperty( key, "****" );
300         }
301         return clone;
302     }	
303 }
304 
305 
306 
307 
308 
309 
310