package com.lizard.fastdb.datasource; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import com.lizard.fastdb.connection.ConnectionProvider; import com.lizard.fastdb.connection.ConnectionProviderFactory; import com.lizard.fastdb.util.StringUtils; /** * DB缓存池管理,主要包括数据源缓存,软连接缓存,以及ConnectionProvider缓存 * * @author SHEN.GANG */ public class DataSourceCache { /** * 数据源对象池<br> * key:数据源对象名(name)<br> * value:数据源对象 */ public static ConcurrentMap<String, Properties> DATASOURCE_POOL = new ConcurrentHashMap<String, Properties>(); /** * 软连接池<br> * key:虚拟数据源<br> * value:真实数据源 */ public static ConcurrentMap<String, String> LINKMAPPING_POOL = new ConcurrentHashMap<String, String>(); /** * 连接策略对象池<br> * key:策略对象所属的数据源名称<br> * value:策略对象 */ public static ConcurrentMap<String, ConnectionProvider> CONNECTIONPROVIDER_POOL = new ConcurrentHashMap<String, ConnectionProvider>(); /** * 将数据源存入缓存 * * @param ds 数据源配置对象 */ public static void putDataSource(Properties ds) { DATASOURCE_POOL.putIfAbsent(ds.getProperty("name").toLowerCase(), ds); } /** * 新增软连接 * * @param virtual 虚拟数据源名称 * @param real 真实数据源名称 */ public static void putLinkmapping(String virtual, String real) { LINKMAPPING_POOL.put(virtual.toLowerCase(), real.toLowerCase()); } /** * 保存ConnectionProvider * * @param name ConnectionProvider对象所属的数据源名称 * @param cp ConnectionProvider对象 */ private static void putConnectionProvider(String name, ConnectionProvider cp) { CONNECTIONPROVIDER_POOL.putIfAbsent(name.toLowerCase(), cp); } /** * 移除缓存中指定名称的数据源 * * @param name 数据源名称 */ protected static void evictDataSource(String name) { DATASOURCE_POOL.remove(name.toLowerCase()); } /** * 移除软连接 * * @param virtual 虚拟数据源名称 */ protected static void evictLinkmapping(String virtual) { virtual = virtual.toLowerCase(); // 要移除的key列表 List<String> keys = new ArrayList<String>(); keys.add(virtual); for (String key : LINKMAPPING_POOL.keySet()) { if (LINKMAPPING_POOL.get(key).equals(virtual)) { keys.add(key); } } for (int i = 0; i < keys.size(); i++) { LINKMAPPING_POOL.remove(keys.get(i)); } } /** * 从缓存中移除指定数据源的ConnectionProvider对象 * * @param name 数据源名称 */ protected static void evictConnectionProvider(String name) { CONNECTIONPROVIDER_POOL.remove(name.toLowerCase()); } /** * 从缓存中获得指定名称的数据源对象 * * @param name 数据源名称或软连接名称 * @return 数据源对象 */ public static Properties getDataSource(String name) { String fina_link_to = getFinalLinkTo(name); if (!StringUtils.isEmptyString(fina_link_to)) { return DATASOURCE_POOL.get(fina_link_to); } else { return null; } } /** * 获得软连接的指向的真实数据源 * * @param virtual 虚拟或真实数据源名称 * @return 真实数据源名称 */ protected static String getFinalLinkTo(String virtual) { virtual = virtual.toLowerCase(); String real = LINKMAPPING_POOL.get(virtual); while (real != null && !virtual.equals(real)) { virtual = real; real = LINKMAPPING_POOL.get(virtual); } return real; } /** * 从缓存中获得指定的连接提供对象,如果不存在则返回null * * @param name 对象名称 * @return 连接对象 */ public static ConnectionProvider getConnectionProvider(String name) { String real = getFinalLinkTo(name); if (real == null) { return null; } return CONNECTIONPROVIDER_POOL.get(real); } /** * 获得或创建ConnectionProvider对象,如果缓存中不存在,则创建并放入缓存 * * @param ds 数据源配置 * @return ConnectionProvider对象 */ protected static ConnectionProvider createConnectionProvider(Properties ds) { ConnectionProvider connP = ConnectionProviderFactory.createConnectionProvider(ds); putConnectionProvider(ds.getProperty("name"), connP); return connP; } /** * 获得数据源对象池 * * @return 数据源对象池 */ protected static Map<String, Properties> getDataSourcePool() { return DATASOURCE_POOL; } /** * 获得连接提供对象池 * * @return ConnectionProvider池 */ protected static Map<String, ConnectionProvider> getConnectionProviderPool() { return CONNECTIONPROVIDER_POOL; } /** * 判断当前数据源缓存中是否存在指定名称的数据源 * * @param name 数据源名称 * @return true -- 存在,false -- 不存在 */ public static boolean containDataSource(String name) { return DATASOURCE_POOL.containsKey(name.toLowerCase()); } /** * 检查当前数据源配置是否在缓存中以存在,判断方式是检查url、username、password是否完全相等 * * @param prop 数据源配置 * @return 存在重复 -- 重复的数据源名称,不存在重复 -- null */ protected static String isDataSourceRepeated(Properties prop) { String driver_url = prop.getProperty("driver-url"); String user = prop.getProperty("user"); String password = prop.getProperty("password"); // 去除url后面的参数 int index = driver_url.lastIndexOf("?"); if (index != -1) { driver_url = driver_url.substring(0, index); } Iterator<String> iter = DATASOURCE_POOL.keySet().iterator(); while (iter.hasNext()) { Properties ds = DATASOURCE_POOL.get(iter.next()); String ds_driver_url = ds.getProperty("driver-url"); String ds_user = ds.getProperty("user"); String ds_password = ds.getProperty("password"); index = ds_driver_url.lastIndexOf("?"); if (index != -1) { ds_driver_url = ds_driver_url.substring(0, index); } // 数据源相同的判断条件是:user、password、url 三者完全相同 if (driver_url.equalsIgnoreCase(ds_driver_url) && user.equalsIgnoreCase(ds_user) && password.equalsIgnoreCase(ds_password)) { return ds.getProperty("name"); } } return null; } /** * 清理缓存 */ protected static void clean() { DATASOURCE_POOL.clear(); LINKMAPPING_POOL.clear(); CONNECTIONPROVIDER_POOL.clear(); DATASOURCE_POOL = null; LINKMAPPING_POOL = null; CONNECTIONPROVIDER_POOL = null; } }