/** * Alipay.com Inc. * Copyright (c) 2004-2013 All Rights Reserved. */ package com.alipay.zdal.client.config; import java.io.File; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.util.CollectionUtils; import com.alipay.zdal.client.config.bean.AppDataSourceBean; import com.alipay.zdal.client.config.bean.PhysicalDataSourceBean; import com.alipay.zdal.client.config.bean.ZdalAppBean; import com.alipay.zdal.client.config.exceptions.ZdalConfigException; import com.alipay.zdal.common.Constants; /** * <p> * A single loader to load Zdal configurations via Web Service or local * directory in order to initialize Zdal data source context. Afterward, it * holds all zdal configurations across applications distinguish by unique id * consist of appName + dbMode + zone * </p> * * @author <a href="mailto:xiang.yangx@alipay.com">Yang Xiang</a> * */ public class ZdalConfigurationLoader { private static final Logger log = Logger .getLogger(Constants.CONFIG_LOG_NAME_LOGNAME); private static final ZdalConfigurationLoader instance = new ZdalConfigurationLoader(); /** ���app����������Դ��������Ϣ��key=appName value=(key = appDsName,value = zdalconfig )*/ private Map<String, Map<String, ZdalConfig>> appDsConfigs = new HashMap<String, Map<String, ZdalConfig>>(); public static ZdalConfigurationLoader getInstance() { return instance; } /** * Load Zdal configuration context via Spring XmlApplicationContext when the * zdal has not been loaded up. If application's Zdal configuration has been * loaded up, just fetch the zdal config from the single configuration map. * * @param appName * @param dbMode * @param idcName * @param appDsName * @param zdataconsoleUrl * @param configPath * @return */ public synchronized ZdalConfig getZdalConfiguration(String appName, String dbMode, String appDsName, String configPath) { Map<String, ZdalConfig> configs = appDsConfigs.get(appName); if (configs == null || configs.isEmpty()) { Map<String, ZdalConfig> maps = getZdalConfigurationFromLocal(appName, dbMode, appDsName, configPath); appDsConfigs.put(appName, maps); return maps.get(appDsName); } else { return configs.get(appDsName); } } /** * It is pretty much as same as getZdalConfiguration, but it only load * configuration from local which given parameter configPath. * * @param appName * @param dbMode * @param idcName * @param appDsName * @param configPath * Given path to load applications's data source and rule * configuraiton files. * @return */ private synchronized Map<String, ZdalConfig> getZdalConfigurationFromLocal(String appName, String dbMode, String appDsName, String configPath) { List<String> zdalConfigurationFilePathList = new ArrayList<String>(); File configurationFile = new File(configPath, MessageFormat.format( Constants.LOCAL_CONFIG_FILENAME_SUFFIX, appName, dbMode)); if (configurationFile.exists() && configurationFile.isFile()) { zdalConfigurationFilePathList.add(configurationFile.getAbsolutePath()); } configurationFile = new File(configPath, MessageFormat.format( Constants.LOCAL_RULE_CONFIG_FILENAME_SUFFIX, appName, dbMode)); if (configurationFile.exists() && configurationFile.isFile()) { zdalConfigurationFilePathList.add(configurationFile.getAbsolutePath()); } if (zdalConfigurationFilePathList.isEmpty()) { throw new ZdalConfigException( "ERROR ## There is no local Zdal configuration files for " + appName + " to initialize ZdalDataSource."); } return loadZdalConfigurationContext(zdalConfigurationFilePathList .toArray(new String[zdalConfigurationFilePathList.size()]), appName, dbMode); } /** * * @param fileNames * @param appName * @param dbMode * @param idcName */ private synchronized Map<String, ZdalConfig> loadZdalConfigurationContext(String[] fileNames, String appName, String dbMode) { Map<String, ZdalConfig> zdalConfigMap = new HashMap<String, ZdalConfig>(); try { FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext(fileNames); if (null == ctx.getBean(appName)) { throw new ZdalConfigException("ERROR ## It must has at least one app bean in " + appName + " Zdal configuration file "); } ZdalAppBean appBean = (ZdalAppBean) ctx.getBean(appName); if (CollectionUtils.isEmpty(appBean.getAppDataSourceList())) { throw new ZdalConfigException( "ERROR ## It must has at least one appDataSource bean in " + appName + " ZdalAppBean"); } if (!appName.equals(appBean.getAppName())) { throw new ZdalConfigException("ERROR ## the configured appName is " + appBean.getAppName() + " are not match with requested appName:" + appName); } if (!dbMode.equals(appBean.getDbmode())) { throw new ZdalConfigException("ERROR ## The configured dbMode is " + appBean.getDbmode() + " are not match with requested dbMode: " + dbMode); } for (AppDataSourceBean appDataSourceBean : appBean.getAppDataSourceList()) { zdalConfigMap.put(appDataSourceBean.getAppDataSourceName(), populateZdalConfig( appBean, appDataSourceBean)); } return zdalConfigMap; } catch (Exception e) { StringBuilder stb = new StringBuilder(); stb.append("Error### Zdal failed to load Zdal datasource and rule context with files "); for (String fileName : fileNames) { stb.append(fileName).append(", "); } stb.append(" when Zdal was loading them."); log.error(stb.toString(), e); throw new ZdalConfigException(e); } } /** * * @param appBean * @param appDataSourceBean * @return */ protected ZdalConfig populateZdalConfig(ZdalAppBean appBean, AppDataSourceBean appDataSourceBean) { ZdalConfig config = new ZdalConfig(); config.setAppName(appBean.getAppName()); config.setDbmode(appBean.getDbmode()); config.setAppDsName(appDataSourceBean.getAppDataSourceName()); config.setDbType(appDataSourceBean.getDbType()); config.setDataSourceConfigType(appDataSourceBean.getDataSourceConfigType()); // Set Rule config.setAppRootRule(appDataSourceBean.getAppRule()); for (PhysicalDataSourceBean physicalDataSource : appDataSourceBean .getPhysicalDataSourceSet()) { config.getDataSourceParameters().put(physicalDataSource.getName(), DataSourceParameter.valueOf(physicalDataSource)); if (null != physicalDataSource.getLogicDbNameSet() && !physicalDataSource.getLogicDbNameSet().isEmpty()) { for (String logicDBName : physicalDataSource.getLogicDbNameSet()) { config.getLogicPhysicsDsNames().put(logicDBName, physicalDataSource.getName()); } } } config.setGroupRules(appDataSourceBean.getGroupDataSourceRuleMap()); config.setFailoverRules(appDataSourceBean.getFailOverGroupRuleMap()); return config; } }