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 tableBeanMap = new ConcurrentHashMap<>(); /** * des 模块内的配置2次处理的静态数据 * 1 模块数据和纯配置数据分离 * 2 为了热更新 整体替换 避免表相互依赖造成的安全问题 */ private static final Map 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> 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); LOGGER.info("hotfix table"+tableName); } Object stable = cls.newInstance(); Method method = cls.getMethod("init"); method.invoke(stable); } try { //加载逻辑数据 Set staticConfigsNames = new HashSet<>(); Set tables = null; if (tableList != null) { tables = new HashSet<>(Arrays.asList(tableList)); } for (Map.Entry entry : classStaticConfigMap.entrySet()) { if (tables != null && entry.getValue().checkChange(tables).size() <= 0) { continue; } staticConfigsNames.add(entry.getKey()); } List> 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 getFigureConfig(Class 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 Map getConfig(Class clazz) { Object o = tableBeanMap.get(clazz.getName()); if (null == o) { o = loadInCache(clazz); } java.util.TreeMap result = null; try { result = (java.util.TreeMap) o; } catch (ClassCastException e) { e.printStackTrace(); } if (null == result) { throw new NullPointerException("clazz.null" + clazz.getName()); } return result; } private static Object loadInCache(Class clazz){ TreeMap map = new TreeMap<>(); try { String tableName = clazz.getAnnotation(Table.class).name(); // String path = SysUtil.getPath("conf", "server", tableName + ".txt"); String path = "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 void readFileToCache(Class clazz, Map map, File file) throws IOException, InstantiationException, IllegalAccessException, NoSuchFieldException { String line; List key = new ArrayList<>(); List 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){ LOGGER.error("clazz = {}, line = {}, para = {}, excep = {}",clazz, line.substring(0,10), Arrays.toString(prarms), e); throw e; } break; } lineNum++; } } } /** * 读取配置表到内存 */ public static Map> getMapConfig(Class clazz) { Map> map = new HashMap<>(); try { String tableName = clazz.getAnnotation(Table.class).name(); String pathDir = "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 mapConf = new HashMap<>(); readFileToCache(clazz, mapConf, mapFile); map.put(mapId, mapConf); } } catch (Exception e) { e.printStackTrace(); LOGGER.error("getMapConfig= {}", e.toString()); } return map; } /** * 处理参数 */ private static void dealParams(Class clazz, Map map, List key, List 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(); LOGGER.error("Key={} Clazz={} Exception={}", key.get(i), clazz, e.toString()); } } } /** * 操作mut开头的类型 */ private static void mut(List key, List 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 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 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 getJsonFilePathInJsonConf(String fileName, Class 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(); } } }