package com.venky.swf.db.jdbc; import java.lang.reflect.Method; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import javax.sql.DataSource; import com.venky.cache.Cache; import com.venky.core.string.StringUtil; import com.venky.core.util.ObjectUtil; import com.venky.swf.db.Database; import com.venky.swf.db.JdbcTypeHelper; import com.venky.swf.db.platform.Platform; import com.venky.swf.routing.Config; public class ConnectionManager { private static ConnectionManager _instance ; public static ConnectionManager instance(){ if (_instance != null){ return _instance; } synchronized (ConnectionManager.class) { if (_instance == null){ _instance = new ConnectionManager(); } } return _instance; } private ConnectionManager(){ loadPools(); } private Cache<String,Class<?>> driverClassCache = new Cache<String, Class<?>>() { /** * */ private static final long serialVersionUID = 3352757744534631289L; @Override protected Class<?> getValue(String pool) { String driver = "[]"; try { driver = Config.instance().getProperty(getNormalizedPropertyName("swf.jdbc."+pool+".driver")); return Class.forName(driver); }catch (Exception e){ throw new RuntimeException("Pool " + pool + " driver not found " + driver, e); } } }; public String getNormalizedPropertyName(String name){ return name.replace("..","."); } private List<String> pools = null; private void loadPools(){ if (pools == null) { pools = new ArrayList<String>(); List<String> keys = Config.instance().getPropertyKeys("swf\\.jdbc\\..*driver"); for (String key : keys) { StringTokenizer t = new StringTokenizer(key, "."); String pool = ""; if (t.countTokens() > 3) { t.nextToken();//swf t.nextToken();//jdbc pool = t.nextToken();//poolname } pools.add(pool); } } } public List<String> getPools(){ return pools; } public Class<?> getDriverClass(String pool){ return driverClassCache.get(pool); } public JdbcTypeHelper getJdbcTypeHelper(String pool) { return JdbcTypeHelper.instance(getDriverClass(pool)); } private Cache<String,DataSource> dsCache = new Cache<String, DataSource>() { /** * */ private static final long serialVersionUID = -4782855310119130688L; @Override protected DataSource getValue(String pool) { if (!isConnectionPooled(pool)){ return null; } Properties info = Platform.getConnectionProperties(pool); info.setProperty("driverClassName",getDriverClass(pool).getName()); info.setProperty("validationQuery",Config.instance().getProperty(getNormalizedPropertyName("swf.jdbc."+pool+".validationQuery"), "select 1 as dbcp_connection_test")); info.setProperty("testOnBorrow", "true"); info.setProperty("testOnReturn", "true"); info.setProperty("testWhileIdle", "false"); info.setProperty("maxActive", "-1"); String poolFix = ObjectUtil.isVoid(pool) ? "" : "\\." + pool; for (String key : Config.instance().getPropertyKeys("swf\\.jdbc"+poolFix+"\\.datasource\\..*")){ String newKey = key.replaceAll("swf\\.jdbc"+poolFix+"\\.datasource\\.",""); info.setProperty(newKey, Config.instance().getProperty(key)); } //Config.instance().getLogger(getClass().getName()).finest("Connection Pool Properties:\n" + info.toString()); try { Class<?> c = Class.forName("org.apache.commons.dbcp.BasicDataSourceFactory"); Method m = c.getMethod("createDataSource", Properties.class); return (DataSource) m.invoke(c, info); }catch (Exception e) { throw new RuntimeException(e); } } public boolean isConnectionPooled(String pool){ String value = Config.instance().getProperty(getNormalizedPropertyName("swf.jdbc."+pool+".connection.pooling"), "true"); return Boolean.valueOf(StringUtil.valueOf(Database.getJdbcTypeHelper(pool).getTypeRef(Boolean.class).getTypeConverter().valueOf(value))); } }; public Connection createConnection(String pool){ DataSource ds = dsCache.get(pool); try { if (ds == null){ Properties props = Platform.getConnectionProperties(pool); return DriverManager.getConnection(props.getProperty("url"), Platform.getConnectionProperties(pool)); }else { return ds.getConnection(); } } catch (SQLException e) { throw new RuntimeException(e); } } private Cache<String,List<String>> sameDBpools = new Cache<String, List<String>>(0,0) { /** * */ private static final long serialVersionUID = -6568310584085285249L; @Override protected List<String> getValue(String pool) { List<String> pools = new ArrayList<String>(); String url = Platform.getConnectionProperties(pool).getProperty("url"); for (String tpool : getPools()){ if (Platform.getConnectionProperties(tpool).getProperty("url").equals(url)){ pools.add(pool); } } return pools; } }; public boolean isPoolReadOnly(String pool){ boolean readOnly = false; if (!readOnly){ for (String tPool : sameDBpools.get(pool) ){ readOnly = readOnly || Config.instance().getBooleanProperty(getNormalizedPropertyName("swf.jdbc."+tPool+".readOnly"),false); } } return readOnly; } public void close() { List<String> allPools = new ArrayList<String>(dsCache.keySet()); for (String pool : allPools) { DataSource ds = dsCache.get(pool); if (ds != null) { try { Method close = ds.getClass().getMethod("close"); close.invoke(ds); Config.instance().getLogger(getClass().getName()).info("Closed Data Source"); } catch (Exception e) { Config.instance().getLogger(getClass().getName()).info("DataSource not closed " + e.getMessage()); } finally { dsCache.remove(pool); } } } } }