/*
* Adito
*
* Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package com.adito.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JDBCConnectionImpl {
final static Log log = LogFactory.getLog(JDBCConnectionImpl.class);
static long currentId = 0;
// database instance name, such as myOracleDB
private String key;
private long id;
private Connection conn;
private Hashtable preparedStatements = new Hashtable();
// the precious connection
private JDBCConnectionImpl(String key, JDBCConnectionSettings settings) throws SQLException,
ClassNotFoundException {
id = currentId++;
this.key = key;
Class.forName(settings.driver);
conn = DriverManager.getConnection(settings.url, settings.username, settings.password);
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
conn.setAutoCommit(autoCommit);
}
String getKey() {
return key;
}
boolean isClosed() throws SQLException {
return conn.isClosed();
}
ResultSet executeQuery(String sqlString) throws SQLException {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sqlString);
return rs;
}
void execute(String sqlString) throws SQLException {
Statement stmt = conn.createStatement();
try {
stmt.execute(sqlString);
}
finally {
stmt.close();
}
}
synchronized PreparedStatement aquirePreparedStatement(String key, String sqlString) throws SQLException {
Vector avail = (Vector) preparedStatements.get(key);
if (avail == null) {
avail = new Vector();
preparedStatements.put(key, avail);
}
if (avail.size() > 0) {
return (PreparedStatement) avail.remove(0);
} else
return conn.prepareStatement(sqlString);
}
synchronized void releasePreparedStatement(String key, PreparedStatement ps) throws SQLException {
ps.clearParameters();
Vector avail = (Vector) preparedStatements.get(key);
avail.add(ps);
}
public long getId() {
return id;
}
public Connection getConnection() {
return conn;
}
public static class JDBCPool {
// dictionary of database names with corresponding vector of connections
private Hashtable poolDictionary = new Hashtable();
// dictionary of database settings
private Hashtable poolSettings = new Hashtable();
// methods and attributes for Singleton pattern
private JDBCPool() {
} // private constructor
private static JDBCPool _instance; // get class instance
// Singleton getter utilizing Double Checked Locking pattern
public static JDBCPool getInstance() {
if (_instance == null) {
synchronized (JDBCPool.class) {
if (_instance == null) {
_instance = new JDBCPool();
}
}
}
return _instance;
}
public synchronized void createImpl(String key, String driver, String url, String username, String password)
throws SQLException, ClassNotFoundException {
Vector pool = new Vector();
JDBCConnectionSettings settings = new JDBCConnectionSettings();
settings.driver = driver;
settings.url = url;
settings.username = username;
settings.password = password;
poolDictionary.put(key, pool);
poolSettings.put(key, settings);
pool.addElement(new JDBCConnectionImpl(key, settings));
}
public Map getPools() {
return poolDictionary;
}
public synchronized void closeAll() {
for (Iterator i = poolDictionary.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
if (log.isInfoEnabled())
log.info("Closing connections for " + entry.getKey());
Vector pool = (Vector) entry.getValue();
for (Iterator j = pool.iterator(); j.hasNext();) {
JDBCConnectionImpl conx = (JDBCConnectionImpl) j.next();
try {
conx.conn.close();
} catch (SQLException sqle) {
log.warn("Failed to close pooled connection. ", sqle);
}
}
}
poolDictionary.clear();
}
// get connection from pool
public synchronized JDBCConnectionImpl acquireImpl(String key) throws SQLException, ClassNotFoundException {
if (log.isDebugEnabled())
log.debug("Aquiring connection for " + key);
// get pool matching database name
Vector pool = (Vector) poolDictionary.get(key);
if (pool != null) {
while (pool.size() > 0) {
if (log.isDebugEnabled())
log.debug(pool.size() + " connections in pool.");
JDBCConnectionImpl impl = null;
// retrieve existing unused connection
impl = (JDBCConnectionImpl) pool.elementAt(pool.size() - 1);
// remove connection from pool
pool.removeElementAt(pool.size() - 1);
// If the connection has closed then drop it and select
// another
if (impl.isClosed()) {
if (log.isDebugEnabled())
log.debug("Connecting for " + key + " is closed, get the next one");
continue;
}
if (log.isDebugEnabled())
log.debug("Found connection " + impl.toString());
return impl;
}
}
if (log.isDebugEnabled())
log.debug("Pool is empty, getting ");
JDBCConnectionSettings settings = (JDBCConnectionSettings) poolSettings.get(key);
// pool is empty so create new connection
return new JDBCConnectionImpl(key, settings);
}
// return connection to pool
public synchronized void releaseImpl(JDBCConnectionImpl impl) {
String key = impl.getKey();
Vector pool = (Vector) poolDictionary.get(key);
if (pool == null) {
pool = new Vector();
poolDictionary.put(key, pool);
}
pool.addElement(impl);
}
}
static class JDBCConnectionSettings {
String url;
String driver;
String cls;
String username;
String password;
}
public void rollback() throws SQLException {
conn.rollback();
}
public void commit() throws SQLException {
conn.commit();
}
}