package io.mycat.server.config.loader.zkloader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.mycat.route.function.AbstractPartitionAlgorithm;
import io.mycat.server.config.ConfigException;
import io.mycat.server.config.node.RuleConfig;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.curator.framework.CuratorFramework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.function.Function;
import static java.util.stream.Collectors.toMap;
/**
* Created by v1.lion on 2015/10/8.
*/
public class ZkRuleConfigLoader extends AbstractZKLoaders {
private static final Logger LOGGER = LoggerFactory.getLogger(ZkRuleConfigLoader.class);
//directory name of rule node config in zookeeper
private static final String RULE_CONFIG_DIRECTORY = "rule-config";
private static final String RULE_NAME_KEY = "name";
private static final String FUNCTION_NAME_KEY = "functionName";
private static final String COLUMN_NAME_KEY = "column";
//hold rule name mapping to RuleConfig
private Map<String, RuleConfig> ruleConfigMap;
public ZkRuleConfigLoader(final String clusterID) {
super(clusterID, RULE_CONFIG_DIRECTORY);
}
@Override
public void fetchConfig(CuratorFramework zkConnection) {
//rule config path in zookeeper
//example: /mycat-cluster-1/rule-config/sharding-by-enum
this.ruleConfigMap = super
.fetchChildren(zkConnection)
.stream()
.map(nodeName -> {
//fetch data
String rawRuleStr = super.fetchDataToString(zkConnection, nodeName);
//parse
JSONObject ruleJson = JSON.parseObject(rawRuleStr);
//create RuleConfig
RuleConfig ruleConfig = new RuleConfig(
ruleJson.getString(RULE_NAME_KEY),
ruleJson.getString(COLUMN_NAME_KEY),
ruleJson.getString(FUNCTION_NAME_KEY));
AbstractPartitionAlgorithm ruleFunction = instanceFunction(ruleJson);
ruleConfig.setRuleAlgorithm(ruleFunction);
ruleConfig.setProps(ruleJson);
return ruleConfig;
})
.collect(toMap(RuleConfig::getName, Function.identity()));
LOGGER.trace("done fetch rule config : {}", ruleConfigMap);
}
private AbstractPartitionAlgorithm instanceFunction(JSONObject ruleJson) {
String functionName = ruleJson.getString(FUNCTION_NAME_KEY);
String ruleName = ruleJson.getString(RULE_NAME_KEY);
//for bean copy
ruleJson.remove(COLUMN_NAME_KEY);
ruleJson.remove(FUNCTION_NAME_KEY);
ruleJson.remove(RULE_NAME_KEY);
AbstractPartitionAlgorithm algorithm;
try {
Class<?> clz = Class.forName(functionName);
if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) {
throw new IllegalArgumentException("rule function must implements "
+ AbstractPartitionAlgorithm.class.getName() + ", name=" + ruleName);
}
algorithm = (AbstractPartitionAlgorithm) clz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
LOGGER.warn("instance function class error: {}", e.getMessage(), e);
throw new ConfigException(e);
}
try {
BeanUtils.populate(algorithm, ruleJson);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new ConfigException("copy property to " + functionName + " error: ", e);
}
//init
algorithm.init();
LOGGER.trace("instanced function class : {}", functionName);
return algorithm;
}
public Map<String, RuleConfig> getRuleConfigs() {
return this.ruleConfigMap;
}
}