/*
* Copyright (c) 2013, OpenCloudDB/MyCAT and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software;Designed and Developed mainly by many Chinese
* opensource volunteers. you can redistribute it and/or modify it under the
* terms of the GNU General Public License version 2 only, as published by the
* Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Any questions about this component can be directed to it's project Web address
* https://code.google.com/p/opencloudb/.
*
*/
package io.mycat.server.config.loader;
import io.mycat.backend.PhysicalDBPool;
import io.mycat.route.function.AbstractPartitionAlgorithm;
import io.mycat.server.config.ConfigException;
import io.mycat.server.config.ConfigUtil;
import io.mycat.server.config.ParameterMapping;
import io.mycat.server.config.cluster.MycatClusterConfig;
import io.mycat.server.config.cluster.MycatNodeConfig;
import io.mycat.server.config.node.CharsetConfig;
import io.mycat.server.config.node.DBHostConfig;
import io.mycat.server.config.node.DataHostConfig;
import io.mycat.server.config.node.DataNodeConfig;
import io.mycat.server.config.node.HostIndexConfig;
import io.mycat.server.config.node.JdbcDriver;
import io.mycat.server.config.node.QuarantineConfig;
import io.mycat.server.config.node.RuleConfig;
import io.mycat.server.config.node.SchemaConfig;
import io.mycat.server.config.node.SequenceConfig;
import io.mycat.server.config.node.SystemConfig;
import io.mycat.server.config.node.TableConfig;
import io.mycat.server.config.node.TableConfigMap;
import io.mycat.server.config.node.UserConfig;
import io.mycat.util.SplitUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* @author mycat
*/
public class LocalLoader implements ConfigLoader {
private static final Logger logger = LoggerFactory.getLogger("LocalLoader");
private Map<String, DataHostConfig> dataHosts;
private Map<String, DataNodeConfig> dataNodes;
private Map<String, SchemaConfig> schemas;
private Map<String, RuleConfig> tableRules;
private SystemConfig system;
private Map<String, UserConfig> users;
private QuarantineConfig quarantine;
private MycatClusterConfig cluster;
private CharsetConfig charsetConfig;
private HostIndexConfig hostIndexConfig;
private SequenceConfig sequenceConfig;
// 为了避免原代码中频繁调用 loadRoot 去频繁读取 /mycat.dtd 和 /mycat.xml,所以将 Document 作为属性进行缓存
private static Document document = null;
public LocalLoader(){
this.system = new SystemConfig();
this.users = new HashMap<String, UserConfig>();
this.dataHosts = new HashMap<String, DataHostConfig>();
this.dataNodes = new HashMap<String, DataNodeConfig>();
this.schemas = new HashMap<String, SchemaConfig>();
this.tableRules = new HashMap<String, RuleConfig>();
this.quarantine = new QuarantineConfig();
this.charsetConfig = new CharsetConfig();
this.hostIndexConfig = new HostIndexConfig();
this.sequenceConfig = new SequenceConfig();
}
private static Element loadRoot() {
if(document == null){
try(InputStream dtd = ConfigFactory.class.getResourceAsStream("/mycat.dtd");
InputStream xml = ConfigFactory.class.getResourceAsStream("/mycat.xml")){
document = ConfigUtil.getDocument(dtd, xml);
return document.getDocumentElement();
} catch (Exception e) {
logger.error(" loadRoot error: " + e.getMessage());
throw new ConfigException(e);
}
}
return document.getDocumentElement();
}
@Override
public UserConfig getUserConfig(String user) {
Element root = loadRoot();
loadUsers(root);
return this.users.get(user);
}
@Override
public Map<String, UserConfig> getUserConfigs() {
Element root = loadRoot();
loadUsers(root);
return users;
}
@Override
public SystemConfig getSystemConfig() {
Element root = loadRoot();
loadSystem(root);
return system;
}
@Override
public Map<String, SchemaConfig> getSchemaConfigs() {
Element root = loadRoot();
loadSchemas(root);
return schemas;
}
@Override
public SchemaConfig getSchemaConfig(String schema) {
Element root = loadRoot();
loadSchemas(root);
return schemas.get(schema);
}
@Override
public Map<String, DataNodeConfig> getDataNodeConfigs() {
Element root = loadRoot();
loadDataNodes(root);
return dataNodes;
}
@Override
public Map<String, DataHostConfig> getDataHostConfigs() {
Element root = loadRoot();
loadDataHosts(root);
return dataHosts;
}
@Override
public Map<String, RuleConfig> getTableRuleConfigs() {
Element root = loadRoot();
loadTableRules(root);
return tableRules;
}
@Override
public QuarantineConfig getQuarantineConfigs() {
return quarantine;
}
@Override
public MycatClusterConfig getClusterConfigs() {
return cluster;
}
@Override
public CharsetConfig getCharsetConfigs() {
Element root = loadRoot();
loadCharsetConfig(root);
return this.charsetConfig;
}
@Override
public HostIndexConfig getHostIndexConfig() {
Element root = loadRoot();
loadHostIndexConfig(root);
return this.hostIndexConfig;
}
@Override
public SequenceConfig getSequenceConfig() {
Element root = loadRoot();
loadSequenceConfig(root);
return this.sequenceConfig;
}
public static Map<String, JdbcDriver> loadJdbcDriverConfig() {
Element root = loadRoot();
return loadJdbcDriverConfig(root);
}
private void loadUsers(Element root) {
NodeList list = root.getElementsByTagName("user");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String name = e.getAttribute("name");
UserConfig user = new UserConfig();
user.setName(name);
Map<String, Object> props = ConfigUtil.loadElements(e);
user.setPassword((String) props.get("password"));
String readOnly = (String) props.get("readOnly");
if (null != readOnly) {
user.setReadOnly(Boolean.valueOf(readOnly));
}
String schemas = (String) props.get("schemas");
if (schemas != null) {
String[] strArray = SplitUtil.split(schemas, ',', true);
user.setSchemas(new HashSet<String>(Arrays.asList(strArray)));
}
if (users.containsKey(name)) {
throw new ConfigException("user " + name + " duplicated!");
}
users.put(name, user);
}
}
}
private void loadSystem(Element root) {
NodeList list = root.getElementsByTagName("system");
try {
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ParameterMapping.mapping(system, props);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadSystem error: " + e.getMessage());
}
}
private void loadSchemas(Element root) {
NodeList list = root.getElementsByTagName("schema");
for (int i = 0, n = list.getLength(); i < n; i++) {
Element schemaElement = (Element) list.item(i);
String name = schemaElement.getAttribute("name");
String dataNode = schemaElement.getAttribute("dataNode");
String checkSQLSchemaStr = schemaElement
.getAttribute("checkSQLschema");
String sqlMaxLimitStr = schemaElement.getAttribute("sqlMaxLimit");
int sqlMaxLimit = -1;
if (sqlMaxLimitStr != null && !sqlMaxLimitStr.isEmpty()) {
sqlMaxLimit = Integer.valueOf(sqlMaxLimitStr);
}
// check dataNode already exists or not
String defaultDbType = null;
if (dataNode != null && !dataNode.isEmpty()) {
List<String> dataNodeLst = new ArrayList<String>(1);
dataNodeLst.add(dataNode);
checkDataNodeExists(dataNodeLst);
String dataHost = dataNodes.get(dataNode).getDataHost();
defaultDbType = dataHosts.get(dataHost).getDbType();
} else {
dataNode = null;
}
Map<String, TableConfig> tables = loadTables(schemaElement);
if (schemas.containsKey(name)) {
throw new ConfigException("schema " + name + " duplicated!");
}
// 设置了table的不需要设置dataNode属性,没有设置table的必须设置dataNode属性
if (dataNode == null && tables.size() == 0) {
throw new ConfigException(
"schema "
+ name
+ " didn't config tables,so you must set dataNode property!");
}
SchemaConfig schemaConfig = new SchemaConfig(name, dataNode,
tables, sqlMaxLimit,
"true".equalsIgnoreCase(checkSQLSchemaStr));
if (defaultDbType != null) {
schemaConfig.setDefaultDataNodeDbType(defaultDbType);
if (!"mysql".equalsIgnoreCase(defaultDbType)) {
schemaConfig.setNeedSupportMultiDBType(true);
}
}
// 判断是否有不是mysql的数据库类型,方便解析判断是否启用多数据库分页语法解析
for (String tableName : tables.keySet()) {
TableConfig tableConfig = tables.get(tableName);
if (isHasMultiDbType(tableConfig)) {
schemaConfig.setNeedSupportMultiDBType(true);
break;
}
}
Map<String, String> dataNodeDbTypeMap = new HashMap<>();
for (String dataNodeName : dataNodes.keySet()) {
DataNodeConfig dataNodeConfig = dataNodes.get(dataNodeName);
String dataHost = dataNodeConfig.getDataHost();
DataHostConfig dataHostConfig = dataHosts.get(dataHost);
if (dataHostConfig != null) {
String dbType = dataHostConfig.getDbType();
dataNodeDbTypeMap.put(dataNodeName, dbType);
}
}
schemaConfig.setDataNodeDbTypeMap(dataNodeDbTypeMap);
schemas.put(name, schemaConfig);
}
}
private Map<String, TableConfig> loadTables(Element node) {
// Map<String, TableConfig> tables = new HashMap<String, TableConfig>();
// 支持表名中包含引号[`] BEN GONG
Map<String, TableConfig> tables = new TableConfigMap();
NodeList nodeList = node.getElementsByTagName("table");
for (int i = 0; i < nodeList.getLength(); i++) {
Element tableElement = (Element) nodeList.item(i);
String tableNameElement = tableElement.getAttribute("name").toUpperCase();
String[] tableNames = tableNameElement.split(",");
String primaryKey = tableElement.hasAttribute("primaryKey") ? tableElement
.getAttribute("primaryKey").toUpperCase() : null;
boolean autoIncrement = false;
if (tableElement.hasAttribute("autoIncrement")) {
autoIncrement = Boolean.parseBoolean(tableElement
.getAttribute("autoIncrement"));
}
boolean needAddLimit = true;
if (tableElement.hasAttribute("needAddLimit")) {
needAddLimit = Boolean.parseBoolean(tableElement
.getAttribute("needAddLimit"));
}
String tableTypeStr = tableElement.hasAttribute("type") ? tableElement
.getAttribute("type") : null;
int tableType = TableConfig.TYPE_GLOBAL_DEFAULT;
if ("global".equalsIgnoreCase(tableTypeStr)) {
tableType = TableConfig.TYPE_GLOBAL_TABLE;
}
String dataNode = tableElement.getAttribute("dataNode");
RuleConfig tableRule = null;
if (tableElement.hasAttribute("rule")) {
String ruleName = tableElement.getAttribute("rule");
tableRule = tableRules.get(ruleName);
if (tableRule == null) {
throw new ConfigException("rule " + ruleName + " is not found!");
}
}
boolean ruleRequired = false;
if (tableElement.hasAttribute("ruleRequired")) {
ruleRequired = Boolean.parseBoolean(tableElement
.getAttribute("ruleRequired"));
}
if (tableNames == null) {
throw new ConfigException("table name is not found!");
}
String distPrex = "distribute(";
boolean distTableDns = dataNode.startsWith(distPrex);
if (distTableDns) {
dataNode = dataNode.substring(distPrex.length(),
dataNode.length() - 1);
}
for (int j = 0; j < tableNames.length; j++) {
String tableName = tableNames[j];
TableConfig table = new TableConfig(tableName, primaryKey,
autoIncrement, needAddLimit, tableType, dataNode,
getDbType(dataNode),
(tableRule != null) ? tableRule : null,
ruleRequired, null, false, null, null);
checkDataNodeExists(table.getDataNodes());
if (distTableDns) {
distributeDataNodes(table.getDataNodes());
}
if (tables.containsKey(table.getName())) {
throw new ConfigException("table " + tableName
+ " duplicated!");
}
tables.put(table.getName(), table);
}
if (tableNames.length == 1) {
TableConfig table = tables.get(tableNames[0]);
// process child tables
processChildTables(tables, table, dataNode, tableElement);
}
}
return tables;
}
/**
* distribute datanodes in multi hosts,means ,dn1 (host1),dn100
* (host2),dn300(host3),dn2(host1),dn101(host2),dn301(host3)...etc
*
* @param dataNodes
*/
private void distributeDataNodes(ArrayList<String> theDataNodes) {
Map<String, ArrayList<String>> newDataNodeMap = new HashMap<String, ArrayList<String>>(
dataHosts.size());
for (String dn : theDataNodes) {
DataNodeConfig dnConf = dataNodes.get(dn);
String host = dnConf.getDataHost();
ArrayList<String> hostDns = newDataNodeMap.get(host);
hostDns = (hostDns == null) ? new ArrayList<String>() : hostDns;
hostDns.add(dn);
newDataNodeMap.put(host, hostDns);
}
ArrayList<String> result = new ArrayList<String>(theDataNodes.size());
boolean hasData = true;
while (hasData) {
hasData = false;
for (ArrayList<String> dns : newDataNodeMap.values()) {
if (!dns.isEmpty()) {
result.add(dns.remove(0));
hasData = true;
}
}
}
theDataNodes.clear();
theDataNodes.addAll(result);
}
private Set<String> getDbType(String dataNode) {
Set<String> dbTypes = new HashSet<>();
String[] dataNodeArr = SplitUtil.split(dataNode, ',', '$', '-');
for (String node : dataNodeArr) {
DataNodeConfig datanode = dataNodes.get(node);
DataHostConfig datahost = dataHosts.get(datanode.getDataHost());
dbTypes.add(datahost.getDbType());
}
return dbTypes;
}
private Set<String> getDataNodeDbTypeMap(String dataNode) {
Set<String> dbTypes = new HashSet<>();
String[] dataNodeArr = SplitUtil.split(dataNode, ',', '$', '-');
for (String node : dataNodeArr) {
DataNodeConfig datanode = dataNodes.get(node);
DataHostConfig datahost = dataHosts.get(datanode.getDataHost());
dbTypes.add(datahost.getDbType());
}
return dbTypes;
}
private boolean isHasMultiDbType(TableConfig table) {
Set<String> dbTypes = table.getDbTypes();
for (String dbType : dbTypes) {
if (!"mysql".equalsIgnoreCase(dbType)) {
return true;
}
}
return false;
}
private void processChildTables(Map<String, TableConfig> tables,
TableConfig parentTable, String dataNodes, Element tableNode) {
// parse child tables
NodeList childNodeList = tableNode.getChildNodes();
for (int j = 0; j < childNodeList.getLength(); j++) {
Node theNode = childNodeList.item(j);
if (!theNode.getNodeName().equals("childTable")) {
continue;
}
Element childTbElement = (Element) theNode;
String cdTbName = childTbElement.getAttribute("name").toUpperCase();
String primaryKey = childTbElement.hasAttribute("primaryKey") ? childTbElement
.getAttribute("primaryKey").toUpperCase() : null;
boolean autoIncrement = false;
if (childTbElement.hasAttribute("autoIncrement")) {
autoIncrement = Boolean.parseBoolean(childTbElement
.getAttribute("autoIncrement"));
}
boolean needAddLimit = true;
if (childTbElement.hasAttribute("needAddLimit")) {
needAddLimit = Boolean.parseBoolean(childTbElement
.getAttribute("needAddLimit"));
}
String joinKey = childTbElement.getAttribute("joinKey")
.toUpperCase();
String parentKey = childTbElement.getAttribute("parentKey")
.toUpperCase();
TableConfig table = new TableConfig(cdTbName, primaryKey,
autoIncrement, needAddLimit,
TableConfig.TYPE_GLOBAL_DEFAULT, dataNodes,
getDbType(dataNodes), null, false, parentTable, true,
joinKey, parentKey);
if (tables.containsKey(table.getName())) {
throw new ConfigException("table " + table.getName()
+ " duplicated!");
}
tables.put(table.getName(), table);
processChildTables(tables, table, dataNodes, childTbElement);
}
}
private void checkDataNodeExists(Collection<String> nodes) {
if (nodes == null || nodes.size() < 1) {
return;
}
for (String node : nodes) {
if (!dataNodes.containsKey(node)) {
throw new ConfigException("dataNode '" + node
+ "' is not found!");
}
}
}
private void loadDataNodes(Element root) {
NodeList list = root.getElementsByTagName("dataNode");
for (int i = 0, n = list.getLength(); i < n; i++) {
Element element = (Element) list.item(i);
String dnNamePre = element.getAttribute("name");
String databaseStr = element.getAttribute("database");
String host = element.getAttribute("dataHost");
if (empty(dnNamePre) || empty(databaseStr) || empty(host)) {
throw new ConfigException("dataNode " + dnNamePre
+ " define error ,attribute can't be empty");
}
String[] dnNames = io.mycat.util.SplitUtil.split(dnNamePre,
',', '$', '-');
String[] databases = io.mycat.util.SplitUtil.split(
databaseStr, ',', '$', '-');
String[] hostStrings = io.mycat.util.SplitUtil.split(host,
',', '$', '-');
if (dnNames.length > 1
&& dnNames.length != databases.length * hostStrings.length) {
throw new ConfigException(
"dataNode "
+ dnNamePre
+ " define error ,dnNames.length must be=databases.length*hostStrings.length");
}
if (dnNames.length > 1) {
List<String[]> mhdList = mergerHostDatabase(hostStrings,
databases);
for (int k = 0; k < dnNames.length; k++) {
String[] hd = mhdList.get(k);
String dnName = dnNames[k];
String databaseName = hd[1];
String hostName = hd[0];
createDataNode(dnName, databaseName, hostName);
}
} else {
createDataNode(dnNamePre, databaseStr, host);
}
}
}
private List<String[]> mergerHostDatabase(String[] hostStrings,
String[] databases) {
List<String[]> mhdList = new ArrayList<>();
for (int i = 0; i < hostStrings.length; i++) {
String hostString = hostStrings[i];
for (int i1 = 0; i1 < databases.length; i1++) {
String database = databases[i1];
String[] hd = new String[2];
hd[0] = hostString;
hd[1] = database;
mhdList.add(hd);
}
}
return mhdList;
}
private void createDataNode(String dnName, String database, String host) {
DataNodeConfig conf = new DataNodeConfig(dnName, database, host);
if (dataNodes.containsKey(conf.getName())) {
throw new ConfigException("dataNode " + conf.getName()
+ " duplicated!");
}
if (!dataHosts.containsKey(host)) {
throw new ConfigException("dataNode " + dnName
+ " reference dataHost:" + host + " not exists!");
}
dataNodes.put(conf.getName(), conf);
}
private boolean empty(String dnName) {
return dnName == null || dnName.length() == 0;
}
private DBHostConfig createDBHostConf(String dataHost, Element node,
String dbType, String dbDriver, int maxCon, int minCon, String filters, long logTime) {
String nodeHost = node.getAttribute("host");
String nodeUrl = node.getAttribute("url");
String user = node.getAttribute("user");
String password = node.getAttribute("password");
String weightStr = node.getAttribute("weight");
int weight = "".equals(weightStr) ? PhysicalDBPool.WEIGHT : Integer.valueOf(weightStr) ;
String ip = null;
int port = 0;
if (empty(nodeHost) || empty(nodeUrl) || empty(user)) {
throw new ConfigException(
"dataHost "
+ dataHost
+ " define error,some attributes of this element is empty: "
+ nodeHost);
}
if ("native".equalsIgnoreCase(dbDriver)) {
int colonIndex = nodeUrl.indexOf(':');
ip = nodeUrl.substring(0, colonIndex).trim();
port = Integer.parseInt(nodeUrl.substring(colonIndex + 1).trim());
} else {
URI url;
try {
url = new URI(nodeUrl.substring(5));
} catch (Exception e) {
throw new ConfigException("invalid jdbc url " + nodeUrl
+ " of " + dataHost);
}
ip = url.getHost();
port = url.getPort();
}
DBHostConfig conf = new DBHostConfig(nodeHost, ip, port, nodeUrl, user, password);
conf.setDbType(dbType);
conf.setMaxCon(maxCon);
conf.setMinCon(minCon);
conf.setFilters(filters);
conf.setLogTime(logTime);
conf.setWeight(weight); //新增权重
return conf;
}
private void loadDataHosts(Element root) {
NodeList list = root.getElementsByTagName("dataHost");
for (int i = 0, n = list.getLength(); i < n; ++i) {
Element element = (Element) list.item(i);
String name = element.getAttribute("name");
if (dataHosts.containsKey(name)) {
throw new ConfigException("dataHost name " + name
+ "duplicated!");
}
int maxCon = Integer.valueOf(element.getAttribute("maxCon"));
int minCon = Integer.valueOf(element.getAttribute("minCon"));
int balance = Integer.valueOf(element.getAttribute("balance"));
String switchTypeStr = element.getAttribute("switchType");
int switchType = switchTypeStr.equals("") ? -1 : Integer
.valueOf(switchTypeStr);
String slaveThresholdStr = element.getAttribute("slaveThreshold");
int slaveThreshold = slaveThresholdStr.equals("") ? -1 : Integer
.valueOf(slaveThresholdStr);
//如果 tempReadHostAvailable 设置大于 0 则表示写主机如果挂掉, 临时的读服务依然可用
String tempReadHostAvailableStr = element.getAttribute("tempReadHostAvailable");
boolean tempReadHostAvailable = tempReadHostAvailableStr.equals("") ? false : Integer.valueOf(tempReadHostAvailableStr) > 0;
String writeTypStr = element.getAttribute("writeType");
int writeType = "".equals(writeTypStr) ? PhysicalDBPool.WRITE_ONLYONE_NODE
: Integer.valueOf(writeTypStr);
String dbDriver = element.getAttribute("dbDriver");
String dbType = element.getAttribute("dbType");
String filters = element.getAttribute("filters");
String logTimeStr = element.getAttribute("logTime");
long logTime = "".equals(logTimeStr) ? PhysicalDBPool.LONG_TIME : Long.valueOf(logTimeStr) ;
String heartbeatSQL = element.getElementsByTagName("heartbeat")
.item(0).getTextContent();
NodeList connectionInitSqlList = element
.getElementsByTagName("connectionInitSql");
String initConSQL = null;
if (connectionInitSqlList.getLength() > 0) {
initConSQL = connectionInitSqlList.item(0).getTextContent();
}
NodeList writeNodes = element.getElementsByTagName("writeHost");
DBHostConfig[] writeDbConfs = new DBHostConfig[writeNodes
.getLength()];
Map<Integer, DBHostConfig[]> readHostsMap = new HashMap<Integer, DBHostConfig[]>(
2);
for (int w = 0; w < writeDbConfs.length; w++) {
Element writeNode = (Element) writeNodes.item(w);
writeDbConfs[w] = createDBHostConf(name, writeNode, dbType,
dbDriver, maxCon, minCon,filters,logTime);
NodeList readNodes = writeNode.getElementsByTagName("readHost");
if (readNodes.getLength() != 0) {
DBHostConfig[] readDbConfs = new DBHostConfig[readNodes
.getLength()];
for (int r = 0; r < readDbConfs.length; r++) {
Element readNode = (Element) readNodes.item(r);
readDbConfs[r] = createDBHostConf(name, readNode,
dbType, dbDriver, maxCon, minCon,filters,logTime);
}
readHostsMap.put(w, readDbConfs);
}
}
DataHostConfig hostConf = new DataHostConfig(name, dbType,
dbDriver, writeDbConfs, readHostsMap, switchType,
slaveThreshold, tempReadHostAvailable);
hostConf.setMaxCon(maxCon);
hostConf.setMinCon(minCon);
hostConf.setBalance(balance);
hostConf.setWriteType(writeType);
hostConf.setHeartbeatSQL(heartbeatSQL);
hostConf.setConnectionInitSql(initConSQL);
hostConf.setFilters(filters);
hostConf.setLogTime(logTime);
dataHosts.put(hostConf.getName(), hostConf);
}
}
private void loadTableRules(Element root) {
NodeList list = root.getElementsByTagName("tableRule");
try {
for (int i = 0, n = list.getLength(); i < n; ++i) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String name = e.getAttribute("name");
String column = e.getAttribute("column");
String functionName = e.getAttribute("functionName");
if (tableRules.containsKey(name)) {
throw new ConfigException("table rule " + name + " duplicated!");
}
RuleConfig ruleConfig = new RuleConfig(name, column, functionName);
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
ruleConfig.setProps(props);
AbstractPartitionAlgorithm function = createFunction(name, functionName);
if (function == null) {
throw new ConfigException("can't find function of name :" + functionName);
}
ParameterMapping.mapping(function, ConfigUtil.loadElements(e));
NodeList configNodes = e.getElementsByTagName("config");
int length = configNodes.getLength();
if (length > 1) {
throw new ConfigException("tableRule only one config can defined :" + name);
}
if(length!=0){
Element configEle = (Element) configNodes.item(0);
LinkedHashMap<String, Object> configs = ConfigUtil.loadLinkElements((Element) configEle);
function.setConfig(configs);
}
function.init();
ruleConfig.setRuleAlgorithm(function);
tableRules.put(name, ruleConfig);
}
}
} catch (Exception e) {
throw new ConfigException("load tableRule error: " ,e);
}
}
private AbstractPartitionAlgorithm createFunction(String name, String clazz)
throws ClassNotFoundException, InstantiationException,
IllegalAccessException, InvocationTargetException {
Class<?> clz = Class.forName(clazz);
if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) {
throw new IllegalArgumentException("rule function must implements "
+ AbstractPartitionAlgorithm.class.getName() + ", name=" + name);
}
return (AbstractPartitionAlgorithm) clz.newInstance();
}
private static Map<String, MycatNodeConfig> loadNode(Element root, int port) {
Map<String, MycatNodeConfig> nodes = new HashMap<String, MycatNodeConfig>();
NodeList list = root.getElementsByTagName("node");
Set<String> hostSet = new HashSet<String>();
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element element = (Element) node;
String name = element.getAttribute("name").trim();
if (nodes.containsKey(name)) {
throw new ConfigException("node name duplicated :" + name);
}
Map<String, Object> props = ConfigUtil.loadElements(element);
String host = (String) props.get("host");
if (null == host || "".equals(host)) {
throw new ConfigException("host empty in node: " + name);
}
if (hostSet.contains(host)) {
throw new ConfigException("node host duplicated :" + host);
}
String wei = (String) props.get("weight");
if (null == wei || "".equals(wei)) {
throw new ConfigException("weight should not be null in host:" + host);
}
int weight = Integer.valueOf(wei);
if (weight <= 0) {
throw new ConfigException("weight should be > 0 in host:" + host + " weight:" + weight);
}
MycatNodeConfig conf = new MycatNodeConfig(name, host, port, weight);
nodes.put(name, conf);
hostSet.add(host);
}
}
return nodes;
}
private static Map<String, List<String>> loadGroup(Element root, Map<String, MycatNodeConfig> nodes) {
Map<String, List<String>> groups = new HashMap<String, List<String>>();
NodeList list = root.getElementsByTagName("group");
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Element e = (Element) node;
String groupName = e.getAttribute("name").trim();
if (groups.containsKey(groupName)) {
throw new ConfigException("group duplicated : " + groupName);
}
Map<String, Object> props = ConfigUtil.loadElements(e);
String value = (String) props.get("nodeList");
if (null == value || "".equals(value)) {
throw new ConfigException("group should contain 'nodeList'");
}
String[] sList = SplitUtil.split(value, ',', true);
if (null == sList || sList.length == 0) {
throw new ConfigException("group should contain 'nodeList'");
}
for (String s : sList) {
if (!nodes.containsKey(s)) {
throw new ConfigException("[ node :" + s + "] in [ group:" + groupName + "] doesn't exist!");
}
}
List<String> nodeList = Arrays.asList(sList);
groups.put(groupName, nodeList);
}
}
if (!groups.containsKey("default")) {
List<String> nodeList = new ArrayList<String>(nodes.keySet());
groups.put("default", nodeList);
}
return groups;
}
private void loadCharsetConfig(Element root){
NodeList list = root.getElementsByTagName("charset-config");
try {
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
this.charsetConfig.setProps(props);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadCharsetConfig error: " + e.getMessage());
}
}
private void loadHostIndexConfig(Element root) {
/*NodeList list = root.getElementsByTagName("dnindex-config");
try {
for (int i = 0, n = list.getLength(); i < n; i++) {
Node node = list.item(i);
if (node instanceof Element) {
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
this.hostIndexConfig.setProps(props);
}
}
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadHostIndexConfig error: " + e.getMessage());
}*/
try {
File file = new File(SystemConfig.getHomePath(), "conf" + File.separator + "dnindex.properties");
Properties dnIndexProperties = new Properties();
dnIndexProperties.load(new FileInputStream(file));
this.hostIndexConfig.setProps(dnIndexProperties);
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadHostIndexConfig error: " + e.getMessage());
}
}
private void loadSequenceConfig(Element root) {
NodeList list = root.getElementsByTagName("sequence");
try {
Node node = list.item(0);
if (node instanceof Element) {
String type = ((Element) node).getAttribute("type");
String vclass = ((Element) node).getAttribute("class");
Map<String, Object> props = ConfigUtil.loadElements((Element) node);
this.sequenceConfig.setType(type);
this.sequenceConfig.setVclass(vclass);
this.sequenceConfig.setProps(props);
}
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadSequenceConfig error: " + e.getMessage());
}
}
private static Map<String, JdbcDriver> loadJdbcDriverConfig(Element root) {
NodeList list = root.getElementsByTagName("driver");
try {
Map<String, JdbcDriver> jdbcDriverConfig = new HashMap<>();
for(int i=0; i<list.getLength(); i++){
Node node = list.item(i);
if(node != null){
String dbType = ((Element) node).getAttribute("dbType");
String className = ((Element) node).getAttribute("className");
JdbcDriver driver = new JdbcDriver(dbType, className);
jdbcDriverConfig.put(dbType.toLowerCase(), driver);
}
}
return jdbcDriverConfig;
} catch (Exception e) {
e.printStackTrace();
throw new ConfigException("loadJdbcDriverConfig error: " + e.getMessage());
}
}
/**
* 获得 mycat.xml 解析之后的 Document 对象
* @return
*/
public static Document getDocument() {
if(document == null)
loadRoot();
return document;
}
/**
* 获得 mycat.xml 的根元素 <mycat></mycat>
* @return
*/
public static Element getRoot() {
if(document == null)
return loadRoot();
return document.getDocumentElement();
}
/**
* 重新加载 mycat.xml
*/
public static void reLoad(){
document = null;
loadRoot();
}
}