//package com.wrox.connectionpool; package com.idega.util.database; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import com.idega.idegaweb.IWMainApplication; import com.idega.repository.data.RefactorClassRegistry; import com.idega.repository.data.Singleton; import com.idega.util.LogWriter; import com.idega.util.text.TextSoap; /** * *@author <a href="http://www.wrox.com">wrox</a> modified by <a href="mailto:tryggvi@idega.is">Tryggvi Larusson</a> *@version 1.3 * Class to deliver database connections through a connectionpool */ public class PoolManager implements Singleton { private static final String IW_APPLICATION_PATH_PLACE_HOLDER = "{iw_application_path}";//a string you can use in a connection url private static final String IW_BUNDLES_PATH_PLACE_HOLDER = "{iw_bundles_path}";//a string you can use in a connection url private static String DEFAULT_DSN = "default"; static private PoolManager instance; static private int clients; private static boolean isUnlocked = true; private LogWriter logWriter; private PrintWriter pw; private Vector drivers = new Vector(); private Hashtable pools = new Hashtable(); private IWMainApplication iwma; private PoolManager() { init(System.getProperty("file.separator") + "db.properties"); } private PoolManager(String propertiesFileLocation) { init(propertiesFileLocation); } private PoolManager(String propertiesFileLocation, IWMainApplication iwMainApplication) { this.iwma = iwMainApplication; init(propertiesFileLocation); } public static void lock() { isUnlocked = false; } public static void unlock() { isUnlocked = true; } static synchronized public PoolManager getInstance() { if (instance == null && isUnlocked) { instance = new PoolManager(); } clients++; return instance; } static synchronized public PoolManager getInstance(String propertiesFileLocation) { if (instance == null && isUnlocked) { instance = new PoolManager(propertiesFileLocation); } clients++; return instance; } static synchronized public PoolManager getInstance(String propertiesFileLocation, IWMainApplication mainApplication) { if (instance == null && isUnlocked) { instance = new PoolManager(propertiesFileLocation,mainApplication); } clients++; return instance; } private void init(String propertiesFile) { // Log to System.err until we have read the logfile property this.pw = new PrintWriter(System.err, true); this.logWriter = new LogWriter("PoolManager", LogWriter.INFO, this.pw); //InputStream is = getClass().getResourceAsStream(propertiesFile); InputStream is; Properties dbProps = new Properties(); try { is = new FileInputStream(propertiesFile); dbProps.load(is); } catch (Exception e) { this.logWriter.log("Can't read the properties file from the specified location", LogWriter.ERROR); return; } String logFile = dbProps.getProperty("logfile"); if (logFile != null) { try { this.pw = new PrintWriter(new FileWriter(logFile, true), true); this.logWriter.setPrintWriter(this.pw); } catch (IOException e) { this.logWriter.log("Can't open the log file: " + logFile + ". Using System.err instead", LogWriter.ERROR); } } loadDrivers(dbProps); createPools(dbProps); } private void loadDrivers(Properties props) { String driverClasses = props.getProperty("drivers"); StringTokenizer st = new StringTokenizer(driverClasses); while (st.hasMoreElements()) { String driverClassName = st.nextToken().trim(); try { Driver driver = (Driver) RefactorClassRegistry.forName(driverClassName).newInstance(); DriverManager.registerDriver(driver); this.drivers.addElement(driver); this.logWriter.log("Registered JDBC driver " + driverClassName, LogWriter.INFO); } catch (Exception e) { this.logWriter.log(e, "Can't register JDBC driver: " + driverClassName, LogWriter.ERROR); } } } private void createPools(Properties props) { Enumeration propNames = props.propertyNames(); while (propNames.hasMoreElements()) { String name = (String) propNames.nextElement(); if (name.endsWith(".url")) { String poolName = name.substring(0, name.lastIndexOf(".")); String url = props.getProperty(poolName + ".url"); if (url == null) { this.logWriter.log("No URL specified for " + poolName, LogWriter.ERROR); continue; } if (this.pools.containsKey(poolName)) { this.logWriter.log("[PoolManager] Pool '" + poolName + "'already exists", LogWriter.ERROR); continue; } // replace the {iw_application_path} variable with the real path to the applications we folder if(this.iwma!=null) { String applicationRealPath = this.iwma.getApplicationRealPath(); String bundlesRealPath = this.iwma.getBundlesRealPath(); //does not work because the string must be an expression //url.replaceAll(IW_APPLICATION_PATH_PLACE_HOLDER, applicationRealPath); if(url.indexOf(IW_APPLICATION_PATH_PLACE_HOLDER)!=-1){ url = TextSoap.findAndReplace(url,IW_APPLICATION_PATH_PLACE_HOLDER, applicationRealPath); } else if(url.indexOf(IW_BUNDLES_PATH_PLACE_HOLDER)!=-1){ url = TextSoap.findAndReplace(url,IW_BUNDLES_PATH_PLACE_HOLDER, bundlesRealPath); } } String user = props.getProperty(poolName + ".user"); String password = props.getProperty(poolName + ".password"); String maxConns = props.getProperty(poolName + ".maxconns", "0"); String sRefreshIntervalMinutes=props.getProperty(poolName + ".refreshminutes", "20");; long lRefreshIntervalMillis; int max; try { max = Integer.valueOf(maxConns).intValue(); } catch (NumberFormatException e) { this.logWriter.log("Invalid maxconns value " + maxConns + " for " + poolName, LogWriter.ERROR); max = 0; } String initConns = props.getProperty(poolName + ".initconns", "0"); int init; try { init = Integer.valueOf(initConns).intValue(); } catch (NumberFormatException e) { this.logWriter.log("Invalid initconns value " + initConns + " for " + poolName, LogWriter.ERROR); init = 0; } String loginTimeOut = props.getProperty(poolName + ".logintimeout", "5"); int timeOut; try { timeOut = Integer.valueOf(loginTimeOut).intValue(); } catch (NumberFormatException e) { this.logWriter.log("Invalid logintimeout value " + loginTimeOut + " for " + poolName, LogWriter.ERROR); timeOut = 5; } String logLevelProp = props.getProperty(poolName + ".loglevel", String.valueOf(LogWriter.ERROR)); int logLevel = LogWriter.INFO; if (logLevelProp.equalsIgnoreCase("none")) { logLevel = LogWriter.NONE; } else if (logLevelProp.equalsIgnoreCase("error")) { logLevel = LogWriter.ERROR; } else if (logLevelProp.equalsIgnoreCase("debug")) { logLevel = LogWriter.DEBUG; } try { int iRefreshIntervalMinutes=Long.valueOf(sRefreshIntervalMinutes).intValue(); lRefreshIntervalMillis = iRefreshIntervalMinutes * 60 * 1000; } catch (NumberFormatException e) { lRefreshIntervalMillis=20*1000*60; this.logWriter.log("Invalid refreshminutes value " + sRefreshIntervalMinutes + " for " + poolName, LogWriter.ERROR); max = 0; } ConnectionPool pool = new ConnectionPool(poolName, url, user, password, max, init, timeOut, this.pw, logLevel,lRefreshIntervalMillis); this.pools.put(poolName, pool); } } } public Connection getConnection() { return getConnection(DEFAULT_DSN); } public Connection getConnection(String dataSourceName) { Connection conn = null; ConnectionPool pool = (ConnectionPool) this.pools.get(dataSourceName); if (pool != null) { try { conn = pool.getConnection(); } catch (SQLException e) { this.logWriter.log(e, "Exception getting connection from " + dataSourceName, LogWriter.ERROR); } } return conn; } public void freeConnection(String datasourceName, Connection con) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { pool.freeConnection(con); } } public void freeConnection(Connection connection) { freeConnection(DEFAULT_DSN, connection); } public synchronized void release() { // Wait until called by the last client //if (--clients != 0) //{ // return; //} // prevent creation PoolManager.lock(); Enumeration allPools = this.pools.elements(); while (allPools.hasMoreElements()) { ConnectionPool pool = (ConnectionPool) allPools.nextElement(); pool.release(); } Enumeration allDrivers = this.drivers.elements(); while (allDrivers.hasMoreElements()) { Driver driver = (Driver) allDrivers.nextElement(); try { DriverManager.deregisterDriver(driver); this.logWriter.log("Deregistered JDBC driver " + driver.getClass().getName(), LogWriter.INFO); } catch (SQLException e) { this.logWriter.log(e, "Couldn't deregister JDBC driver: " + driver.getClass().getName(), LogWriter.ERROR); } } instance=null; } //debug public String getStats(String name) { ConnectionPool tempPool = (ConnectionPool) this.pools.get(name); return tempPool.getStats(); } //Status of all pools: public String getStats() { String returnString = ""; for (Enumeration e = this.pools.keys(); e.hasMoreElements();) { String name = (String) e.nextElement(); ConnectionPool tempPool = (ConnectionPool) this.pools.get(name); returnString = returnString + "\nStatus of datasource " + name + " is: " + tempPool.getStats() + " "; } return returnString; } public Hashtable getStatsHashtable() { Hashtable table = new Hashtable(); for (Enumeration e = this.pools.keys(); e.hasMoreElements();) { String name = (String) e.nextElement(); ConnectionPool tempPool = (ConnectionPool) this.pools.get(name); table.put(name, "Status of datasource " + name + " is: " + tempPool.getStats() + " "); } return table; } public String[] getDatasources() { Vector sources = new Vector(); for (Enumeration e = this.pools.keys(); e.hasMoreElements();) { String name = (String) e.nextElement(); sources.add(name); } return (String[]) sources.toArray(new String[0]); } public boolean hasDatasource(String datasource) { return this.pools.containsKey(datasource); } public String getPasswordForPool(String datasourceName) { String password = null; ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { password = pool.getPassword(); } return password; } public String getPasswordForPool() { return getPasswordForPool(DEFAULT_DSN); } public String getUserNameForPool(String datasourceName) { String userName = null; ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { userName = pool.getUserName(); } return userName; } public String getUserNameForPool() { return getUserNameForPool(DEFAULT_DSN); } public String getURLForPool(String datasourceName) { String URL = null; ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { URL = pool.getURL(); } return URL; } public String getURLForPool() { return getURLForPool(DEFAULT_DSN); } /** * This only works if there is one driver definition in the db.properties file * TODO: Fix this limitation public String getDriverClassForPool(String datasourceName){ String driverClass = null; ConnectionPool pool = (ConnectionPool) pools.get(datasourceName); if (pool != null) { driverClass = drivers.elementAt(0); } return driverClass; }*/ public String getDriverClassForPool() { String driverClass = null; //ConnectionPool pool = (ConnectionPool) pools.get(datasourceName); if (this.drivers != null) { driverClass = ((Driver) this.drivers.elementAt(0)).getClass().getName(); } return driverClass; //return getDriverClassForPool(DEFAULT_DSN); } public Connection recycleConnection(Connection conn) { return recycleConnection(conn, DEFAULT_DSN); } public Connection recycleConnection(Connection conn, String dataSourceName) { ConnectionPool pool = (ConnectionPool) this.pools.get(dataSourceName); return pool.recycleConnection(conn); } /** * Trims the pool so that it has only size connections */ public void trimTo(String datasourceName, int size) { trimTo(datasourceName, size, size, size); } /** * Trims the pool so that it has only size,minSize,maxSize connections */ public void trimTo(String datasourceName, int size, int minSize, int maxSize) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { pool.trimTo(size, minSize, maxSize); } } /** * Enlarges the pool so it has size number of connections */ public void enlargeTo(String datasourceName, int size) { this.enlargeTo(datasourceName, size, size, size); } /** * Enlarges the pool so it has size number of connections */ public void enlargeTo(String datasourceName, int size, int minSize, int maxSize) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { pool.enlargeTo(size, minSize, maxSize); } } public int getCurrentConnectionCount(String datasourceName) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { return pool.getCurrentConnectionCount(); } return 0; } public int getMaximumConnectionCount(String datasourceName) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { return pool.getMaximumConnectionCount(); } return 0; } public int getMaximumConnectionCount() { return getMaximumConnectionCount(DEFAULT_DSN); } public int getMinimumConnectionCount(String datasourceName) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { return pool.getMinimumConnectionCount(); } return 0; } public int getMinimumConnectionCount() { return getMinimumConnectionCount(DEFAULT_DSN); } public int getTimeOut(String datasourceName) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { return pool.getTimeOut(); } return 0; } public void setTimeOut(String datasourceName, int timeout) { ConnectionPool pool = (ConnectionPool) this.pools.get(datasourceName); if (pool != null) { pool.setTimeOut(timeout); } } }