File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\jdbcx\JdbcConnectionPool.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: Christian d'Heureuse, www.source-code.biz
6 *
7 * This class is dual-licensed LGPL and under the H2 License.
8 *
9 * This module 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 3 of the License, or (at your option) any later version.
13 * See http://www.gnu.org/licenses/lgpl.html
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied
17 * warranty of MERCHANTABILITY or FITNESS FOR A
18 * PARTICULAR PURPOSE. See the GNU Lesser General Public
19 * License for more details.
20 */
21 package org.h2.jdbcx;
22
23 import java.io.PrintWriter;
24 import java.sql.Connection;
25 import java.sql.SQLException;
26 import java.util.ArrayList;
27 import javax.sql.ConnectionEvent;
28 import javax.sql.ConnectionEventListener;
29 import javax.sql.ConnectionPoolDataSource;
30 import javax.sql.DataSource;
31 import javax.sql.PooledConnection;
32 import org.h2.util.New;
33
34 //## Java 1.6 ##
35 import org.h2.message.DbException;
36 //*/
37
38 /*## Java 1.7 ##
39 import java.util.logging.Logger;
40 //*/
41
42 /**
43 * A simple standalone JDBC connection pool.
44 * It is based on the
45 * <a href="http://www.source-code.biz/snippets/java/8.htm">
46 * MiniConnectionPoolManager written by Christian d'Heureuse (Java 1.5)
47 * </a>. It is used as follows:
48 * <pre>
49 * import java.sql.*;
50 * import org.h2.jdbcx.JdbcConnectionPool;
51 * public class Test {
52 * public static void main(String... args) throws Exception {
53 * JdbcConnectionPool cp = JdbcConnectionPool.create(
54 * "jdbc:h2:~/test", "sa", "sa");
55 * for (String sql : args) {
56 * Connection conn = cp.getConnection();
57 * conn.createStatement().execute(sql);
58 * conn.close();
59 * }
60 * cp.dispose();
61 * }
62 * }
63 * </pre>
64 *
65 * @author Christian d'Heureuse
66 * (<a href="http://www.source-code.biz">www.source-code.biz</a>)
67 * @author Thomas Mueller
68 */
69 public class JdbcConnectionPool implements DataSource, ConnectionEventListener {
70
71 private static final int DEFAULT_TIMEOUT = 30;
72 private static final int DEFAULT_MAX_CONNECTIONS = 10;
73
74 private final ConnectionPoolDataSource dataSource;
75 private final ArrayList<PooledConnection> recycledConnections = New.arrayList();
76 private PrintWriter logWriter;
77 private int maxConnections = DEFAULT_MAX_CONNECTIONS;
78 private int timeout = DEFAULT_TIMEOUT;
79 private int activeConnections;
80 private boolean isDisposed;
81
82 protected JdbcConnectionPool(ConnectionPoolDataSource dataSource) {
83 this.dataSource = dataSource;
84 if (dataSource != null) {
85 try {
86 logWriter = dataSource.getLogWriter();
87 } catch (SQLException e) {
88 // ignore
89 }
90 }
91 }
92
93 /**
94 * Constructs a new connection pool.
95 *
96 * @param dataSource the data source to create connections
97 * @return the connection pool
98 */
99 public static JdbcConnectionPool create(ConnectionPoolDataSource dataSource) {
100 return new JdbcConnectionPool(dataSource);
101 }
102
103 /**
104 * Constructs a new connection pool for H2 databases.
105 *
106 * @param url the database URL of the H2 connection
107 * @param user the user name
108 * @param password the password
109 * @return the connection pool
110 */
111 public static JdbcConnectionPool create(String url, String user, String password) {
112 JdbcDataSource ds = new JdbcDataSource();
113 ds.setURL(url);
114 ds.setUser(user);
115 ds.setPassword(password);
116 return new JdbcConnectionPool(ds);
117 }
118
119 /**
120 * Sets the maximum number of connections to use from now on.
121 * The default value is 10 connections.
122 *
123 * @param max the maximum number of connections
124 */
125 public synchronized void setMaxConnections(int max) {
126 if (max < 1) {
127 throw new IllegalArgumentException("Invalid maxConnections value: " + max);
128 }
129 this.maxConnections = max;
130 // notify waiting threads if the value was increased
131 notifyAll();
132 }
133
134 /**
135 * Gets the maximum number of connections to use.
136 *
137 * @return the max the maximum number of connections
138 */
139 public synchronized int getMaxConnections() {
140 return maxConnections;
141 }
142
143 /**
144 * Gets the maximum time in seconds to wait for a free connection.
145 *
146 * @return the timeout in seconds
147 */
148 public synchronized int getLoginTimeout() {
149 return timeout;
150 }
151
152 /**
153 * Sets the maximum time in seconds to wait for a free connection.
154 * The default timeout is 30 seconds. Calling this method with the
155 * value 0 will set the timeout to the default value.
156 *
157 * @param seconds the timeout, 0 meaning the default
158 */
159 public synchronized void setLoginTimeout(int seconds) {
160 if (seconds == 0) {
161 seconds = DEFAULT_TIMEOUT;
162 }
163 this.timeout = seconds;
164 }
165
166 /**
167 * Closes all unused pooled connections.
168 * Exceptions while closing are written to the log stream (if set).
169 */
170 public synchronized void dispose() {
171 if (isDisposed) {
172 return;
173 }
174 isDisposed = true;
175 ArrayList<PooledConnection> list = recycledConnections;
176 for (int i = 0, size = list.size(); i < size; i++) {
177 closeConnection(list.get(i));
178 }
179 }
180
181 /**
182 * Retrieves a connection from the connection pool. If
183 * <code>maxConnections</code> connections are already in use, the method
184 * waits until a connection becomes available or <code>timeout</code>
185 * seconds elapsed. When the application is finished using the connection,
186 * it must close it in order to return it to the pool.
187 * If no connection becomes available within the given timeout, an exception
188 * with SQL state 08001 and vendor code 8001 is thrown.
189 *
190 * @return a new Connection object.
191 * @throws SQLException when a new connection could not be established,
192 * or a timeout occurred
193 */
194 public Connection getConnection() throws SQLException {
195 long max = System.currentTimeMillis() + timeout * 1000;
196 do {
197 synchronized (this) {
198 if (activeConnections < maxConnections) {
199 return getConnectionNow();
200 }
201 try {
202 wait(1000);
203 } catch (InterruptedException e) {
204 // ignore
205 }
206 }
207 } while (System.currentTimeMillis() <= max);
208 throw new SQLException("Login timeout", "08001", 8001);
209 }
210
211 /**
212 * INTERNAL
213 */
214 public Connection getConnection(String user, String password) {
215 throw new UnsupportedOperationException();
216 }
217
218 private Connection getConnectionNow() throws SQLException {
219 if (isDisposed) {
220 throw new IllegalStateException("Connection pool has been disposed.");
221 }
222 PooledConnection pc;
223 if (!recycledConnections.isEmpty()) {
224 pc = recycledConnections.remove(recycledConnections.size() - 1);
225 } else {
226 pc = dataSource.getPooledConnection();
227 }
228 Connection conn = pc.getConnection();
229 activeConnections++;
230 pc.addConnectionEventListener(this);
231 return conn;
232 }
233
234 /**
235 * This method usually puts the connection back into the pool. There are
236 * some exceptions: if the pool is disposed, the connection is disposed as
237 * well. If the pool is full, the connection is closed.
238 *
239 * @param pc the pooled connection
240 */
241 synchronized void recycleConnection(PooledConnection pc) {
242 if (activeConnections <= 0) {
243 throw new AssertionError();
244 }
245 activeConnections--;
246 if (!isDisposed && activeConnections < maxConnections) {
247 recycledConnections.add(pc);
248 } else {
249 closeConnection(pc);
250 }
251 if (activeConnections >= maxConnections - 1) {
252 notifyAll();
253 }
254 }
255
256 private void closeConnection(PooledConnection pc) {
257 try {
258 pc.close();
259 } catch (SQLException e) {
260 if (logWriter != null) {
261 e.printStackTrace(logWriter);
262 }
263 }
264 }
265
266 /**
267 * INTERNAL
268 */
269 public void connectionClosed(ConnectionEvent event) {
270 PooledConnection pc = (PooledConnection) event.getSource();
271 pc.removeConnectionEventListener(this);
272 recycleConnection(pc);
273 }
274
275 /**
276 * INTERNAL
277 */
278 public void connectionErrorOccurred(ConnectionEvent event) {
279 // not used
280 }
281
282 /**
283 * Returns the number of active (open) connections of this pool. This is the
284 * number of <code>Connection</code> objects that have been issued by
285 * getConnection() for which <code>Connection.close()</code> has
286 * not yet been called.
287 *
288 * @return the number of active connections.
289 */
290 public synchronized int getActiveConnections() {
291 return activeConnections;
292 }
293
294 /**
295 * INTERNAL
296 */
297 public PrintWriter getLogWriter() {
298 return logWriter;
299 }
300
301 /**
302 * INTERNAL
303 */
304 public void setLogWriter(PrintWriter logWriter) {
305 this.logWriter = logWriter;
306 }
307
308 /**
309 * [Not supported] Return an object of this class if possible.
310 *
311 * @param iface the class
312 */
313 //## Java 1.6 ##
314 public <T> T unwrap(Class<T> iface) throws SQLException {
315 throw DbException.getUnsupportedException("unwrap");
316 }
317 //*/
318
319 /**
320 * [Not supported] Checks if unwrap can return an object of this class.
321 *
322 * @param iface the class
323 */
324 //## Java 1.6 ##
325 public boolean isWrapperFor(Class<?> iface) throws SQLException {
326 throw DbException.getUnsupportedException("isWrapperFor");
327 }
328 //*/
329
330 /**
331 * [Not supported]
332 */
333 /*## Java 1.7 ##
334 public Logger getParentLogger() {
335 return null;
336 }
337 //*/
338
339
340 }
341