/*
* codjo.net
*
* Common Apache License 2.0
*/
package net.codjo.utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
/**
* Manager of SQL connection.
*
* <p> Spool database connection in order to speed up process. A ConnectionManager is specific for one
* database and one user. The Pool contains 2 kinds of list: one for all connections built by this manager,
* and another for unused connection. </p>
*
* <p> This class is multi-thread safe. </p>
*
* @author $Author: marcona $
* @version $Revision: 1.5 $
*/
public class ConnectionManager {
private List allConnections;
private String catalog;
private String classDriver;
private long closeDelay = 5000;
private Properties dbProps;
private String dbUrl;
private Timer timer;
private long timestamp = System.currentTimeMillis();
private Stack unusedConnections;
public ConnectionManager() {
}
/**
* Constructor for the ConnectionManager object.
*
* @param classDriver Class driver name (ex: com.sybase.jdbc2.jdbc.SybDriver)
* @param url Url of the Database
* @param catalog Catalog de la base (optionnal)
* @param props Propriete du driver
*
* @throws ClassNotFoundException Si le driver n'est pas trouve.
*/
public ConnectionManager(String classDriver, String url, String catalog,
Properties props) throws ClassNotFoundException {
this(classDriver, url, catalog, props, false);
}
/**
* Constructeur de ConnectionManager
*
* @param classDriver Description of the Parameter
* @param url Description of the Parameter
* @param catalog Description of the Parameter
* @param props Description of the Parameter
* @param numericTruncationWarning
*
* @throws ClassNotFoundException Description of the Exception
*/
public ConnectionManager(String classDriver, String url, String catalog,
Properties props, boolean numericTruncationWarning)
throws ClassNotFoundException {
Class.forName(classDriver);
this.classDriver = classDriver;
this.dbUrl = url;
this.dbProps = props;
this.catalog = catalog;
if (numericTruncationWarning) {
dbProps.put("SQLINITSTRING", "set arithabort numeric_truncation on");
}
else {
dbProps.put("SQLINITSTRING", "set arithabort numeric_truncation off");
}
unusedConnections = new Stack();
allConnections = new java.util.LinkedList();
initTimer();
}
/**
* Ferme toutes les connections du pool.
*/
public synchronized void closeAllConnections() {
List copy = new ArrayList(allConnections);
for (Iterator iter = copy.iterator(); iter.hasNext();) {
Connection con = ((Connection)iter.next());
closeConnection(con);
}
}
/**
* Retourne Le catalogue utilis� par ce ConnectionManager.
*
* @return nom de catalog
*/
public String getCatalog() {
return catalog;
}
/**
* Retourne Le driver JDBC utilis� par ce ConnectionManager.
*
* @return nom de classe
*/
public String getClassDriver() {
return classDriver;
}
/**
* Gets one valid connection to the database.
*
* @return a connection object to the database.
*
* @throws SQLException Description of Exception
*/
public synchronized Connection getConnection()
throws SQLException {
if (unusedConnections.isEmpty()) {
addNewConnection();
}
Connection co = (Connection)unusedConnections.pop();
return co;
}
/**
* Retourne Les propri�t�s utilis� par ce ConnectionManager pour cr�er des connections.
*
* @return properties
*/
public Properties getDbProps() {
return dbProps;
}
/**
* Retourne L'url de la BD utilis� par ce ConnectionManager.
*
* @return addresse de la BD
*/
public String getDbUrl() {
return dbUrl;
}
/**
* Release a connection (previously given by this manager), and close the given statement.
*
* @param con a connection
* @param stmt a statement
*
* @throws SQLException DB access error
*/
public synchronized void releaseConnection(Connection con, Statement stmt)
throws SQLException {
try {
if (stmt != null) {
stmt.close();
}
}
finally {
releaseConnection(con);
}
}
/**
* Release a connection (previously given by this manager).
*
* @param con a connection
*
* @throws SQLException DB access error
*/
public synchronized void releaseConnection(Connection con)
throws SQLException {
if ((con != null)
&& (con.isClosed() == false)
&& (unusedConnections.contains(con) == false)) {
if (con.getAutoCommit() == false) {
con.rollback();
con.setAutoCommit(true);
}
timestamp = System.currentTimeMillis();
if (unusedConnections.size() == 0) {
unusedConnections.push(con);
}
else {
closeConnection(con);
}
}
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public String toString() {
return "ConnectionManager(" + "total=" + allConnections.size() + ", unused="
+ unusedConnections.size() + ")";
}
/**
* Retourne l'attribut allConnectionsSize de ConnectionManager
*
* @return La valeur de allConnectionsSize
*/
public int getAllConnectionsSize() {
return allConnections.size();
}
/**
* Ferme toutes les connexions et arr�te le timer de fermeture des connexions
*/
public void shutdown() {
closeAllConnections();
timer.cancel();
}
/**
* Adds a feature to the NewConnection attribute of the ConnectionManager object
*
* @throws SQLException Description of Exception
* @throws NullPointerException TODO
*/
void addNewConnection() throws SQLException {
Connection con = DriverManager.getConnection(dbUrl, dbProps);
if (con == null) {
throw new NullPointerException("DriverManager retourne une connection null");
}
if (catalog != null) {
con.setCatalog(catalog);
}
allConnections.add(con);
unusedConnections.push(con);
}
/**
* Renseigne un nouveau d�lai d'attente avant de fermer une connection non utilis�e.
*
* @param delay Le d�lai (en millisecondes).
*/
void setCloseDelay(long delay) {
closeDelay = delay;
timer.cancel();
initTimer();
}
/**
* Ferme la connection.
*
* @param con Une connection
*/
private void closeConnection(Connection con) {
try {
if (con.isClosed() == false) {
con.close();
}
}
catch (SQLException ex) {
System.err.println("Unable to close a connection : " + ex.toString());
ex.printStackTrace();
}
allConnections.remove(con);
unusedConnections.remove(con);
}
/**
* Ferme la connection non utilis�e apr�s le closeDelay.
*/
private synchronized void closeOldConnection() {
if (unusedConnections.size() != 0) {
if (System.currentTimeMillis() >= timestamp + closeDelay) {
closeConnection((Connection)unusedConnections.get(0));
}
}
}
/**
* Initialise le Timer permettant de fermer une connection non utilis�e au bout du closeDelay.
*/
private void initTimer() {
timer = new Timer(true);
timer.schedule(new TimerTask() {
public void run() {
closeOldConnection();
}
}, 1, closeDelay);
}
}