public void registerAndPush(int configId, int envId) { Config config = getConfig(configId); if (config == null) { throw new EntityNotFoundException("config[id=" + configId + "] not found, maybe deleted."); } ConfigInstance defaultInst = findDefaultInstance(configId, envId); if (defaultInst == null) { throw new RuntimeBusinessException("该环境下配置项不存在!"); } try { ConfigRegisterService registerService = getRegisterService(envId); // register context value需要放在register default value前面,重要的操作在后面,确保zk与db数据一致,大部分配置无context value // 第一个注册操作就需要push,第二个不需要,确保第一个操作时客户端感知到变化时就已经感知到了push事务 registerService.registerAndPushContextValue( config.getKey(), getConfigContextValue(configId, envId)); registerService.registerDefaultValue( config.getKey(), resolveConfigFinalValue(defaultInst.getValue(), envId)); } catch (RuntimeException e) { Environment environment = environmentService.findEnvByID(envId); logger.error( "Register and push config[" + config.getKey() + "] to env[" + (environment != null ? environment.getLabel() : envId) + "] failed.", e); throw e; } }
@Override public String getConfigContextValue(int configId, int envId) { try { List<ConfigInstance> topInsts = configDao.findInstanceByConfig(configId, envId, ServiceConstants.MAX_AVAIL_CONFIG_INST); if (!topInsts.isEmpty()) { Iterator<ConfigInstance> iterator = topInsts.iterator(); while (iterator.hasNext()) { ConfigInstance inst = iterator.next(); if (inst.isDefault()) { iterator.remove(); break; } } } JSONArray valueArray = new JSONArray(); for (ConfigInstance topInst : topInsts) { JSONObject valueObj = new JSONObject(); valueObj.put("value", resolveConfigFinalValue(topInst.getValue(), envId)); valueObj.put("context", topInst.getContext()); valueArray.put(valueObj); } return valueArray.toString(); } catch (JSONException e) { Config config = getConfig(configId); throw new RuntimeBusinessException( "Cannot create config[key=" + config.getKey() + "]'s register value, " + "plz check its instances' value.", e); } }
private void updateReferencedInstances( Config config, List<ConfigInstance> refInstances, ConfigSetType setType) { try { for (ConfigInstance refInstance : refInstances) { int envId = refInstance.getEnvId(); try { if (setType == ConfigSetType.RegisterAndPush) { registerAndPush(refInstance.getConfigId(), envId); } else if (setType == ConfigSetType.Register) { register(refInstance.getConfigId(), envId); } } catch (RuntimeException e) { Config refconfig = getConfig(refInstance.getConfigId()); operationLogService.createOpLog( new OperationLog( OperationTypeEnum.Config_Edit, config.getProjectId(), envId, "同步更新关联引用配置项[" + (refconfig != null ? refconfig.getKey() : refInstance.getConfigId()) + "]出错,请重新保存该配置.") .key(config.getKey(), ConfigInstance.NO_CONTEXT)); } } } catch (Exception e) { logger.error("Update config[" + config.getKey() + "]'s referenced configs failed.", e); } }
@Override public List<ConfigInstance> findInstancesByConfig(int configId, Integer maxPerEnv) { Config config = getConfig(configId); if (config == null) { return Collections.emptyList(); } return configDao.findInstanceByConfig(config.getId(), maxPerEnv); }
public void deleteInstance(Config config, int envId) { if (hasConfigReferencedTo(config.getKey(), envId)) { throw new ReferencedConfigForbidDeleteException(config.getKey()); } configDao.deleteInstance(config.getId(), envId); configDao.deleteStatus(config.getId(), envId); getRegisterService(envId).unregister(config.getKey()); }
public int updateConfig(Config config) { try { config.setModifyUserId(SecurityUtils.getCurrentUserId()); return configDao.update(config); } finally { cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getId()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getKey()); } }
public int createInstance(ConfigInstance instance, ConfigSetType setType) { Integer currentUserId = SecurityUtils.getCurrentUserId(); if (instance.getCreateUserId() == null) { instance.setCreateUserId(currentUserId); } if (instance.getModifyUserId() == null) { instance.setModifyUserId(currentUserId); } processInstanceIfReferenceType(instance); int retryTimes = 0; while (true) { try { instance.setSeq(configDao.getMaxInstSeq(instance.getConfigId(), instance.getEnvId()) + 1); int instId = configDao.createInstance(instance); updateConfigModifyStatus(instance.getConfigId(), instance.getEnvId()); Config config = getConfig(instance.getConfigId()); List<ConfigInstance> refInstances = getInstanceReferencedTo(config.getKey(), instance.getEnvId()); // 确保注册操作是在最后一步 if (setType == ConfigSetType.RegisterAndPush) { registerAndPush(instance.getConfigId(), instance.getEnvId()); } else if (setType == ConfigSetType.Register) { register(instance.getConfigId(), instance.getEnvId()); } updateReferencedInstances(config, refInstances, setType); return instId; } catch (RuntimeException e) { if (DBUtils.isDuplicateKeyError(e)) { if (retryTimes++ >= 1) { String errorMsg = StringUtils.isNotBlank(instance.getContext()) ? "该上下文[context]下配置值已存在!" : "默认配置值已存在!"; throw new RuntimeBusinessException(errorMsg); } } else { throw e; } } } }
private int updateInstance(ConfigInstance instance, ConfigSetType setType) { instance.setModifyUserId(SecurityUtils.getCurrentUserId()); processInstanceIfReferenceType(instance); int instId = configDao.updateInstance(instance); updateConfigModifyStatus(instance.getConfigId(), instance.getEnvId()); Config config = getConfig(instance.getConfigId()); List<ConfigInstance> refInstances = getInstanceReferencedTo(config.getKey(), instance.getEnvId()); // 确保注册操作是在最后一步(后续的都需要try-catch掉所有error) if (setType == ConfigSetType.RegisterAndPush) { registerAndPush(instance.getConfigId(), instance.getEnvId()); } else if (setType == ConfigSetType.Register) { register(instance.getConfigId(), instance.getEnvId()); } updateReferencedInstances(config, refInstances, setType); return instId; }
@Override public ConfigDeleteResult delete(int configId) { final ConfigDeleteResult result = new ConfigDeleteResult(); final Config config = getConfig(configId); if (config != null) { result.setConfig(config); List<Environment> environments = environmentService.findAll(); for (final Environment environment : environments) { try { this.transactionTemplate.execute( new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { deleteInstance(config, environment.getId()); } }); } catch (RuntimeException e) { logger.error( "Delete config[" + config.getKey() + "] in environment[" + environment.getLabel() + "] failed.", e); result.addFailedEnv(environment.getLabel()); if (e instanceof ReferencedConfigForbidDeleteException) { result.setHasReference(true); } } } if (result.isSucceed()) { configDao.delete(configId); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + configId); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getKey()); } } return result; }
@Override public void moveUp(int projectId, Integer configId) { Config config = getConfig(configId); if (config == null) { throw new EntityNotFoundException("Config[id=" + configId + "] not found."); } projectDao.lockProject(projectId); Config prevConfig = configDao.getPrevConfig(configId); if (prevConfig != null) { try { int seq = config.getSeq(); config.setSeq(prevConfig.getSeq()); prevConfig.setSeq(seq); configDao.update(config); configDao.update(prevConfig); } finally { cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getId()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getKey()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + prevConfig.getId()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + prevConfig.getKey()); } } }
@Override public void moveDown(int projectId, int configId) { Config config = getConfig(configId); if (config == null) { throw new EntityNotFoundException("Config[id=" + configId + "] not found."); } projectDao.lockProject(projectId); // 锁定指定projectId,避免同一项目下的config出现相同的seq值 Config nextConfig = configDao.getNextConfig(configId); if (nextConfig != null) { try { int seq = config.getSeq(); config.setSeq(nextConfig.getSeq()); nextConfig.setSeq(seq); configDao.update(config); configDao.update(nextConfig); } finally { cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getId()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + config.getKey()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + nextConfig.getId()); cacheClient.remove(ServiceConstants.CACHE_CONFIG_PREFIX + nextConfig.getKey()); } } }
@Override public List<ConfigVo> findConfigVos(ConfigCriteria criteria) { int projectId = criteria.getProjectId(); int envId = criteria.getEnvId(); HasValueEnum hasValue = EnumUtils.fromEnumProperty(HasValueEnum.class, "value", criteria.getHasValue()); List<Config> configs = configDao.findConfigByProject(projectId); List<ConfigVo> configVos = new ArrayList<ConfigVo>(configs.size()); if (!configs.isEmpty()) { List<Integer> hasInstanceConfigs = configDao.findHasInstanceConfigs(projectId, envId); List<Integer> hasContextInstConfigs = configDao.findHasContextInstConfigs(projectId, envId); Map<Integer, ConfigInstance> defaultInsts = configDao.findDefaultInstance(projectId, envId); List<Integer> hasReferencedConfigs = isSharedProject(projectId) ? configDao.getProjectHasReferencedConfigs(projectId) : Collections.<Integer>emptyList(); for (Config config : configs) { // 配置不会太多,使用内存过滤,无分页,如果配置太多影响到性能则考虑数据库过滤和分页 String key = StringUtils.trim(criteria.getKey()); String value = StringUtils.trim(criteria.getValue()); ConfigInstance defaultInst = defaultInsts.get(config.getId()); if ((StringUtils.isEmpty(key) || config.getKey().contains(key)) && (hasValue == HasValueEnum.All || (hasValue == HasValueEnum.Yes && defaultInst != null) || (hasValue == HasValueEnum.No && defaultInst == null)) && (StringUtils.isEmpty(value) || (defaultInst != null && defaultInst.getValue().contains(value)))) { configVos.add( new ConfigVo( config, hasInstanceConfigs.contains(config.getId()), hasContextInstConfigs.contains(config.getId()), hasReferencedConfigs.contains(config.getId()), defaultInst)); } } } return configVos; }
@Override public void setConfigValue( int projectId, int envId, String key, String desc, String context, String value, ConfigSetType setType) { Config config = findConfigByKey(key); int configId = 0; if (config == null) { config = new Config(); config.setKey(key); config.setDesc(desc); config.setTypeEnum(ConfigTypeEnum.String); config.setProjectId(projectId); configId = create(config); } else { configId = config.getId(); } setConfigValue(configId, envId, context, value, setType); }
@Override public int create(Config config) { Config configFound = configDao.findConfigByKey(config.getKey()); if (configFound != null) { Project project = projectDao.getProject(configFound.getProjectId()); throw new RuntimeBusinessException( "该配置项已存在(project: " + (project != null ? project.getName() : "***") + ", desc: " + configFound.getDesc() + ")!"); } Integer currentUserId = SecurityUtils.getCurrentUserId(); int projectId = config.getProjectId(); if (config.getCreateUserId() == null) { config.setCreateUserId(currentUserId); } if (config.getModifyUserId() == null) { config.setModifyUserId(currentUserId); } projectDao.lockProject(projectId); if (!config.isPrivatee()) { config.setPrivatee(isSharedProject(projectId)); } config.setSeq(configDao.getMaxSeq(projectId) + 1); return configDao.create(config); }