View Javadoc

1   /*
2    * $Header: /cvsroot/jdbforms/dbforms/src/org/dbforms/conprovider/SinglePerThreadConnectionProvider.java,v 1.7 2006/01/23 07:26:18 hkollmann Exp $
3    * $Revision: 1.7 $
4    * $Date: 2006/01/23 07:26:18 $
5    *
6    * DbForms - a Rapid Application Development Framework
7    * Copyright (C) 2001 Joachim Peer <joepeer@excite.com>
8    *
9    * This library is free software; you can redistribute it and/or
10   * modify it under the terms of the GNU Lesser General Public
11   * License as published by the Free Software Foundation; either
12   * version 2.1 of the License, or (at your option) any later version.
13   *
14   * This library is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this library; if not, write to the Free Software
21   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22   */
23  
24  package org.dbforms.conprovider;
25  
26  import java.sql.Connection;
27  import java.sql.DriverManager;
28  import java.sql.ResultSet;
29  import java.sql.SQLException;
30  import java.sql.Statement;
31  import java.util.Date;
32  import java.util.Properties;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  import org.dbforms.util.Util;
38  
39  /***
40   * Single Connection per thread provider. <br>
41   * provides one connection for all
42   * 
43   * @author Henner Kollmann
44   */
45  public class SinglePerThreadConnectionProvider extends
46  		AbstractConnectionProvider {
47  	private static final ThreadLocal singlePerThread = new ThreadLocal();
48  	private static final ThreadLocal singlePerThreadDateNext = new ThreadLocal();
49  	private static Log logCat = LogFactory.getLog(SinglePerThreadConnectionProvider.class);
50  
51  	// End 20060117
52  
53  	/***
54  	 * Default constructor.
55  	 * 
56  	 * @exception Exception
57  	 *                Description of the Exception
58  	 * @throws Exception
59  	 *             because of the <code>throws Exception</code> clause of the
60  	 *             <code>init</code> method.
61  	 */
62  	public SinglePerThreadConnectionProvider() throws Exception {
63  		super();
64  	}
65  
66  	/***
67  	 * Get a JDBC Connection
68  	 * 
69  	 * @return a JDBC Connection
70  	 * 
71  	 * @exception SQLException
72  	 *                Description of the Exception
73  	 */
74  	protected synchronized Connection getConnection() throws SQLException {
75  		Connection con = (Connection) singlePerThread.get();
76  
77  		long validationInterval;
78  		// Get Validation Interval from the config and convert to seconds.
79  		// Default interval is six hours (21,600,000 milliseconds).
80  		try {
81  			validationInterval = Long.parseLong(getPrefs().getPoolProperties()
82  					.getProperty("validationInterval", "21600"));
83  			// Convert from seconds as expressed in property to milliseconds.
84  			validationInterval = validationInterval * 1000;
85  		} catch (NumberFormatException ex) {
86  			validationInterval = 21600000;
87  		}
88  
89  		Date rightNow = new Date();
90  		Date conNextValidationDate = (Date) singlePerThreadDateNext.get();
91  		// Initialise the validation check time, validationInterval into the
92  		// future from now.
93  		if (conNextValidationDate == null) {
94  			conNextValidationDate = new Date(validationInterval
95  					+ rightNow.getTime());
96  			;
97  			singlePerThreadDateNext.set(conNextValidationDate);
98  		}
99  
100 		if (con != null && conNextValidationDate.before(rightNow)) {
101 			conNextValidationDate.setTime(validationInterval
102 					+ rightNow.getTime());
103 			String validationQuery = getPrefs().getPoolProperties()
104 					.getProperty("validationQuery", "");
105 			if (!Util.isNull(validationQuery)) {
106 				logCat.debug("Testing connection: checking validation timestamp='"
107 								+ rightNow.toString() + "'.");
108 				logCat.debug("Testing connection: next validation check='"
109 						+ conNextValidationDate.toString() + "'.");
110 				logCat.debug("Testing connection: validationQuery='"
111 						+ validationQuery + "'.");
112 				// Test the connection.
113 				try {
114 					Statement st = con.createStatement();
115 					ResultSet rs = st.executeQuery(validationQuery);
116 					try {
117 						rs.next();
118 						logCat.debug("Testing connection: Connection is valid.");
119 					} finally {
120 						rs.close();
121 						st.close();
122 					}
123 				} catch (SQLException sqlex) {
124 					// Exception, so close the connection and set to null
125 					// so it is recreated in the body of the "if (con == null)"
126 					// below.
127 					logCat.debug("Testing connection: Connection is invalid. Forcing recreate.");
128 					con.close();
129 					con = null;
130 				}
131 			}
132 		}
133 
134 		if (con == null) {
135 			Properties props = getPrefs().getProperties();
136 			// uses custom jdbc properties;
137 			if ((props != null) && !props.isEmpty()) {
138 				props.put("user", getPrefs().getUser());
139 				props.put("password", getPrefs().getPassword());
140 				con = DriverManager.getConnection(getPrefs().getJdbcURL(),
141 						props);
142 			}
143 			// "plain" flavour;
144 			else {
145 				con = DriverManager.getConnection(getPrefs().getJdbcURL(),
146 						getPrefs().getUser(), getPrefs().getPassword());
147 			}
148 
149 			singlePerThread.set(con);
150 		}
151 
152 		return new SingleConnectionWrapper(con);
153 	}
154 
155 	/***
156 	 * Initialize the ConnectionProvider.
157 	 * 
158 	 * @throws Exception
159 	 *             if any error occurs
160 	 */
161 	protected void init() throws Exception {
162 		Class.forName(getPrefs().getJdbcDriver()).newInstance();
163 	}
164 }