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