com.taobao.tddl.jdbc.group.config.ConfigManager.java Source code

Java tutorial

Introduction

Here is the source code for com.taobao.tddl.jdbc.group.config.ConfigManager.java

Source

/*(C) 2007-2012 Alibaba Group Holding Limited.   
 *This program is free software; you can redistribute it and/or modify   
*it under the terms of the GNU General Public License version 2 as   
* published by the Free Software Foundation.   
* Authors:   
*   junyu <junyu@taobao.com> , shenxun <shenxun@taobao.com>,   
*   linxuan <linxuan@taobao.com> ,qihao <qihao@taobao.com>    
*/
package com.taobao.tddl.jdbc.group.config;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;

import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.taobao.tddl.common.DataSourceChangeListener;
import com.taobao.tddl.common.config.ConfigDataHandler;
import com.taobao.tddl.common.config.ConfigDataHandlerFactory;
import com.taobao.tddl.common.config.ConfigDataListener;
import com.taobao.tddl.common.config.impl.DefaultConfigDataHandlerFactory;
import com.taobao.tddl.common.util.DataSourceFetcher;
import com.taobao.tddl.common.util.TStringUtil;
import com.taobao.tddl.interact.rule.bean.DBType;
import com.taobao.tddl.jdbc.atom.TAtomDataSource;
import com.taobao.tddl.jdbc.atom.config.object.AtomDbStatusEnum;
import com.taobao.tddl.jdbc.group.DataSourceWrapper;
import com.taobao.tddl.jdbc.group.TGroupDataSource;
import com.taobao.tddl.jdbc.group.dbselector.AbstractDBSelector;
import com.taobao.tddl.jdbc.group.dbselector.DBSelector;
import com.taobao.tddl.jdbc.group.dbselector.EquityDbManager;
import com.taobao.tddl.jdbc.group.dbselector.OneDBSelector;
import com.taobao.tddl.jdbc.group.dbselector.PriorityDbGroupSelector;
import com.taobao.tddl.jdbc.group.dbselector.RuntimeWritableAtomDBSelector;
import com.taobao.tddl.jdbc.group.exception.ConfigException;
import com.taobao.tddl.jdbc.group.exception.TAtomDataSourceException;

/**
 * ConfigManagerTGroupDataSource
 * GroupdataIDdb0:rwp1q1i0, db1:rwp0q0i1
 * GroupGroupAtom db0  db1   Map<String,
 * DataSourceWrapper>  String Atom DS dbKey DataSourceWrapper
 * TAtomDataSource
 * ---AtomDataSourceAtomDataSource ***
 *
 *
 * Atom DataSourceAtom
 * dbKeydbKeyAtomAtomDataSource ***
 *
 * mapdbKeyDatasourceGroup
 * GroupDB
 * DBSelector ***
 *
 *
 *
 * @author yangzhu
 * @author linxuan refactor
 *
 */
public class ConfigManager {
    private static final Log logger = LogFactory.getLog(ConfigManager.class);

    private final ConfigDataListener configReceiver; // //Diamond
    private ConfigDataHandlerFactory configFactory;
    private ConfigDataHandler globalHandler;

    //add by junyu
    private final ConfigDataListener extraGroupConfigReceiver;
    private ConfigDataHandler extraHandler;
    private ConfigDataHandlerFactory extraFactory;

    private final TGroupDataSource tGroupDataSource;

    private boolean createTAtomDataSource = true;

    private Map<String/* Atom dbIndex */, DataSourceWrapper/* WrapperAtom DS */> dataSourceWrapperMap = new HashMap<String, DataSourceWrapper>();

    private volatile GroupExtraConfig groupExtraConfig = new GroupExtraConfig();

    public ConfigManager(TGroupDataSource tGroupDataSource) {
        this.tGroupDataSource = tGroupDataSource;
        this.configReceiver = new ConfigReceiver();
        this.extraGroupConfigReceiver = new ExtraGroupConfigReceiver();
    }

    /**
     * DiamondTAtomDataSourceDBSelector ---add by
     * mazhidan.pt
     */
    public void init() {
        // : DefaultDiamondManagerManagerListener(:configReceiver)
        // : new DefaultDiamondManager(dbGroupKey, configReceiver)
        // null
        // DiamondManagerListener
        // ManagerListener
        configFactory = new DefaultConfigDataHandlerFactory();
        globalHandler = configFactory.getConfigDataHandler(tGroupDataSource.getFullDbGroupKey(), null);

        String dsWeightCommaStr = globalHandler.getData(tGroupDataSource.getConfigReceiveTimeout(),
                ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY);

        //extra config
        extraFactory = new DefaultConfigDataHandlerFactory();
        extraHandler = extraFactory.getConfigDataHandler(tGroupDataSource.getDbGroupExtraConfigKey(), null);
        String extraConfig = extraHandler.getData(tGroupDataSource.getConfigReceiveTimeout(),
                ConfigDataHandler.FIRST_CACHE_THEN_SERVER_STRATEGY);

        if (extraConfig != null) {
            parseExtraConfig(extraConfig);
            extraHandler.addListener(extraGroupConfigReceiver, null);
        }

        List<DataSourceWrapper> dswList = parse2DataSourceWrapperList(dsWeightCommaStr);
        resetByDataSourceWrapper(dswList);
        globalHandler.addListener(configReceiver, null);
    }

    /**
     * DataSourceDBSelector
     */
    public void init(List<DataSourceWrapper> dataSourceWrappers) {
        if ((dataSourceWrappers == null) || dataSourceWrappers.size() < 1) {
            throw new ConfigException("dataSourceWrappersnull0");
        }
        createTAtomDataSource = false;
        // update(createDBSelectors2(dataSourceWrappers));
        resetByDataSourceWrapper(dataSourceWrappers);
    }

    private class MyDataSourceFetcher implements DataSourceFetcher {
        private DBType dbType = DBType.MYSQL;

        @Override
        public DataSource getDataSource(String dsKey) {
            DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey);
            if (dsw != null) {
                dbType = dsw.getDBType();
                return dsw.getWrappedDataSource();
            } else {
                if (createTAtomDataSource) {
                    TAtomDataSource atom = createTAtomDataSource(dsKey);
                    dbType = DBType.valueOf(atom.getDbType().name());
                    return atom;
                } else {
                    throw new IllegalArgumentException(dsKey + " not exist!");
                }
            }
        }

        @Override
        public DBType getDataSourceDBType(String key) {
            return dbType;
        }
    };

    // configInfo: db1:rw, db2:r, db3:r
    private void parse(String dsWeightCommaStr) {
        List<DataSourceWrapper> dswList = parse2DataSourceWrapperList(dsWeightCommaStr);
        resetByDataSourceWrapper(dswList);
    }

    /**
     * extraConfig is a json format string,include table dataSourceIndex
     * relation or sql dataSourceIndex relation or default go main db config.
     * example: {sqlDsIndex: { 0:[sql1,sql2,sql3], 1:[sql0], 2:[sql4]
     * }, tabDsIndex: { 0:[table1,table2] 1:[table3,table4] },
     * defaultMain:true}
     *
     * @throws JSONException
     *
     **/
    @SuppressWarnings("rawtypes")
    private void parseExtraConfig(String extraConfig) {
        if (extraConfig == null) {
            this.groupExtraConfig.getSqlForbidSet().clear();
            this.groupExtraConfig.getSqlDsIndexMap().clear();
            this.groupExtraConfig.getTableDsIndexMap().clear();
            this.groupExtraConfig.setDefaultMain(false);
        }
        try {
            JSONObject obj = JSONObject.fromObject(extraConfig);
            if (obj.has("sqlForbid")) {
                Set<String> tempSqlForbidSet = new HashSet<String>();
                JSONArray array = obj.getJSONArray("sqlForbid");
                for (int i = 0; i < array.size(); i++) {
                    String sql = array.getString(i);
                    String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase());
                    if (nomalSql != null && !nomalSql.trim().isEmpty()) {
                        tempSqlForbidSet.add(nomalSql);
                    }
                }
                this.groupExtraConfig.setSqlForbidSet(tempSqlForbidSet);
            } else {
                this.groupExtraConfig.getSqlForbidSet().clear();
            }

            if (obj.has("sqlDsIndex")) {
                Map<String, Integer> tempSqlDsIndexMap = new HashMap<String, Integer>();
                JSONObject sqlDsIndex = obj.getJSONObject("sqlDsIndex");
                Iterator it = sqlDsIndex.keys();
                while (it.hasNext()) {
                    String key = String.valueOf(it.next()).trim();
                    Integer index = Integer.valueOf(key);
                    JSONArray array = sqlDsIndex.getJSONArray(key);
                    for (int i = 0; i < array.size(); i++) {
                        String sql = array.getString(i);
                        String nomalSql = TStringUtil.fillTabWithSpace(sql.trim().toLowerCase());
                        if (tempSqlDsIndexMap.get(nomalSql) == null) {
                            tempSqlDsIndexMap.put(nomalSql, index);
                        } else {
                            // have a nice log
                            throw new ConfigException("sql can not be route to different dataSourceIndex:" + sql);
                        }
                    }
                }
                this.groupExtraConfig.setSqlDsIndexMap(tempSqlDsIndexMap);
            } else {
                this.groupExtraConfig.getSqlDsIndexMap().clear();
            }

            if (obj.has("tabDsIndex")) {
                Map<String, Integer> tempTabDsIndexMap = new HashMap<String, Integer>();
                JSONObject sqlDsIndex = obj.getJSONObject("tabDsIndex");
                Iterator it = sqlDsIndex.keys();
                while (it.hasNext()) {
                    String key = String.valueOf(it.next()).trim();
                    Integer index = Integer.valueOf(key);
                    JSONArray array = sqlDsIndex.getJSONArray(key);
                    for (int i = 0; i < array.size(); i++) {
                        String table = array.getString(i);
                        String nomalTable = table.trim().toLowerCase();
                        if (tempTabDsIndexMap.get(nomalTable) == null) {
                            tempTabDsIndexMap.put(nomalTable, index);
                        } else {
                            // have a nice log
                            throw new ConfigException(
                                    "table can not be route to different dataSourceIndex:" + table);
                        }
                    }
                }
                this.groupExtraConfig.setTableDsIndexMap(tempTabDsIndexMap);
            } else {
                this.groupExtraConfig.getTableDsIndexMap().clear();
            }

            if (obj.has("defaultMain")) {
                this.groupExtraConfig.setDefaultMain(obj.getBoolean("defaultMain"));
            } else {
                this.groupExtraConfig.setDefaultMain(false);
            }

        } catch (JSONException e) {
            throw new ConfigException("group extraConfig is not json valid string:" + extraConfig, e);
        }
    }

    /**
     * :   =
     * +1012..."db1,,db3"3
     * ThreadLocalThreadLocal
     */
    private List<DataSourceWrapper> parse2DataSourceWrapperList(String dsWeightCommaStr) {
        logger.info("[parse2DataSourceWrapperList]dsWeightCommaStr=" + dsWeightCommaStr);
        if ((dsWeightCommaStr == null) || (dsWeightCommaStr = dsWeightCommaStr.trim()).length() == 0) {
            throw new ConfigException("dbGroupKey:'" + tGroupDataSource.getFullDbGroupKey()
                    + "'null0");
        }
        return buildDataSourceWrapper(dsWeightCommaStr, new MyDataSourceFetcher());
    }

    /**
     * AtomDataSourceDBSelector ---add by
     * mazhidan.pt
     *
     * @param dswList
     */
    private void resetByDataSourceWrapper(List<DataSourceWrapper> dswList) {
        // DataSourceWrapper
        Map<String, DataSourceWrapper> newDataSourceWrapperMap = new HashMap<String, DataSourceWrapper>(
                dswList.size());
        for (DataSourceWrapper dsw : dswList) {
            newDataSourceWrapperMap.put(dsw.getDataSourceKey(), dsw);
        }
        Map<String, DataSourceWrapper> old = this.dataSourceWrapperMap;
        this.dataSourceWrapperMap = newDataSourceWrapperMap;
        old.clear();
        old = null;

        DBSelector r_DBSelector = null;
        DBSelector w_DBSelector = null;

        // dbOneDBSelector
        if (dswList.size() == 1) {
            DataSourceWrapper dsw2 = dswList.get(0);
            r_DBSelector = new OneDBSelector(dsw2);
            r_DBSelector.setDbType(dsw2.getDBType());
            w_DBSelector = r_DBSelector;
        } else {
            // Map
            Map<Integer/*  */, List<DataSourceWrapper>/* keyDS  */> rPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>();
            Map<Integer, List<DataSourceWrapper>> wPriority2DswList = new HashMap<Integer, List<DataSourceWrapper>>();
            for (DataSourceWrapper dsw1 : dswList) {
                add2LinkedListMap(rPriority2DswList, dsw1.getWeight().p, dsw1);
                add2LinkedListMap(wPriority2DswList, dsw1.getWeight().q, dsw1);
            }
            r_DBSelector = createDBSelector(rPriority2DswList, true);
            w_DBSelector = createDBSelector(wPriority2DswList, false);
        }

        r_DBSelector.setReadable(true);
        w_DBSelector.setReadable(false);

        this.readDBSelectorWrapper = r_DBSelector;
        this.writeDBSelectorWrapper = w_DBSelector;

        if (tGroupDataSource.getAutoSelectWriteDataSource())
            runtimeWritableAtomDBSelectorWrapper = new RuntimeWritableAtomDBSelector(dataSourceWrapperMap,
                    groupExtraConfig);

        // System.out.println("dataSourceWrapperMap=" + dataSourceWrapperMap);
        if (this.dataSourceChangeListener != null) {
            dataSourceChangeListener.onDataSourceChanged(null);// getDataSource()
        }
    }

    private DataSourceChangeListener dataSourceChangeListener;

    public void setDataSourceChangeListener(DataSourceChangeListener dataSourceChangeListener) {
        this.dataSourceChangeListener = dataSourceChangeListener;
    }

    /*
     * //21readwrite private DBSelector[]
     * createDBSelectors(List<String> dbKeyAndWeightList) { DBSelector
     * r_DBSelector = null; DBSelector w_DBSelector = null;
     *
     * //dbOneDBSelector if (dbKeyAndWeightList.size() == 1) { String[]
     * dbKeyAndWeight = split(dbKeyAndWeightList.get(0), ":"); DataSourceWrapper
     * dsw = createDataSourceWrapper(dbKeyAndWeight[0], (dbKeyAndWeight.length
     * == 2 ? dbKeyAndWeight[1] : null), 0); //0
     *
     * r_DBSelector = new OneDBSelector(dsw);
     * r_DBSelector.setDbType(dsw.getDBType()); w_DBSelector = r_DBSelector; }
     * else { List<List<DataSourceWrapper>> rDataSourceWrappers = new
     * ArrayList<List<DataSourceWrapper>>(); List<List<DataSourceWrapper>>
     * wDataSourceWrappers = new ArrayList<List<DataSourceWrapper>>();
     *
     * for (int i = 0; i < dbKeyAndWeightList.size(); i++) { String[]
     * dbKeyAndWeight = split(dbKeyAndWeightList.get(i), ":");
     *
     * DataSourceWrapper dsw = createDataSourceWrapper(dbKeyAndWeight[0],
     * (dbKeyAndWeight.length == 2 ? dbKeyAndWeight[1] : null), i);
     *
     * insertSort(rDataSourceWrappers, dsw, true);
     * insertSort(wDataSourceWrappers, dsw, false); }
     *
     * r_DBSelector = createDBSelector(rDataSourceWrappers, true); w_DBSelector
     * = createDBSelector(wDataSourceWrappers, false); }
     *
     * r_DBSelector.setReadable(true); w_DBSelector.setReadable(false);
     *
     * return new DBSelector[] { r_DBSelector, w_DBSelector }; }
     */

    /**
     * k  V list  ----DS ---add by
     * mazhidan.pt
     */
    private static <K, V> void add2LinkedListMap(Map<K, List<V>> m, K key, V value) {
        // MapList
        List<V> c = (List<V>) m.get(key);
        // new
        if (c == null) {
            c = new LinkedList<V>();
            m.put(key, c);
        }
        // add()
        c.add(value);
    }

    /**
     * @param dsWeightCommaStr
     *            :  db0:rwp1q1i0, db1:rwp0q0i1
     */
    public static List<DataSourceWrapper> buildDataSourceWrapper(String dsWeightCommaStr,
            DataSourceFetcher fetcher) {
        String[] dsWeightArray = dsWeightCommaStr.split(","); // db0:rwp1q1i0,
        // db1:rwp0q0i1
        List<DataSourceWrapper> dss = new ArrayList<DataSourceWrapper>(dsWeightArray.length);
        for (int i = 0; i < dsWeightArray.length; i++) {
            String[] dsAndWeight = dsWeightArray[i].split(":"); // db0:rwp1q1i0
            String dsKey = dsAndWeight[0].trim();
            String weightStr = dsAndWeight.length == 2 ? dsAndWeight[1] : null;

            // groupdataSourcegroup
            // dataSource dataSource
            DataSource dataSource = fetcher.getDataSource(dsKey);
            DBType fetcherDbType = fetcher.getDataSourceDBType(dsKey);
            // dbType = fetcherDbType == null ? dbType : fetcherDbType;
            DataSourceWrapper dsw = new DataSourceWrapper(dsKey, weightStr, dataSource, fetcherDbType, i);
            dss.add(dsw);
        }
        return dss;
    }

    /**
     * DataSourceMapDBSelector---add by mazhidan.pt
     *
     * @param priority2DswList
     * @param isRead
     * @return
     */
    private DBSelector createDBSelector(Map<Integer/*  */, List<DataSourceWrapper>> priority2DswList,
            boolean isRead) {
        if (priority2DswList.size() == 1) { // EquityDbManager
            return createDBSelector2(priority2DswList.entrySet().iterator().next().getValue(), isRead);
        } else {
            List<Integer> priorityKeys = new LinkedList<Integer>();
            priorityKeys.addAll(priority2DswList.keySet());
            Collections.sort(priorityKeys); // 
            EquityDbManager[] priorityGroups = new EquityDbManager[priorityKeys.size()];
            for (int i = 0; i < priorityGroups.length; i++) { // 
                List<DataSourceWrapper> dswList = priority2DswList.get(priorityGroups.length - 1 - i); // 
                // PriorityDbGroupSelectorEquityDbManagerNoMoreDataSourceException
                // dsEquityDbManager
                priorityGroups[i] = createEquityDbManager(dswList, isRead, groupExtraConfig);

            }
            return new PriorityDbGroupSelector(priorityGroups);
        }
    }

    private AbstractDBSelector createDBSelector2(List<DataSourceWrapper> dswList, boolean isRead) {
        AbstractDBSelector dbSelector;
        if (dswList.size() == 1) {
            DataSourceWrapper dsw = dswList.get(0);
            dbSelector = new OneDBSelector(dsw);
            dbSelector.setDbType(dsw.getDBType());
        } else {
            dbSelector = createEquityDbManager(dswList, isRead, groupExtraConfig);
        }
        return dbSelector;
    }

    /*
     * private DBSelector createDBSelector(List<List<DataSourceWrapper>> list,
     * boolean isRead) {
     *
     * int size = list.size(); // if (size == 1) {
     * //EquityDbManager return createEquityDbManager(list.get(0),
     * isRead); } else { EquityDbManager[] priorityGroups = new
     * EquityDbManager[size]; for (int i = 0; i < size; i++) { priorityGroups[i]
     * = createEquityDbManager(list.get(i), isRead); } return new
     * PriorityDbGroupSelector(priorityGroups); } }
     */

    private static EquityDbManager createEquityDbManager(List<DataSourceWrapper> list, boolean isRead,
            GroupExtraConfig groupExtraConfig) {
        Map<String, DataSourceWrapper> dataSourceMap = new HashMap<String, DataSourceWrapper>(list.size());
        Map<String, Integer> weightMap = new HashMap<String, Integer>(list.size());

        DBType dbType = null;
        for (DataSourceWrapper dsw : list) {
            String dsKey = dsw.getDataSourceKey();
            dataSourceMap.put(dsKey, dsw);
            weightMap.put(dsKey, isRead ? dsw.getWeight().r : dsw.getWeight().w);

            if (dbType == null) {
                dbType = dsw.getDBType();
            }
        }
        EquityDbManager equityDbManager = new EquityDbManager(dataSourceMap, weightMap, groupExtraConfig);
        equityDbManager.setDbType(dbType);
        return equityDbManager;
    }

    /**
     * 3
     * List(:List<List<DataSourceWrapper>>)
     * List()List01
     * List() ---- |p9|-->|db0|-->|db2| ---- |p8|-->|db1|
     * ---- |p7|-->|db3| ----
     *
     * @param priorityList
     *            null
     * @param dsw
     *            
     * @param isRead
     *            pqisReadtruePq
     */
    /*
     * public static void insertSort(List<List<DataSourceWrapper>> priorityList,
     * DataSourceWrapper dsw, boolean isRead) {
     * //0 // if ((isRead &&
     * dsw.getWeight().r == 0) || (!isRead && dsw.getWeight().w == 0)) //
     * return;
     *
     * List<DataSourceWrapper> samePriorityDataSourceWrappers;
     *
     * int newPriority = isRead ? dsw.getWeight().p : dsw.getWeight().q;
     *
     * int index = 0; int size = priorityList.size();
     *
     * while (index < size) { samePriorityDataSourceWrappers =
     * priorityList.get(index);
     *
     * //priorityList if (samePriorityDataSourceWrappers
     * == null || samePriorityDataSourceWrappers.size() == 0) {
     * priorityList.remove(index); size--; continue; }
     *
     * Weight oldWeight = samePriorityDataSourceWrappers.get(0).getWeight(); int
     * oldPriority = isRead ? oldWeight.p : oldWeight.q;
     *
     * if (newPriority == oldPriority) { //
     * samePriorityDataSourceWrappers.add(dsw); return; } else if (newPriority >
     * oldPriority) { break; } else { index++; } }
     *
     * // (size=0) samePriorityDataSourceWrappers =
     * new ArrayList<DataSourceWrapper>();
     * samePriorityDataSourceWrappers.add(dsw); priorityList.add(index,
     * samePriorityDataSourceWrappers); }
     */
    /*
     * private DataSourceWrapper createDataSourceWrapper(String dsKey, String
     * weightStr, int dataSourceIndex) { aliveDataSourceKeys.add(dsKey);
     *
     * DataSourceWrapper dsw = dataSourceWrapperMap.get(dsKey); if (dsw != null)
     * { //dsw.setWeightStr(weightStr);
     * //dsw.setDataSourceIndex(dataSourceIndex); } else { if
     * (createTAtomDataSource) { TAtomDataSource ads =
     * createTAtomDataSource(dsKey); dsw = new DataSourceWrapper(dsKey,
     * weightStr, ads, getDBTypeFrom(ads), dataSourceIndex);
     * dataSourceWrapperMap.put(dsKey, dsw); } else { throw new
     * IllegalArgumentException(dsKey + " not exist!"); } } return dsw; }
     */

    /**
     * GroupAtomDataSourceDataSourcedbkey
     * dbkeyDiamondAtomDataSource ---add by
     * mazhidan.pt
     */
    private TAtomDataSource createTAtomDataSource(String dsKey) {
        TAtomDataSource ads = null;
        try {
            ads = new TAtomDataSource();
            ads.setAppName(tGroupDataSource.getAppName());
            ads.setDbKey(dsKey);

            ads.init(); // TAtomDataSourceinit()throws Exception

            ads.setLogWriter(tGroupDataSource.getLogWriter());
            ads.setLoginTimeout(tGroupDataSource.getLoginTimeout());
        } catch (Exception e) {
            throw new TAtomDataSourceException("TAtomDataSource: dsKey=" + dsKey, e);
        }
        return ads;
    }

    /**
     * TAtomDataSource(DBCP)
     *
     * @param ds
     *            
     * @param isRead
     *            (isRead=true)(isRead=false)
     * @return true
     *         TAtomDataSourceNAfalse, WRisRead
     */
    public static boolean isDataSourceAvailable(DataSource ds, boolean isRead) {
        if (ds instanceof DataSourceWrapper)
            ds = ((DataSourceWrapper) ds).getWrappedDataSource();

        if (!(ds instanceof TAtomDataSource))
            return true;

        AtomDbStatusEnum status = ((TAtomDataSource) ds).getDbStatus();
        if (status.isNaStatus())
            return false;

        if (status.isRstatus() && isRead)
            return true;
        if (status.isWstatus() && !isRead)
            return true;

        return false;
    }

    /**
     * TGroupDataSourceTGroupConnectionDBSelector
     * db
     */
    private volatile DBSelector readDBSelectorWrapper;
    private volatile DBSelector writeDBSelectorWrapper;
    private volatile DBSelector runtimeWritableAtomDBSelectorWrapper;

    /**
     * DBSelector---add by mazhidan.pt
     */
    public DBSelector getDBSelector(boolean isRead, boolean autoSelectWriteDataSource) {
        DBSelector dbSelector = isRead ? readDBSelectorWrapper : writeDBSelectorWrapper;
        if (!isRead && autoSelectWriteDataSource) {
            // dbSelectorTAtomDataSourceTAtomDataSource
            // TAtomDataSourcedbSelector
            // TAtomDataSourceW
            // dbSelectorruntimeWritableAtomDBSelector
            // hasWritableDataSource()true

            // if(!dbSelector.hasWritableDataSource())
            dbSelector = runtimeWritableAtomDBSelectorWrapper;
        }
        return dbSelector;
    }

    private class ConfigReceiver implements ConfigDataListener {
        public void onDataRecieved(String dataId, String data) {
            try {
                parse(data);
            } catch (Throwable t) {
                logger.error(":" + data, t);
            }
        }
    }

    private class ExtraGroupConfigReceiver implements ConfigDataListener {
        @Override
        public void onDataRecieved(String dataId, String data) {
            logger.info("receive group extra data:" + data);
            parseExtraConfig(data);
        }
    }

    // 
    public void receiveConfigInfo(String configInfo) {
        configReceiver.onDataRecieved(null, configInfo);
    }

    // 
    public void resetDbGroup(String configInfo) {
        try {
            parse(configInfo);
        } catch (Throwable t) {
            logger.error("resetDbGroup failed:" + configInfo, t);
        }
    }
}