package logwire.web.bo.session; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import logwire.core.bo.object.BizObject; import logwire.core.exceptions.ApplicationException; import logwire.core.meta.model.Model; import logwire.core.support.ApplicationContextHelper; import logwire.web.security.SecurityUtil; import logwire.web.security.TenantUser; import logwire.web.service.ActionContext; import logwire.web.service.event.BuiltinEventNames; import logwire.web.service.query.QueryService; import logwire.web.service.query.sql.QueryTransactionCode; import java.util.List; import java.util.Map; import java.util.Set; /** * 业务对象操作上下文会话 */ public class Session { /* private ActionContext actionContext; public Session(ActionContext actionContext) { this.actionContext = actionContext; } */ /** * 业务对象的缓存 * 第一层 map 的 key 为 model 名称 * 第二层 map 的 key 为 主键值 *//* private Map<String, Map<String, BizObject>> cache = Maps.newHashMap(); */ /** * 业务对象主键值的缓存 * 第一层 map 的 key 为 model 名称 * 第二层 map 的 key 为 model 某个字段的名称 * 第三层 map 的 key 为 model 某个字段的值, value 为 model 主键的值 *//* private Map<String, Map<String, Map<String, Set<Object>>>> pkCache = Maps.newHashMap(); */ /** * 保存业务对象之间的关系 * 第一层 map 的 key 为 明细表的 model 名称 * 第二层 map 的 key 为 明细表的主键值 * 第三层 map 的 value 为明细表对应的主表对应的业务对象 * <p> * 保存时需要,先保存主表,再保存明细表 *//* private Map<String, Map<String, Set<BizObject>>> itemHeaderRelations = Maps.newHashMap(); */ /** * 保存业务对象之间的关系 * 第一层 map 的 key 为 item 关系的主表对应的 model 名称 * 第二层 map 的 key 为 主键值 * 第三层 map 的 value 为 item 关系的明细表对应的业务对象 * <p> * 删除时 * item 关系时,先删除明细表,再删除主表 *//* private Map<String, Map<String, Set<BizObject>>> headerItemRelations = Maps.newHashMap(); */ /** * 保存业务对象之间的关系 * 第一层 map 的 key 为 join 关系的被 join 表 * 第二层 map 的 key 为 主键值 * 第三层 map 的 value 为 join 关系的主表 * <p> * 删除时 * join 关系时,先删除主表,再删除被关联 JOIN 的表 *//* private Map<String, Map<String, Set<BizObject>>> joinOrExtendRelations = Maps.newHashMap(); */ /** * 组合对象和业务对象的映射关系 * key 为 compositeObject.hashCode() *//* private Map<Integer, BizObject> compositeBizObjectMapping = Maps.newHashMap(); */ /** * 组合对象和业务对象中的组合对象类中属性名称的映射关系 * key 为 compositeObject.hashCode() *//* private Map<Integer, String> compositeBizObjectFieldMapping = Maps.newHashMap(); */ /** * 业务对象数据的存放 *//* private Map<Integer, OperableAgent> operableAgentMap = Maps.newHashMap(); */ /** * 待持久化的业务对象 *//* private List<BizObject> bizObjects = Lists.newArrayList(); public ActionContext getActionContext() { return actionContext; } */ /** * 将业务对象存入上下文中 * * @param t 业务对象 *//* public void add(BizObject t) { if (t == null) { return; } int existIndex = -1; for (int i = 0; i < bizObjects.size(); i++) { if (t.equals(bizObjects.get(i))) { existIndex = i; break; } } bizObjects.add(t); if (existIndex != -1) { bizObjects.remove(existIndex); } } private class PersistedRecorder { */ /** * 暂存已执行持久化操作的业务对象标记 *//* private Map<Integer, Boolean> record = Maps.newHashMap(); public void accept(BizObject t) { record.put(t.hashCode(), true); } public boolean persistent(BizObject t) { return record.containsKey(t.hashCode()); } } */ /** * 持久化 *//* public void commit(QueryService queryService) { if (this.bizObjects.isEmpty()) { return; } PersistedRecorder persistedRecorder = new PersistedRecorder(); //待新增的业务对象 Map<String, List<BizObject>> insertBizObjects = Maps.newConcurrentMap(); //非待新增的业务对象 List<BizObject> otherBizObjects = Lists.newArrayList(); while (!this.bizObjects.isEmpty()) { //将业务对象按照持久化方式分类为新增和其他 for (int i = 0; i < this.bizObjects.size(); i++) { BizObject t = this.bizObjects.get(i); if (QueryTransactionCode.TX_INSERT.equals(t.getTxCode())) { List<BizObject> list = insertBizObjects.get(t.getBoName()); if (list == null) { list = Lists.newArrayList(); insertBizObjects.put(t.getBoName(), list); } list.add(t); } else { otherBizObjects.add(t); } } this.bizObjects.clear(); //执行新增操作 for (Map.Entry<String, List<BizObject>> entry : insertBizObjects.entrySet()) { List<BizObject> bizObjects = entry.getValue(); if (bizObjects == null) { continue; } for (int i = 0; i < bizObjects.size(); i++) { BizObject bizObject = bizObjects.get(i); if (persistedRecorder.persistent(bizObject)) { continue; } persistedInsert(bizObject, queryService, persistedRecorder); } } insertBizObjects.clear(); //执行编辑和删除操作 for (int i = 0; i < otherBizObjects.size(); i++) { BizObject bizObject = otherBizObjects.get(i); if (persistedRecorder.persistent(bizObject)) { continue; } persisted(bizObject, queryService, persistedRecorder); } otherBizObjects.clear(); } SessionHolder.clear(); } private void persistedHeader(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) { //明细表有增删改时,头表一定要修改(如果不是新增的头表)而不管主表的数据是否有变化 Map<String, Set<BizObject>> headers = itemHeaderRelations.get(t.getBoName()); if (headers != null && !headers.isEmpty()) { Set<BizObject> set = headers.get(t.getId()); if (set == null || set.isEmpty()) { return; } for (BizObject header : set) { if (persistedRecorder.persistent(header)) { continue; } BizObjectAgent agent = getOperableAgent(t); agent.setForceUpdate(); persisted(header, queryService, persistedRecorder); } } } private void persistedInsert(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) { BizObjectAgent agent = getOperableAgent(t); TenantUser currentUser = SecurityUtil.currentUser(); if (BizObjectStatus.NEW_SAVE.equals(t.getTxCode())) { agent.setInternal(QueryTransactionCode.TX_FIELD_NAME, QueryTransactionCode.TX_INSERT); // persistedBefore(t, itemHeaderRelations, queryService); TODO 新增明细表前先新增主表 queryService.insert(t.getBoName(), t.toMap()); persistedRecorder.accept(t); persistedHeader(t, queryService, persistedRecorder); } } private void persisted(BizObject t, QueryService queryService, PersistedRecorder persistedRecorder) { BizObjectAgent agent = getOperableAgent(t); TenantUser currentUser = SecurityUtil.currentUser(); if (BizObjectStatus.UPDATE.equals(t.getBizObjectStatus())) { agent.setInternal(QueryTransactionCode.TX_FIELD_NAME, QueryTransactionCode.TX_UPDATE); actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_UPDATE_BEFORE.name(), currentUser.getDomain(), t); queryService.update(t.getModelName(), t.toMap()); actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_UPDATE_AFTER.name(), currentUser.getDomain(), t); persistedRecorder.accept(t); persistedHeader(t, queryService, persistedRecorder); } else if (BizObjectStatus.DELETED.equals(t.getBizObjectStatus())) { agent.setInternal(QueryTransactionCode.TX_FIELD_NAME, QueryTransactionCode.TX_DELETE); persistedBefore(t, headerItemRelations, queryService, persistedRecorder); persistedBefore(t, joinOrExtendRelations, queryService, persistedRecorder); actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_DELETE_BEFORE.name(), currentUser.getDomain(), t); Model model = actionContext.model(t.getModelName()); boolean hasVersion = model.getIncludeVersionField(); boolean deleted; Object pkValue = t.getPkValue(); if (hasVersion) { deleted = queryService.delete(t.getModelName(), t.getPkValue(), (int) t.get(Model.VERSION_FIELD_NAME)); } else { deleted = queryService.delete(t.getModelName(), t.getPkValue()); } if (!deleted) { throw new ApplicationException(model.getTenantProject().getMessageSourceAccessor().getMessage( "failed.delete.biz-object", new Object[]{model.getVerboseNameI18n(), model.getPrimaryKeyField().getName(), pkValue}, String.format("删除失败:找不到或无权访问 [%s] 为 [%s] 的业务对象[%s]", model.getPrimaryKeyField().getName(), pkValue, model.getVerboseNameI18n()))); } actionContext.emit(t.getOperableName(), BuiltinEventNames.BIZ_DELETE_AFTER.name(), currentUser.getDomain(), t); persistedRecorder.accept(t); persistedHeader(t, queryService, persistedRecorder); } } private void persistedBefore(BizObject t, Map<String, Map<String, Set<BizObject>>> relations, QueryService queryService, PersistedRecorder persistedRecorder) { Map<String, Set<BizObject>> map = relations.get(t.getModelName()); if (map == null) { return; } Set<? extends BizObject> set = map.get(t.getPkValue()); if (set == null || set.isEmpty()) { return; } for (BizObject t2 : set) { persistedInsert(t2, queryService, persistedRecorder); persisted(t2, queryService, persistedRecorder); } } public void flush() { cache.clear(); pkCache.clear(); itemHeaderRelations.clear(); headerItemRelations.clear(); joinOrExtendRelations.clear(); compositeBizObjectMapping.clear(); compositeBizObjectFieldMapping.clear(); bizObjects.clear(); operableAgentMap.clear(); } public BizObject getBizObjectByCompositeObject(Object compositeObject) { if (compositeObject == null) { return null; } return compositeBizObjectMapping.get(compositeObject.hashCode()); } public String getBizObjectCompositeFieldNameByCompositeObject(Object compositeObject) { if (compositeObject == null) { return null; } return compositeBizObjectFieldMapping.get(compositeObject.hashCode()); } public void cacheCompositeBizObject(BizObject bizObject, Object compositeObject, String compositeName) { compositeBizObjectMapping.put(compositeObject.hashCode(), bizObject); compositeBizObjectFieldMapping.put(compositeObject.hashCode(), compositeName); } public void cacheHeaderItemRelation(BizObject header, BizObject item) { cacheBizObjectRelations(headerItemRelations, header, item); cacheBizObjectRelations(itemHeaderRelations, item, header); } public void cacheJoinOrExtendRelation(BizObject main, BizObject joinOrExtend) { cacheBizObjectRelations(joinOrExtendRelations, joinOrExtend, main); } private void cacheBizObjectRelations(Map<String, Map<String, Set<BizObject>>> relationsCollection, BizObject key, BizObject value) { Object pkValue = key.getPkValue(); if (pkValue == null) { return; } Map<String, Set<BizObject>> modelMap = relationsCollection.get(key.getModelName()); if (modelMap == null) { modelMap = Maps.newHashMap(); relationsCollection.put(key.getModelName(), modelMap); } Set<BizObject> set = modelMap.get(pkValue.toString()); if (set == null) { set = Sets.newHashSet(); modelMap.put(pkValue.toString(), set); } set.add(value); } */ /** * 缓存根据某个字段作为查询条件加载得到的若干业务对象 * 此处只缓存业务对象中的主键值 * 因为 Session 是线程安全的,所以此处内部不考虑并发问题 * * @param t * @param fieldName *//* public void cache(BizObject t, String fieldName) { Object pkValue = t.getId(); if (pkValue == null) { return; } //拿到存放某个 model 的主键缓存值的 map Map<String, Map<String, Set<Object>>> modelMap = pkCache.get(t.getBoName()); if (modelMap == null) { modelMap = Maps.newHashMap(); pkCache.put(t.getBoName(), modelMap); } //拿到存放通过某个 model 的 某个字段查询得到的主键后缓存值的 map Map<String, Set<Object>> fieldMap = modelMap.get(fieldName); if (fieldMap == null) { fieldMap = Maps.newHashMap(); modelMap.put(fieldName, fieldMap); } //拿到存放通过某个 model 的 某个字段查询得到的主键后缓存的主键值的列表 Object fieldValue = t.get(fieldName); Set<Object> set = fieldMap.get(fieldValue.toString()); if (set == null) { set = Sets.newHashSet(); fieldMap.put(fieldValue.toString(), set); } set.add(t.getPkValue()); fieldMap.put(fieldValue.toString(), set); } public void cacheAgent(OperableAgent agent) { operableAgentMap.put(agent.getTarget().hashCode(), agent); } */ /** * 缓存业务对象 * 因为 Session 是线程安全的,所以此处内部不考虑并发问题 * * @param t *//* public void cache(BizObject t) { if (t == null) { return; } Object pkValue = t.getPkValue(); if (pkValue == null) { return; } Map<String, BizObject> map = cache.get(t.getModelName()); if (map == null) { map = Maps.newHashMap(); cache.put(t.getModelName(), map); } map.put(pkValue.toString(), t); } public void remove(BizObject t) { //删除缓存中的数据 Map<String, BizObject> map = cache.get(t.getModelName()); if (map == null) { return; } Object pkValue = t.getPkValue(); if (pkValue == null) { return; } if (map.containsKey(pkValue.toString())) { map.remove(pkValue.toString()); } bizObjects.remove(t); } private boolean isNew(BizObject t) { return BizObjectStatus.NEW.equals(t.getBizObjectStatus()); } */ /** * 从上下文中获取之前加载过的业务对象 * * @param modelName * @param pkValue * @return *//* public <T extends BizObject> T get(String modelName, Object pkValue) { if (modelName == null || pkValue == null) { return null; } Map<String, BizObject> map = cache.get(modelName); if (map == null) { return null; } return (T) map.get(pkValue.toString()); } */ /** * 从上下文中获取之前加载过的业务对象 * * @param modelName * @param fieldName * @param fieldValue * @return *//* public <T extends BizObject> List<T> get(String modelName, String fieldName, Object fieldValue) { if (modelName == null || fieldName == null || fieldValue == null) { return null; } Map<String, Map<String, Set<Object>>> modelMap = pkCache.get(modelName); if (modelMap == null || modelMap.isEmpty()) { return null; } Map<String, Set<Object>> fieldMap = modelMap.get(fieldName); if (fieldMap == null || fieldMap.isEmpty()) { return null; } Set pkValues = fieldMap.get(fieldValue.toString()); if (pkValues == null || pkValues.isEmpty()) { return null; } List<T> result = Lists.newArrayList(); pkValues.forEach(pkValue -> { T t = get(modelName, pkValue); if (t != null) { result.add(t); } }); return result; } public <T extends Operable, R extends OperableAgent> R getOperableAgent(T operable) { return (R) operableAgentMap.get(operable.hashCode()); } */ }