miduo_server/tablemanager/src/main/java/manager/STableManager.java

435 lines
16 KiB
Java

package manager;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import util.ClassLoaderHelper;
import util.StringUtil;
import util.SysUtil;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class STableManager {
private static final Logger LOGGER = LoggerFactory.getLogger(STableManager.class);
/**
* table表包名
*/
private static String data_parackage = null;
private static String jsonPath;
private static int currentDbVersion;
/**
* des 配置类缓存
* 1 懒加载 各个模块各取所需
* 2 为了热更新 整体替换 避免表相互依赖造成的安全问题
* 3 为保证所有数据一致性 做了以下处理
* a 去掉了配置类中静态配置数据 所有获取都应该从此map中拿 保证最新和一致
*/
private static final Map<String, Object> tableBeanMap = new ConcurrentHashMap<>();
/**
* des 模块内的配置2次处理的静态数据
* 1 模块数据和纯配置数据分离
* 2 为了热更新 整体替换 避免表相互依赖造成的安全问题
*/
private static final Map<String, AbstractClassStaticConfig> classStaticConfigMap = new ConcurrentHashMap<>();
public static void initialize(String data_parackage) throws Exception {
STableManager.data_parackage = data_parackage;
updateTablesWithTableNames(false);
initJsonPath();
initDbVersion();
}
/**
* 根据表名字更新表数据
*
* @throws Exception
*/
public static void updateTablesWithTableNames(boolean isHotFix) throws Exception {
String[] tableList = null;
if (isHotFix) {
CDataBaseVersion version = getJsonFilePathInJsonConf("c_database_version.json", CDataBaseVersion.class);
if (version == null || version.getTables().isEmpty() || currentDbVersion >= version.getVersion()) { // 启动而不是热更
return;
}
currentDbVersion = version.getVersion();
//更新指定表
tableList = version.getTables().split("\\|");
}
Set<Class<?>> messageCommandClasses = ClassScanner.listClassesWithAnnotation(data_parackage, Table.class);
for (Class<?> cls : messageCommandClasses) {
String tableName = cls.getAnnotation(Table.class).name();
if (tableList != null) {
if (!isHotFixContainTableName(tableList, tableName)) {
continue;
}
//TODO 应该说有数据都加载后统一替换 但是现在部分静态数据遗留在cfg类中 只能一个一个加载
if(!tableName.equals("Map"))
loadInCache(cls);
}
Object stable = cls.newInstance();
Method method = cls.getMethod("init");
method.invoke(stable);
}
try {
//加载逻辑数据
Set<String> staticConfigsNames = new HashSet<>();
Set<String> tables = null;
if (tableList != null) {
tables = new HashSet<>(Arrays.asList(tableList));
}
for (Map.Entry<String, AbstractClassStaticConfig> entry : classStaticConfigMap.entrySet()) {
if (tables != null && entry.getValue().checkChange(tables).size() <= 0) {
continue;
}
staticConfigsNames.add(entry.getKey());
}
List<Class<?>> staticConfigsclass = new LinkedList<>();
try {
ClassLoaderHelper.findLocalClass("com.ljsd.jieling.config.clazzStaticCfg", AbstractClassStaticConfig.class,Thread.currentThread().getContextClassLoader(), staticConfigsclass);
}catch (RuntimeException e){
}
try {
ClassLoaderHelper.findClassJar("com.ljsd.jieling.config.clazzStaticCfg", AbstractClassStaticConfig.class, Thread.currentThread().getContextClassLoader(), staticConfigsclass);
}catch (RuntimeException e){
}
for (Class<?> cls : staticConfigsclass) {
if (tables != null) {
if(!staticConfigsNames.contains(cls.getName())){
continue;
}
}
AbstractClassStaticConfig newClassConfig = (AbstractClassStaticConfig) cls.newInstance();
classStaticConfigMap.put(cls.getName(), newClassConfig);
}
} catch (InstantiationException | IllegalAccessException e2) {
LOGGER.error("e={}",e2);
}
}
private static void registFigureConfig(AbstractClassStaticConfig classStaticConfig) {
if (classStaticConfig == null) {
return;
}
classStaticConfigMap.put(classStaticConfig.getClass().getName(), classStaticConfig);
}
/**
* 获取类的二次处理配置类
*/
public static <T extends AbstractClassStaticConfig> T getFigureConfig(Class<T> tClass) {
if (!classStaticConfigMap.containsKey(tClass.getName())) {
if (ClassLoaderHelper.filter(tClass, AbstractClassStaticConfig.class)) {
try {
registFigureConfig((AbstractClassStaticConfig) tClass.newInstance());
} catch (Exception e) {
}
}
}
return (T) classStaticConfigMap.get(tClass.getName());
}
private static boolean isHotFixContainTableName(String[] tableNames, String curTableName) {
if (tableNames == null) {
return false;
}
if (tableNames.length == 0) {
return false;
}
for (String oneTable : tableNames) {
if (oneTable.equalsIgnoreCase(curTableName)) {
return true;
}
}
return false;
}
/**
* 读取配置表到内存
*/
@SuppressWarnings("unchecked")
public static <T> Map<Integer, T> getConfig(Class<T> clazz) {
Object o = tableBeanMap.get(clazz.getName());
if (null == o) {
o = loadInCache(clazz);
}
java.util.TreeMap<Integer, T> result = null;
try {
result = (java.util.TreeMap<Integer, T>) o;
} catch (ClassCastException e) {
e.printStackTrace();
}
if (null == result) {
throw new NullPointerException("clazz.null" + clazz.getName());
}
return result;
}
private static <T> Object loadInCache(Class<T> clazz){
TreeMap<Integer, T> map = new TreeMap<>();
try {
String tableName = clazz.getAnnotation(Table.class).name();
String path = SysUtil.getPath("conf", "server", tableName + ".txt");
File file = new File(path);
if (!file.exists()) {
LOGGER.error("file not find {}, do not find sheet with {} you need rebuild all sheet by gen sheet tool!", path, tableName);
throw new NullPointerException("clazz.null" + clazz.getName());
}
LOGGER.info("initMap:{}", clazz.getSimpleName());
readFileToCache(clazz, map, file);
} catch (Exception e) {
e.printStackTrace();
}
tableBeanMap.put(clazz.getName(), map);
return map;
}
private static <T> void readFileToCache(Class<T> clazz, Map<Integer, T> map, File file) throws IOException, InstantiationException, IllegalAccessException, NoSuchFieldException {
String line;
List<String> key = new ArrayList<>();
List<String> type = new ArrayList<>();
int lineNum = 0;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
while ((line = bufferedReader.readLine()) != null) {
if (line.isEmpty()) {
continue;
}
T obj = clazz.newInstance();
String[] prarms = line.split("\\t");
switch (lineNum) {
case 0:
prarms = StringUtil.fieldHandle(prarms);
key.addAll(Arrays.asList(prarms));
break;
case 1:
type.addAll(Arrays.asList(prarms));
break;
default:
try {
dealParams(clazz, map, key, type, obj, prarms);
}catch (Exception e){
System.out.println("clazz = [" + clazz + "], line = [" + line.substring(0,10) + "]"+prarms.toString() );
throw e;
}
break;
}
lineNum++;
}
}
}
/**
* 读取配置表到内存
*/
public static <T> Map<Integer, Map<Integer, T>> getMapConfig(Class<T> clazz) {
Map<Integer, Map<Integer, T>> map = new HashMap<>();
try {
String tableName = clazz.getAnnotation(Table.class).name();
String pathDir = SysUtil.getPath("conf", "server");
File mapDir = new File(pathDir);
String prefix = tableName + "_";
int preLength = prefix.length();
for (File mapFile : mapDir.listFiles()) {
tableName = mapFile.getName();
if (!mapFile.getName().startsWith(prefix)) {
continue;
}
int mapId = Integer.parseInt(tableName.substring(preLength).split("\\.")[0]);
LOGGER.info("initMap:{}", tableName);
Map<Integer, T> mapConf = new HashMap<>();
readFileToCache(clazz, mapConf, mapFile);
map.put(mapId, mapConf);
}
} catch (Exception e) {
LOGGER.error("getMapConfig" + e.toString());
}
return map;
}
/**
* 处理参数
*/
private static <T> void dealParams(Class<T> clazz, Map<Integer, T> map, List<String> key, List<String> type, T obj, String[] prarms) throws NoSuchFieldException, IllegalAccessException {
int id = Integer.parseInt(prarms[0]);
for (int i = 0; i < prarms.length; i++) {
try {
Field field = clazz.getDeclaredField(key.get(i));
boolean flag = field.isAccessible();
field.setAccessible(true);
switch (type.get(i)) {
case "int":
field.set(obj, Integer.parseInt(prarms[i]));
break;
case "string":
case "stringt":
if (!"null".equalsIgnoreCase(prarms[i]) || !"".equalsIgnoreCase(prarms[i])) {
field.set(obj, prarms[i]);
}
break;
case "long":
field.set(obj, Long.parseLong(prarms[i]));
break;
case "double":
field.set(obj, Double.parseDouble(prarms[i]));
break;
case "float":
field.set(obj, Float.parseFloat(prarms[i]));
break;
case "bool":
field.set(obj, Boolean.parseBoolean(prarms[i]));
break;
default:
if (type.get(i).startsWith("ref")) {
field.set(obj, Integer.parseInt(prarms[i]));
} else if (type.get(i).startsWith("mut")) {
mut(key, type, obj, prarms, i, field);
}
break;
}
field.setAccessible(flag);
map.put(id, obj);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
/**
* 操作mut开头的类型
*/
private static <T> void mut(List<String> key, List<String> type, T obj, String[] prarms, int i, Field field) throws IllegalAccessException {
String[] params = type.get(i).split(",");
String[] type1 = params[1].split("#");
int dimension = dimension(type1, params);
if (dimension == 0) {
field.set(obj, prarms[i]);
} else {
//全为int或者float
switch (type1[0]) {
case "int":
intField(obj, prarms, i, field, dimension);
break;
case "float":
floatField(obj, prarms, i, field, dimension);
break;
default:
break;
}
}
}
private static <T> void floatField(T obj, String[] prarms, int i, Field field, int dimension) throws IllegalAccessException {
switch (dimension) {
case 1:
field.set(obj, StringUtil.parseFiledFloat(prarms[i]));
break;
case 2:
field.set(obj, StringUtil.parseFiledFloat2(prarms[i]));
break;
case 3:
field.set(obj, StringUtil.parseFiledFloat3(prarms[i]));
break;
default:
break;
}
}
private static <T> void intField(T obj, String[] prarms, int i, Field field, int dimension) throws IllegalAccessException {
switch (dimension) {
case 1:
field.set(obj, StringUtil.parseFiledInt(prarms[i]));
break;
case 2:
field.set(obj, StringUtil.parseFiledInt2(prarms[i]));
break;
case 3:
field.set(obj, StringUtil.parseFiledInt3(prarms[i]));
break;
default:
break;
}
}
/**
* 判断是几维数组
*/
private static int dimension(String type[], String[] params) throws IllegalAccessException {
String type1 = type[0];
boolean flag = false;
for (int i = 0; i < type.length; i++) {
if (!type1.equals(type[i])) {
flag = true;
}
}
if (flag) {
return 0;
}
return Integer.parseInt(params[2]);
}
private static String getType(String param) {
String[] params = param.split(",");
String[] type = params[1].split("#");
return type[0];
}
public static <T> T getJsonFilePathInJsonConf(String fileName, Class<T> fileClass) {
File file = new File(jsonPath + fileName);
if (!file.exists()) {
LOGGER.info("the {} is not exist", fileName);
return null;
}
try (InputStream in = new FileInputStream(file);) {
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
return mapper.readValue(in, fileClass);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static void initJsonPath() {
String osName = System.getProperty("os.name");
jsonPath = "../conf/";
if (osName.matches("^(?i)Windows.*$")) {// Window 系统
jsonPath = "conf/";
}
}
private static void initDbVersion() {
CDataBaseVersion cDataBaseVersion = getJsonFilePathInJsonConf("c_database_version.json", CDataBaseVersion.class);
if (null == cDataBaseVersion) {
currentDbVersion = 0;
} else {
currentDbVersion = cDataBaseVersion.getVersion();
}
}
}