提交 42adebf3 编写于 作者: zhouweidong's avatar zhouweidong

区分本地与远程逻辑

上级 1b3af286
......@@ -3,9 +3,461 @@ TARGET=PSSYSTEM
</#ibiztemplate>
<#if sys.getCodeName()=='Sample' || sys.getCodeName()=='EAM'>
<#assign isDynaSys =false>
<#if pub.isEnableDynaModel()?? && pub.isEnableDynaModel()== true>
<#if sys.getAllPSSystemModules()??>
<#list sys.getAllPSSystemModules() as module>
<#if module.getDynaInstMode()?? && module.getDynaInstMode()=='1'>
<#assign isDynaSys =true>
<#break>
</#if>
</#list>
</#if>
<#comment>非动态系统,加载本地逻辑</#comment>
<#if !isDynaSys>
package ${pub.getPKGCodeName()}.util.aspect;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import ${pub.getPKGCodeName()}.util.domain.DELogic;
import ${pub.getPKGCodeName()}.util.domain.EntityBase;
import ${pub.getPKGCodeName()}.util.errors.BadRequestAlertException;
import ${pub.getPKGCodeName()}.util.helper.DEFieldCacheMap;
import org.apache.commons.io.IOUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.Message;
import org.kie.api.builder.Results;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.internal.io.ResourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 实体处理逻辑切面(前后附加逻辑、实体行为调用处理逻辑)
*/
@Aspect
@Component
@Slf4j
public class DELogicAspect {
private static BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
private final ExpressionParser parser = new SpelExpressionParser();
private ConcurrentMap<String, DELogic> deLogicMap = new ConcurrentHashMap<>();
private final String DEFAULT_MODULE_PACKAGE = "[\\w+\\.]\\.core.(\\w+)\\.domain";
private static Map<String, Object> validLogic = new HashMap<>();
/**
* 执行实体行为附加逻辑、实体行为调用处理逻辑
*
* @param point
* @return
* @throws Throwable
*/
@Around("execution(* ${pub.getPKGCodeName()}.core.*.service.*.*(..))")
public Object executeLogic(ProceedingJoinPoint point) throws Throwable {
Object args[] = point.getArgs();
if (ObjectUtils.isEmpty(args) || args.length == 0) {
return point.proceed();
}
Object service = point.getTarget();
Object arg = args[0];
String action = point.getSignature().getName();
EntityBase entity = null;
if ("remove".equalsIgnoreCase(action) || "get".equalsIgnoreCase(action)) {
entity = getEntity(service);
String id = DEFieldCacheMap.getDEKeyField(entity.getClass());
entity.set(id, arg);
} else if (arg instanceof EntityBase) {
entity = (EntityBase) arg;
}
if (entity != null) {
executeBeforeLogic(entity, action);
Object result = point.proceed();
executeLogic(entity, action);
executeAfterLogic(entity, action);
return result;
}
return point.proceed();
}
/**
* 前附加逻辑
*
* @param entity
* @param action
*/
private void executeBeforeLogic(EntityBase entity, String action) {
File bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.BEFORE);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
}
}
/**
* 后附加逻辑
*
* @param entity
* @param action
*/
private void executeAfterLogic(EntityBase entity, String action) {
File bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.AFTER);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
}
}
/**
* 实体行为调用处理逻辑
*
* @param entity
* @param action
*/
private void executeLogic(EntityBase entity, String action) {
File bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.EXEC);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
}
}
/**
* 编译并执行规则(bpmndrl
*
* @param bpmnFile
* @param entity
*/
private void executeLogic(File bpmnFile, Object entity, String action, LogicMode logicMode) {
log.debug("开始执行实体处理逻辑[{}:{}:{}:{}]", entity.getClass().getSimpleName(), action, bpmnFile.getName(), logicMode.text);
String bpmnId = DigestUtils.md5DigestAsHex(bpmnFile.getPath().getBytes());
DELogic logic = getDELogic(bpmnFile, entity, logicMode);
if (logic == null) {
return;
}
if (deLogicMap.containsKey(bpmnId) && logic.getMd5().equals(deLogicMap.get(bpmnId).getMd5())) {
logic = deLogicMap.get(bpmnId);
} else {
reloadLogic(logic);
deLogicMap.put(bpmnId, logic);
}
KieContainer container = logic.getContainer();
KieSession kieSession = container.getKieBase().newKieSession();
Process mainProcess = logic.getProcess();
//主流程参数
fillGlobalParam(kieSession, mainProcess, entity);
//子流程参数
if (!ObjectUtils.isEmpty(logic.getRefLogic())) {
for (DELogic subLogic : logic.getRefLogic()) {
fillGlobalParam(kieSession, subLogic.getProcess(), entity);
}
}
kieSession.startProcess(mainProcess.getId());
log.debug("实体处理逻辑[{}:{}:{}:{}]执行结束", entity.getClass().getSimpleName(), action, bpmnFile.getName(), logicMode.text);
}
/**
* 编译规则
*
* @param logic
*/
private void reloadLogic(DELogic logic) {
KieServices kieServices = KieServices.get();
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
for (File bpmn : logic.getRefRuleFiles()) {
kieFileSystem.write(ResourceFactory.newFileResource(bpmn));
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem).buildAll();
Results results = kieBuilder.getResults();
if (results.hasMessages(Message.Level.ERROR)) {
throw new BadRequestAlertException(String.format("编译实体处理逻辑 [%s] 发生异常, %s", logic.getName(), results.getMessages()), "LogicAspect", "reloadLogic");
}
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
logic.setContainer(kieContainer);
}
/**
* 填充逻辑参数
*
* @param kieSession
* @param process
* @param entity
*/
private void fillGlobalParam(KieSession kieSession, Process process, Object entity) {
Map<String, List<ExtensionElement>> params = process.getExtensionElements();
for (Map.Entry<String, List<ExtensionElement>> param : params.entrySet()) {
if ("metaData".equalsIgnoreCase(param.getKey())) {
List<ExtensionElement> globalParams = param.getValue();
for (ExtensionElement globalParam : globalParams) {
Object value = null;
Map<String, List<ExtensionAttribute>> globalParamAttr = globalParam.getAttributes();
ExtensionAttribute name = globalParamAttr.get("name").get(0);
ExtensionAttribute type = globalParamAttr.get("type").get(0);
ExtensionAttribute express = globalParamAttr.get("express").get(0);
String express_value = express.getValue();
EvaluationContext oldContext = new StandardEvaluationContext();
if ("entity".equalsIgnoreCase(type.getValue())) {
value = entity;
}
if (!ObjectUtils.isEmpty(type.getValue()) && ObjectUtils.isEmpty(value)) {
Expression oldExp = parser.parseExpression(express_value);
value = oldExp.getValue(oldContext);
}
if ("entity".equalsIgnoreCase(type.getValue()) || "refentity".equalsIgnoreCase(type.getValue())) {
kieSession.insert(value);
}
kieSession.setGlobal(name.getValue(), value);
}
}
}
}
/**
* 获取逻辑配置
*
* @param bpmnFile
* @param entity
* @return
*/
@SneakyThrows
private DELogic getDELogic(File bpmnFile, Object entity, LogicMode logicMode) {
DELogic logic = null;
XMLStreamReader reader = null;
InputStream bpmn = null;
try {
if (bpmnFile.exists()) {
XMLInputFactory factory = XMLInputFactory.newInstance();
bpmn = new FileInputStream(bpmnFile);
reader = factory.createXMLStreamReader(bpmn);
BpmnModel model = bpmnXMLConverter.convertToBpmnModel(reader);
Process mainProcess = model.getMainProcess();
if (mainProcess == null) {
return null;
}
List<DELogic> refLogics = new ArrayList<>();
List<File> refFiles = new ArrayList<>();
//自己 bpmn drl
refFiles.add(bpmnFile);
File drlFile = getDrl(bpmnFile);
if (drlFile.exists()) {
refFiles.add(drlFile);
}
// bpmn drl
if (!ObjectUtils.isEmpty(model.getMainProcess()) && !ObjectUtils.isEmpty(model.getMainProcess().getFlowElementMap())) {
model.getMainProcess().getFlowElementMap().values().forEach(item -> {
if (item instanceof CallActivity) {
CallActivity subBpmn = (CallActivity) item;
String bpmnFileName = subBpmn.getName();
log.debug("正在加载 BPMN{}", bpmnFileName);
File subBpmnFile = getSubBpmn(getDEModule(entity), entity.getClass().getSimpleName(), bpmnFileName, logicMode);
if (ObjectUtils.isEmpty(subBpmnFile)) {
log.debug("BPMN:{},缺少文件:{} ", bpmnFileName, subBpmnFile);
}
DELogic refLogic = getDELogic(subBpmnFile, entity, logicMode);
if (refLogic != null) {
refLogics.add(refLogic);
if (!ObjectUtils.isEmpty(refLogic.getRefRuleFiles())) {
refFiles.addAll(refLogic.getRefRuleFiles());
}
}
}
});
}
logic = new DELogic();
logic.setId(mainProcess.getId());
logic.setName(mainProcess.getName());
logic.setProcess(mainProcess);
logic.setRefLogic(refLogics);
logic.setRefRuleFiles(refFiles);
logic.setMd5(getMd5(refFiles));
}
} catch (Exception e) {
} finally {
try {
if (reader != null) {
reader.close();
}
if (bpmn != null) {
bpmn.close();
}
} catch (Exception e) {
}
}
return logic;
}
/**
* 获取实体
*
* @param service
* @return
* @throws Exception
*/
private EntityBase getEntity(Object service) throws Exception {
Method[] methods = service.getClass().getDeclaredMethods();
for (Method method : methods) {
for (Class cls : method.getParameterTypes()) {
try {
Object arg = cls.newInstance();
if (arg instanceof EntityBase) {
return (EntityBase) arg;
}
} catch (InstantiationException e) {
}
}
}
throw new BadRequestAlertException("获取实体信息失败", "DELogicAspect", "getEntity");
}
/**
* 获取bpmn md5
*
* @param subFiles
* @return
*/
private String getMd5(List<File> subFiles) {
try {
StringBuffer buffer = new StringBuffer();
for (File file : subFiles) {
InputStream bpmnFile = null;
try {
bpmnFile = new FileInputStream(file);
if (!ObjectUtils.isEmpty(bpmnFile)) {
String strBpmn = IOUtils.toString(bpmnFile, "UTF-8");
buffer.append(strBpmn);
}
} catch (Exception e) {
} finally {
if (bpmnFile != null) {
bpmnFile.close();
}
}
}
if (!StringUtils.isEmpty(buffer.toString())) {
return DigestUtils.md5DigestAsHex(buffer.toString().getBytes());
} else {
return null;
}
} catch (Exception e) {
return null;
}
}
/**
* 本地逻辑
*
* @param entity
* @param action
* @param logicExecMode
* @return
*/
private File getLocalModel(String entity, String action, LogicExecMode logicExecMode) {
String logicName = String.format("%s.bpmn", logicExecMode.value);
String filePath = File.separator + "rules" + File.separator + entity.toLowerCase() + File.separator + action + File.separator + logicName;
URL url = this.getClass().getResource(filePath.replace("\\", "/"));
return ObjectUtils.isEmpty(url) ? null : new File(url.getPath());
}
/**
* 处理逻辑 bpmn
*
* @param module
* @param entity
* @param logicName
* @return
*/
private File getSubBpmn(String module, String entity, String logicName, LogicMode logicMode) {
String filePath = String.format("/rules/%s", logicName);
return ObjectUtils.isEmpty(this.getClass().getResource(filePath)) ? null : new File(this.getClass().getResource(filePath).getPath());
}
/**
* 处理逻辑 drl
*
* @param bpmn
* @return
*/
private File getDrl(File bpmn) {
return new File(bpmn.getPath().replace("RuleFlow.bpmn", "Rule.drl"));
}
/**
* 获取实体模块
*
* @param entity
* @return
*/
private String getDEModule(Object entity) {
String strModule = null;
String packageName = entity.getClass().getPackage().getName();
Pattern p = Pattern.compile(DEFAULT_MODULE_PACKAGE);
Matcher m = p.matcher(packageName);
while (m.find()) {
strModule = m.group(1);
}
if (StringUtils.isEmpty(strModule)) {
throw new BadRequestAlertException(String.format("无法获取实体[%s]所属模块信息", entity.getClass().getSimpleName()), "LogicAspect", "getDEModule");
}
return strModule;
}
/**
* 逻辑是否有效
*
* @param bpmn
* @param entity
* @param action
* @return
*/
private boolean isValid(File bpmn, Object entity, Object action) {
String logicId = String.format("%s%s%s", entity.getClass().getSimpleName(), action, bpmn.getName()).toLowerCase();
if (validLogic.containsKey(logicId)) {
return true;
} else {
return false;
}
}
static {
<@validLogic/>
}
<@enum />
}
</#if>
<#else>
<#comment>加载远程逻辑(动态系统)</#comment>
package ${pub.getPKGCodeName()}.util.aspect;
import lombok.SneakyThrows;
......@@ -71,13 +523,50 @@ public class DELogicAspect {
private ConcurrentMap<String, DELogic> deLogicMap = new ConcurrentHashMap<>();
private final String DEFAULT_MODULE_PACKAGE = "[\\w+\\.]\\.core.(\\w+)\\.domain";
private static Map<String, Object> validLogic = new HashMap<>();
<#if isDynaSys>
@Value("${r'${ibiz.dynamic.path:/app/file/dynamicmodel/}'}")
private String dynamicPath;
@Value("${r'$'}{ibiz.systemid:${sys.getCodeName()}}")
private String systemId;
@Value("${r'$'}{ibiz.dynainstid:${sys.getCodeName()?lower_case}}")
private String dynamicId;
<#assign hasDynamicModule =false>
<#assign hasLocalModule = false>
<#assign dynamicModule="">
<#assign localModule="">
<#if sys.getAllPSSystemModules()??>
<#list sys.getAllPSSystemModules() as module>
<#if module.getDynaInstMode()?? && module.getDynaInstMode()=='1'>
<#assign hasDynamicModule=true>
<#if dynamicModule!="">
<#assign dynamicModule=dynamicModule+" || ">
</#if>
<#assign dynamicModule=dynamicModule+ "execution(* "+pub.getPKGCodeName()+".core."+module.codeName?lower_case+".*.service.*.*(..)) ">
</#if>
</#list>
<#list sys.getAllPSSystemModules() as module>
<#if module.getDynaInstMode()?? && module.getDynaInstMode()=='0'>
<#assign hasLocalModule=true>
<#if localModule!="">
<#assign localModule=localModule+" || ">
</#if>
<#assign localModule=localModule+ "execution(* "+pub.getPKGCodeName()+".core."+module.codeName?lower_case+".*.service.*.*(..)) ">
</#if>
</#list>
<#comment>输出动态模块</#comment>
<#if hasDynamicModule>
@Around("execution(* ${dynamicModule} ")
public Object executeRemoteLogic(ProceedingJoinPoint point) throws Throwable {
return executeLogic(point, true);
}
</#if>
<#if hasLocalModule>
@Around("execution(* ${localModule} ")
public Object executeLocalLogic(ProceedingJoinPoint point) throws Throwable {
return executeLogic(point, false);
}
</#if>
</#if>
/**
......@@ -87,8 +576,7 @@ public class DELogicAspect {
* @return
* @throws Throwable
*/
@Around("execution(* ${pub.getPKGCodeName()}.core.*.service.*.*(..))")
public Object executeLogic(ProceedingJoinPoint point) throws Throwable {
public Object executeLogic(ProceedingJoinPoint point, boolean isDyna) throws Throwable {
Object args[] = point.getArgs();
if (ObjectUtils.isEmpty(args) || args.length == 0) {
return point.proceed();
......@@ -105,10 +593,10 @@ public class DELogicAspect {
entity = (EntityBase) arg;
}
if (entity != null) {
executeBeforeLogic(entity, action);
executeBeforeLogic(entity, action, isDyna);
Object result = point.proceed();
executeLogic(entity, action);
executeAfterLogic(entity, action);
executeLogic(entity, action, isDyna);
executeAfterLogic(entity, action, isDyna);
return result;
}
return point.proceed();
......@@ -120,15 +608,15 @@ public class DELogicAspect {
* @param entity
* @param action
*/
private void executeBeforeLogic(EntityBase entity, String action) {
private void executeBeforeLogic(EntityBase entity, String action, boolean isDyna) {
File bpmnFile;
<#if isDynaSys>
if (isDyna) {
bpmnFile = getRemoteModel(getDEModule(entity), entity.getClass().getSimpleName(), action, LogicExecMode.BEFORE);
if (bpmnFile.exists()) {
executeLogic(bpmnFile, entity, action, LogicMode.REMOTE);
return;
}
</#if>
}
bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.BEFORE);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
......@@ -141,15 +629,15 @@ public class DELogicAspect {
* @param entity
* @param action
*/
private void executeAfterLogic(EntityBase entity, String action) {
private void executeAfterLogic(EntityBase entity, String action, boolean isDyna) {
File bpmnFile;
<#if isDynaSys>
if (isDyna) {
bpmnFile = getRemoteModel(getDEModule(entity), entity.getClass().getSimpleName(), action, LogicExecMode.AFTER);
if (bpmnFile.exists()) {
executeLogic(bpmnFile, entity, action, LogicMode.REMOTE);
return;
}
</#if>
}
bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.AFTER);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
......@@ -162,15 +650,15 @@ public class DELogicAspect {
* @param entity
* @param action
*/
private void executeLogic(EntityBase entity, String action) {
private void executeLogic(EntityBase entity, String action, boolean isDyna) {
File bpmnFile;
<#if isDynaSys>
if (isDyna) {
bpmnFile = getRemoteModel(getDEModule(entity), entity.getClass().getSimpleName(), action, LogicExecMode.EXEC);
if (bpmnFile.exists()) {
executeLogic(bpmnFile, entity, action, LogicMode.REMOTE);
return;
}
</#if>
}
bpmnFile = getLocalModel(entity.getClass().getSimpleName(), action, LogicExecMode.EXEC);
if (bpmnFile != null && bpmnFile.exists() && isValid(bpmnFile, entity, action)) {
executeLogic(bpmnFile, entity, action, LogicMode.LOCAL);
......@@ -413,7 +901,6 @@ public class DELogicAspect {
return ObjectUtils.isEmpty(url) ? null : new File(url.getPath());
}
<#if isDynaSys>
/**
* 远程逻辑
*
......@@ -427,7 +914,6 @@ public class DELogicAspect {
String logicName = String.format("psdeaction.json.%s.bpmn", logicExecMode.value);
return new File(dynamicPath + File.separator + (systemId + File.separator + dynamicId + File.separator + "psmodules" + File.separator + module + File.separator + "psdataentities" + File.separator + entity + File.separator + "psdeactions" + File.separator + action + File.separator + logicName).toLowerCase());
}
</#if>
/**
* 处理逻辑 bpmn
......@@ -438,17 +924,12 @@ public class DELogicAspect {
* @return
*/
private File getSubBpmn(String module, String entity, String logicName, LogicMode logicMode) {
<#if isDynaSys>
if (LogicMode.REMOTE.equals(logicMode)) {
return new File(dynamicPath + File.separator + (systemId + File.separator + dynamicId + File.separator + "psmodules" + File.separator + module + File.separator + "psdataentities" + File.separator + entity + File.separator + "psdelogics" + File.separator + logicName + File.separator + "psdelogic.json.bpmn").toLowerCase());
} else {
String filePath = String.format("/rules/%s", logicName);
return ObjectUtils.isEmpty(this.getClass().getResource(filePath)) ? null : new File(this.getClass().getResource(filePath).getPath());
}
<#else>
String filePath = String.format("/rules/%s", logicName);
return ObjectUtils.isEmpty(this.getClass().getResource(filePath)) ? null : new File(this.getClass().getResource(filePath).getPath());
</#if>
}
......@@ -459,15 +940,11 @@ public class DELogicAspect {
* @return
*/
private File getDrl(File bpmn) {
<#if isDynaSys>
if (bpmn.getPath().endsWith("RuleFlow.bpmn")) {
return new File(bpmn.getPath().replace("RuleFlow.bpmn", "Rule.drl"));
} else {
return new File(bpmn.getPath().replace(".bpmn", ".drl"));
}
<#else>
return new File(bpmn.getPath().replace("RuleFlow.bpmn", "Rule.drl"));
</#if>
}
/**
......@@ -490,7 +967,6 @@ public class DELogicAspect {
return strModule;
}
<#if isDynaSys>
/**
* 执行动态行为
*
......@@ -519,7 +995,6 @@ public class DELogicAspect {
}
}
}
</#if>
/**
* 逻辑是否有效
......@@ -539,6 +1014,17 @@ public class DELogicAspect {
}
static {
<@validLogic />
}
<@enum />
}
</#if>
<#comment>输出可用的逻辑</#comment>
<#macro validLogic>
<#if sys.getAllPSDataEntities()??>
<#list sys.getAllPSDataEntities() as dataEntity>
<#if dataEntity.getAllPSDEActions()??>
......@@ -569,9 +1055,10 @@ public class DELogicAspect {
</#if>
</#list>
</#if>
}
</#macro>
<#comment>输出枚举类</#comment>
<#macro enum>
public enum LogicMode {
/**
* 本地
......@@ -613,6 +1100,4 @@ public class DELogicAspect {
private String value;
private String text;
}
}
</#if>
\ No newline at end of file
</#macro>
\ No newline at end of file
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册