diff --git a/dashboard/package-lock.json b/dashboard/package-lock.json index 1d1ab3979cda2b6b837f88598b65ae5bf455b354..151fdc2e188b961f015d6ec154b5d8fb95c447b2 100644 --- a/dashboard/package-lock.json +++ b/dashboard/package-lock.json @@ -11,9 +11,11 @@ "@antv/g2": "v4.2.8", "@antv/g6": "^4.8.5", "@antv/vis-predict-engine": "^0.1.1", + "@highlightjs/vue-plugin": "^2.1.0", "@layui/layui-vue": "1.8.4", "axios": "^1.2.1", "echarts": "^5.4.1", + "highlight.js": "^11.7.0", "js-base64": "^3.7.2", "mockjs": "^1.1.0", "monaco-editor": "^0.34.1", @@ -848,6 +850,15 @@ "node": ">=12" } }, + "node_modules/@highlightjs/vue-plugin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@highlightjs/vue-plugin/-/vue-plugin-2.1.0.tgz", + "integrity": "sha512-E+bmk4ncca+hBEYRV2a+1aIzIV0VSY/e5ArjpuSN9IO7wBJrzUE2u4ESCwrbQD7sAy+jWQjkV5qCCWgc+pu7CQ==", + "peerDependencies": { + "highlight.js": "^11.0.1", + "vue": "^3" + } + }, "node_modules/@intlify/core-base": { "version": "9.1.10", "resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.1.10.tgz", @@ -2449,6 +2460,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/highlight.js": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz", + "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/htmlparser2": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", diff --git a/dashboard/package.json b/dashboard/package.json index 7ba33b7993bcb4418459c0b9347bf98de9878408..201ab523a982e657085350f6366ba3bcf288952e 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -11,9 +11,11 @@ "@antv/g2": "v4.2.8", "@antv/g6": "^4.8.5", "@antv/vis-predict-engine": "^0.1.1", + "@highlightjs/vue-plugin": "^2.1.0", "@layui/layui-vue": "1.8.4", "axios": "^1.2.1", "echarts": "^5.4.1", + "highlight.js": "^11.7.0", "js-base64": "^3.7.2", "mockjs": "^1.1.0", "monaco-editor": "^0.34.1", diff --git a/dashboard/src/main.ts b/dashboard/src/main.ts index 7c98cffc07f471bfb60eccf154a9b0aaff710374..7173ca17113bfb22152c8903ee83577ee7ffddaa 100644 --- a/dashboard/src/main.ts +++ b/dashboard/src/main.ts @@ -13,3 +13,33 @@ app.use(Router); app.directive("permission",permission); app.mount('#app'); + +// 代码高亮插件 +import hljs from 'highlight.js'; +// 必须导入 否则没样式 +import 'highlight.js/styles/github-dark-dimmed.css'; +import 'highlight.js/lib/common'; +import hjsVuePlugin from '@highlightjs/vue-plugin'; +const high: any = { + deep: true, + bind: function (el: any, binding: any) { + const targets = el.querySelectorAll('code') + targets.forEach((target: any) => { + if (binding.value) { + target.textContent = binding.value; + } + (hljs as any).highlightBlock(target); + }) + }, + componentUpdated: function (el: any, binding: any) { + const targets = el.querySelectorAll('code') + targets.forEach((target: any) => { + if (binding.value) { + target.textContent = binding.value; + (hljs as any).highlightBlock(target); + } + }) + } +} +app.directive('highlightjs', high) +app.use(hjsVuePlugin); diff --git a/dashboard/src/mockjs/user.ts b/dashboard/src/mockjs/user.ts index a0770eb144865141845df033c5017969ec1ae285..2e2dbc440d86509a2d256aa4d270ba50f22e8c6d 100644 --- a/dashboard/src/mockjs/user.ts +++ b/dashboard/src/mockjs/user.ts @@ -37,7 +37,7 @@ const menus = [ { id: "/engine-manager", icon: "layui-icon-senior", - title: "引擎管理", + title: "实时监控", children:[ { id: "/engine-manager/engines-list", diff --git a/dashboard/src/views/Engines/history-detail.vue b/dashboard/src/views/Engines/history-detail.vue index cf41ecd1f8784756cf71a485cfbdf1188c7ecc0c..3433733d3dc29c1b29de4d6b6b8a65e022f54362 100644 --- a/dashboard/src/views/Engines/history-detail.vue +++ b/dashboard/src/views/Engines/history-detail.vue @@ -106,6 +106,7 @@ export default { selectionClipboard: false, // 选择剪切板 automaticLayout: true, // 自动布局 codeLens: false, // 代码镜头 + tabCompletion: 'on', scrollBeyondLastLine: false, // 滚动完最后一行后再滚动一屏幕 colorDecorators: true, // 颜色装饰器 accessibilitySupport: "off", // 辅助功能支持 "auto" | "off" | "on" diff --git a/dashboard/src/views/ReportManager/metrics_detail.vue b/dashboard/src/views/ReportManager/metrics_detail.vue index 3d47718ef1e03df1df69bd488c40a438ccc52d36..6403886a88dc626b8669cae2c2b332d75ccc6c3a 100644 --- a/dashboard/src/views/ReportManager/metrics_detail.vue +++ b/dashboard/src/views/ReportManager/metrics_detail.vue @@ -2,7 +2,7 @@
- +

基本信息

@@ -30,7 +30,15 @@
- +
@@ -44,20 +52,27 @@
-
- +
+ +
-
- +
+
- -
- + +
+
+ +
+
+
+
+ +
@@ -91,11 +106,6 @@ + + + + + + + + +
+
+
+
+
+ + + diff --git a/smart-flow-core/pom.xml b/smart-flow-core/pom.xml index 55e79d2efe77f368f14e55efe6f5dce290f1c986..3d801eb1d7d8ad274a099854113f0c37e8ec06ba 100644 --- a/smart-flow-core/pom.xml +++ b/smart-flow-core/pom.xml @@ -5,7 +5,7 @@ org.smartboot.flow smart-flow-parent - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/EngineConstants.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/EngineConstants.java deleted file mode 100644 index 54b59ce815bf1053881ef2e3777fde837f4eca87..0000000000000000000000000000000000000000 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/EngineConstants.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.smartboot.flow.core; - -/** - * @author qinluo - * @date 2023/2/1 21:52 - * @since 1.0.0 - */ -public interface EngineConstants { - - /** - * 匿名Pipeline前缀 - */ - String ANONYMOUS_PREFIX = "anonymous-pipeline"; - - int TAB_SIZE = 4; -} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListener.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListener.java index 6d697c7da3f57231d99d4166a7b3ea5128b2dedc..cd6a41b8e946965fbca4c7f8af29b9fa30a57f5e 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListener.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListener.java @@ -11,13 +11,17 @@ public interface ExecutionListener { * 开始执行 * @param ctx ctx 上下文 */ - void start(EngineContext ctx); + default void start(EngineContext ctx) { + + } /** * 结束执行 * @param ctx ctx 上下文 */ - void completed(EngineContext ctx); + default void completed(EngineContext ctx) { + + } /** * 开始执行组件分支 @@ -25,7 +29,9 @@ public interface ExecutionListener { * @param ctx ctx 上下文 * @param object 组件/分支 */ - void beforeExecute(EngineContext ctx, Object object); + default void beforeExecute(EngineContext ctx, Object object) { + + } /** * 结束执行组件分支 @@ -34,7 +40,9 @@ public interface ExecutionListener { * @param object 组件/分支 * @param ex 执行错误信息 */ - void afterExecute(EngineContext ctx, Object object, Throwable ex); + default void afterExecute(EngineContext ctx, Object object, Throwable ex) { + + } /** * 开始回滚组件分支 @@ -42,7 +50,9 @@ public interface ExecutionListener { * @param ctx ctx 上下文 * @param object 组件/分支 */ - void beforeRollback(EngineContext ctx, Object object); + default void beforeRollback(EngineContext ctx, Object object) { + + } /** * 结束执行组件分支 @@ -50,5 +60,7 @@ public interface ExecutionListener { * @param ctx ctx 上下文 * @param object 组件/分支 */ - void afterRollback(EngineContext ctx, Object object); + default void afterRollback(EngineContext ctx, Object object) { + + } } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerRegistry.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerRegistry.java index 2e7b7521f02e05d9799e56b6d7b67969dd352ad9..a3d5847a4873c21760027ecf072554fa27bc0103 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerRegistry.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerRegistry.java @@ -16,7 +16,6 @@ public class ExecutionListenerRegistry { public synchronized static void register(ExecutionListener listener) { AssertUtil.notNull(listener, "listener must not be null"); - if (!REGISTERED.contains(listener)) { REGISTERED.add(listener); } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerSupport.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerSupport.java deleted file mode 100644 index a38617263fd1cddc0d2566dc8bf2eb75a4403b29..0000000000000000000000000000000000000000 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/ExecutionListenerSupport.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.smartboot.flow.core; - -/** - * @author qinluo - * @date 2022-11-25 21:29:22 - * @since 1.0.0 - */ -public class ExecutionListenerSupport implements ExecutionListener { - - @Override - public void start(EngineContext context) { - - } - - @Override - public void completed(EngineContext context) { - - } - - @Override - public void beforeExecute(EngineContext context, Object object) { - - } - - @Override - public void afterExecute(EngineContext context, Object object, Throwable ex) { - - } - - @Override - public void beforeRollback(EngineContext context, Object object) { - - } - - @Override - public void afterRollback(EngineContext context, Object object) { - - } -} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/Pipeline.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/Pipeline.java index 5902e044691024b4adf5bd00d13dc5721fac309d..cd7c443317d19472ac67c9822bd64fb153200cb1 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/Pipeline.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/Pipeline.java @@ -81,7 +81,7 @@ public class Pipeline implements Rollback, Describable, Validator, M try { WrappedInvoker.rollback(context, component); } catch (Exception e) { - LOGGER.error("{} rollback failed {}", this.name, component.describe()); + LOGGER.error("{} rollback failed {}", this.name, component.describe(), e); } } @@ -133,5 +133,8 @@ public class Pipeline implements Rollback, Describable, Validator, M for (Component component : components) { component.reset(); } + + // Reset after all components called. + resetCalled = false; } } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/attribute/AttributeValueResolver.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/attribute/AttributeValueResolver.java index a02fda0e07febfa1ae7df2965eb65d8a21d3f14b..2bb68d33168d7baaddd2ee42c23de0a946044552 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/attribute/AttributeValueResolver.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/attribute/AttributeValueResolver.java @@ -20,7 +20,6 @@ public class AttributeValueResolver { private ObjectCreator objectCreator = DefaultObjectCreator.getInstance(); private AttributeValueResolver() { - } public AttributeValueResolver(ObjectCreator objectCreator) { diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/builder/EngineBuilder.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/builder/EngineBuilder.java index d54e1c0acda8926ba5608f7d56d1cbd5e2061e3e..0887ffa7753b1677000ea4e082d1af234006f04e 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/builder/EngineBuilder.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/builder/EngineBuilder.java @@ -3,6 +3,7 @@ package org.smartboot.flow.core.builder; import org.smartboot.flow.core.FlowEngine; import org.smartboot.flow.core.Pipeline; +import org.smartboot.flow.core.exception.ExceptionHandler; import org.smartboot.flow.core.util.AssertUtil; import java.util.concurrent.ExecutorService; @@ -17,6 +18,7 @@ public class EngineBuilder { private Pipeline pipeline; private String name; private ExecutorService executor; + private ExceptionHandler handler; public EngineBuilder(String name) { this.name = name; @@ -29,17 +31,23 @@ public class EngineBuilder { } public EngineBuilder name(String name) { - AssertUtil.notBlank(name, "engine's name is required"); + AssertUtil.notBlank(name, "name is required"); this.name = name; return this; } public EngineBuilder executor(ExecutorService executor) { - AssertUtil.notNull(executor, "must not be null"); + AssertUtil.notNull(executor, "executor must not be null"); this.executor = executor; return this; } + public EngineBuilder handler(ExceptionHandler handler) { + AssertUtil.notNull(handler, "handler must not be null"); + this.handler = handler; + return this; + } + public FlowEngine build() { AssertUtil.notBlank(name, "engine's name is required"); @@ -48,6 +56,11 @@ public class EngineBuilder { engine.setName(name); engine.setPipeline(pipeline); engine.setExecutor(executor); + + if (handler != null) { + engine.setExceptionHandler(handler); + } + return engine; } } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/component/AdapterComponent.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/component/AdapterComponent.java index 7e7101f3a3897520e29334bc56ec3da2163acc4d..f1f5c2f688081abdcfee3d9ba79de9966196944b 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/component/AdapterComponent.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/component/AdapterComponent.java @@ -87,6 +87,8 @@ public class AdapterComponent extends Component { @Override public void accept(ComponentVisitor visitor) { visitor.visitAttributes(attributes); + // Ignored executable visitor. + visitor.visitExecutable(this.adapter.describe()); visitor.visitSource(this); ComponentVisitor componentVisitor = visitor.visitComponent(component.getType(), component.getName(), component.describe()); if (componentVisitor != null) { diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/AdapterElementParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/AdapterElementParser.java index a8756b390e24423d0265ce4133f5f687e636f46b..2bd868792a144d06161ab2d049193ef77c39e022 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/AdapterElementParser.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/AdapterElementParser.java @@ -32,6 +32,8 @@ public class AdapterElementParser extends AbstractElementParser{ definition.setIdentifier(identifier); definition.getAttributes().addAll(ElementUtils.extraAttributes(element)); + AssertUtil.notBlank(definition.getExecute(), "attribute [execute] cannot be null"); + ElementDefinition def = parseSubElements(element, context); definition.setPipelineElement(def); context.register(definition); diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/BuilderDefinitionVisitor.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/BuilderDefinitionVisitor.java index 7049ef10db2d9550f8082eb715b958db405c7b9d..b73ee4b470db5b3d0be23c2e5b0a05209323fc80 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/BuilderDefinitionVisitor.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/BuilderDefinitionVisitor.java @@ -15,6 +15,7 @@ import org.smartboot.flow.core.component.AdapterComponent; import org.smartboot.flow.core.component.ChooseComponent; import org.smartboot.flow.core.component.Component; import org.smartboot.flow.core.component.PipelineComponent; +import org.smartboot.flow.core.exception.ExceptionHandler; import org.smartboot.flow.core.executable.Executable; import org.smartboot.flow.core.parser.definition.AdapterDefinition; import org.smartboot.flow.core.parser.definition.ChooseDefinition; @@ -25,6 +26,8 @@ import org.smartboot.flow.core.parser.definition.PipelineComponentDefinition; import org.smartboot.flow.core.parser.definition.PipelineDefinition; import org.smartboot.flow.core.parser.definition.ScriptDefinition; import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.script.ScriptExecutable; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AssertUtil; import org.smartboot.flow.core.util.AuxiliaryUtils; @@ -46,7 +49,7 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { private final Map> namedPipelines = new ConcurrentHashMap<>(); private final Map> namedEngines = new ConcurrentHashMap<>(); private final Map> callbacks = new ConcurrentHashMap<>(); - private final Map scriptConditions = new ConcurrentHashMap<>(); + private final Map scriptExecutors = new ConcurrentHashMap<>(); private final ObjectCreator objectCreator; private final boolean useCache; private final AttributeValueResolver valueResolver; @@ -62,16 +65,16 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { if (ed instanceof ScriptDefinition) { ScriptDefinition sed = (ScriptDefinition) ed; Class javaType = sed.getJavaType(); - ScriptCondition condition; + ScriptExecutor scriptExecutor; if (javaType != null) { - condition = objectCreator.create(javaType.getName(), ScriptCondition.class, true); + scriptExecutor = objectCreator.create(javaType.getName(), ScriptExecutor.class, false); } else { - condition = objectCreator.create(sed.getType(), ScriptCondition.class, true); + scriptExecutor = objectCreator.create(sed.getType(), ScriptExecutor.class, false); } - condition.setName(sed.getName()); - condition.setScript(sed.getScript()); - scriptConditions.put(ed.getIdentifier(), condition); + scriptExecutor.setName(sed.getName()); + scriptExecutor.setScript(sed.getScript()); + scriptExecutors.put(ed.getIdentifier(), scriptExecutor); } else { ed.visit(this); } @@ -115,6 +118,14 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { this.collect(ed.getPipeline(), (engineBuilder::pipeline)); } + if (ed.getThreadpools().size() > 0) { + engineBuilder.executor(ThreadPoolCreator.create(ed.getThreadpools())); + } + + if (AuxiliaryUtils.isNotBlank(ed.getExceptionHandler())) { + engineBuilder.handler(newInstance(ed.getExceptionHandler(), ExceptionHandler.class)); + } + this.namedEngines.put(engineName, engineBuilder); } @@ -158,7 +169,28 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { // resolve value type. builder.apply(p.getAttribute(), p.getValue()); }); - Component component = builder.newAdapter(newInstance(ed.getExecute(), Executable.class)); + + Executable executable; + if (AuxiliaryUtils.isType(ed.getExecute())) { + executable = newInstance(ed.getExecute(), Executable.class); + } else if (ed.getContext().getRegistered(ed.getExecute()) != null) { + executable = new ScriptExecutable(); + ScriptExecutor scriptExecutor = getInternalObject(ed.getExecute(), ed.getContext()); + AssertUtil.notNull(scriptExecutor, "script executor is null"); + ((ScriptExecutable)executable).setScriptExecutor(scriptExecutor); + + String rollback = getRollbackScriptName(ed.getExecute()); + if (ed.getContext().getRegistered(rollback) != null) { + scriptExecutor = getInternalObject(rollback, ed.getContext()); + AssertUtil.notNull(scriptExecutor, "script executor is null"); + ((ScriptExecutable)executable).setRollbackExecutor(scriptExecutor); + } + } else { + executable = newInstance(ed.getExecute(), Executable.class); + } + + AssertUtil.notNull(executable, "executable " + executable + " is null"); + Component component = builder.newAdapter(executable); namedComponents.put(ed.getIdentifier(), component); } @@ -173,7 +205,10 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { if (AuxiliaryUtils.isType(test)) { condition = newInstance(test, Condition.class); } else if (ed.getContext().getRegistered(test) != null) { - condition = getInternalObject(test, ed.getContext()); + ScriptExecutor scriptExecutor = getInternalObject(test, ed.getContext()); + AssertUtil.notNull(scriptExecutor, "script executor is null"); + condition = new ScriptCondition(); + ((ScriptCondition)condition).setScriptExecutor(scriptExecutor); } else { condition = newInstance(test, Condition.class); } @@ -199,11 +234,11 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { this.namedComponents.put(ed.getIdentifier(), build); } - public T getInternalObject(String test, ParserContext context) { + public ScriptExecutor getInternalObject(String test, ParserContext context) { ElementDefinition registered = context.getRegistered(test); AssertUtil.notNull(registered, "registered condition def[" + test + "] not found"); this.visit(registered); - return (T)scriptConditions.get(test); + return scriptExecutors.get(test); } @Override @@ -213,7 +248,10 @@ public class BuilderDefinitionVisitor implements DefinitionVisitor { if (AuxiliaryUtils.isType(test)) { condition = newInstance(test, Condition.class); } else if (ed.getContext().getRegistered(test) != null) { - condition = getInternalObject(test, ed.getContext()); + ScriptExecutor scriptExecutor = getInternalObject(test, ed.getContext()); + AssertUtil.notNull(scriptExecutor, "script executor is null"); + condition = new ScriptCondition(); + ((ScriptCondition)condition).setScriptExecutor(scriptExecutor); } else { condition = newInstance(test, Condition.class); } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ChooseElementParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ChooseElementParser.java index 5c4bb4adcf65a3416ff942544da3be79ea917bb8..bc6c21800be4d907ad7c9435503156e02c81c382 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ChooseElementParser.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ChooseElementParser.java @@ -64,6 +64,7 @@ public class ChooseElementParser extends AbstractElementParser{ String type = subElement.getAttribute(ParseConstants.EXECUTE); if (AuxiliaryUtils.isNotBlank(type)) { + currentDef.setContext(context); continue; } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefaultParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefaultParser.java index dbdfdf077aeda4171cff5256f5f3cdf5de8d80de..5f3c34cacc290a307363751fa86bc428a13ccd1b 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefaultParser.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefaultParser.java @@ -26,12 +26,18 @@ public class DefaultParser implements Parser { ALLOWED.add(ParseConstants.ENGINE); ALLOWED.add(ParseConstants.PIPELINE); ALLOWED.add(ParseConstants.SCRIPT); + ALLOWED.add(ParseConstants.SCRIPT_LOADER); } private BuilderDefinitionVisitor visitor; private final ParserContext context = new ParserContext(); private ObjectCreator objectCreator = DefaultObjectCreator.getInstance(); private boolean assemble = true; + private final ScriptLoader scriptLoader = new ScriptLoader(); + + public ScriptLoader scriptLoader() { + return this.scriptLoader; + } @Override public void parse(InputStream is, InputStream... streams) { @@ -67,6 +73,12 @@ public class DefaultParser implements Parser { useCache = useCache || Boolean.parseBoolean(root.getAttribute("useCache")); } + // Load script inside xml. + context.getScriptLoaders().forEach(p -> p.load(context)); + + // Load script outside xml. + scriptLoader.load(context); + if (assemble) { this.visitor = new BuilderDefinitionVisitor(useCache, objectCreator); context.getRegistered().forEach(ElementDefinition::validate); diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefinitionVisitor.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefinitionVisitor.java index 8f07dc245a9e5aabef814fff2fe65772af4fe00c..47ef8079a647fcd312bdb97c9e5e06859f9dd6b3 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefinitionVisitor.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/DefinitionVisitor.java @@ -55,4 +55,20 @@ public interface DefinitionVisitor { default void init(ParserContext ctx) { } + + /** + * Return rollback script name of name. + * + *

+ * initScript --> initScript-rollback. + * reduceStock --> reduceStock-rollback. + * + *

+ * + * @param name name + * @return rollback name + */ + default String getRollbackScriptName(String name) { + return name + "-rollback"; + } } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementAttr.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementAttr.java new file mode 100644 index 0000000000000000000000000000000000000000..15b14e3b14d41f6ccf8902ec6cce0d3f5ee143b2 --- /dev/null +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementAttr.java @@ -0,0 +1,33 @@ +package org.smartboot.flow.core.parser; + +import java.io.Serializable; + +/** + * @author qinluo + * @date 2023/3/19 13:52 + * @since 1.0.0 + */ +public class ElementAttr implements Serializable { + + private static final long serialVersionUID = 2105126904710511899L; + + private final String name; + private final String value; + + public ElementAttr(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + + public static ElementAttr of(String name, String value) { + return new ElementAttr(name, value); + } +} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementParserRegistry.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementParserRegistry.java index 250a95b000dd7a5b0fe8329a0b245168a0b4b2b9..5334ba38ec1b1b1e6a9149ee9e11a0a493c6800a 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementParserRegistry.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementParserRegistry.java @@ -21,6 +21,7 @@ public class ElementParserRegistry { this.register("engine", new EngineElementParser()); this.register("script", new ScriptElementParser()); this.register("adapter", new AdapterElementParser()); + this.register("script-loader", new ScriptLoaderParser()); } public static ElementParserRegistry getInstance() { diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementUtils.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementUtils.java index a778b336d6aa897f11bf2882bcfbc3e05198efdd..a70c14466f65821b01409a3e3c73214d00219d9e 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementUtils.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ElementUtils.java @@ -42,6 +42,33 @@ public final class ElementUtils { return holders; } + /** + * Extra prefix attributes + */ + public static List extraAttributes(Element element, String prefix) { + List holders = new ArrayList<>(); + NamedNodeMap attributes = element.getAttributes(); + for (int i = 0; i < attributes.getLength(); i++) { + Node item = attributes.item(i); + + if (!item.getNodeName().startsWith(prefix)) { + continue; + } + + // 跳过空字符串 + if (AuxiliaryUtils.isBlank(item.getNodeValue())) { + continue; + } + + String name = item.getNodeName().substring(prefix.length()); + holders.add(ElementAttr.of(name, item.getNodeValue())); + } + + return holders; + } + + + /** * Extra all elements. */ diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/EngineElementParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/EngineElementParser.java index 4c398deb74dd910570cac07b9c7f2f1bf595c9ea..d0f845b82b8596d23318a3d9accc37e636d1bda0 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/EngineElementParser.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/EngineElementParser.java @@ -31,9 +31,13 @@ public class EngineElementParser extends AbstractElementParser { definition.setName(name); definition.setPipeline(pipeline); - definition.getAttributes().addAll(ElementUtils.extraAttributes(element)); // name as identifier. definition.setIdentifier(name); + + // 提取threadpool开头的属性 + definition.getThreadpools().addAll(ElementUtils.extraAttributes(element, "threadpool.")); + definition.setExceptionHandler(element.getAttribute(ParseConstants.EXCEPTION_HANDLER)); + context.register(definition); } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/IfElementParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/IfElementParser.java index 7269f957152e3449805f580336aa1b93ef45b8ec..fb4c60c5c3c5838a4a699e377511f190fc81060e 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/IfElementParser.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/IfElementParser.java @@ -56,11 +56,13 @@ public class IfElementParser extends AbstractElementParser { ElementDefinition elseDefinition = new ElementDefinition(); ElementDefinition.build(elseDefinition, subElement); elseDefinition.setIdentifier(super.getIdentifier(subElement, context)); + elseDefinition.setContext(context); elseDef = elseDefinition; } else { ElementDefinition thenDefinition = new ElementDefinition(); ElementDefinition.build(thenDefinition, subElement); thenDefinition.setIdentifier(super.getIdentifier(subElement, context)); + thenDefinition.setContext(context); thenDef = thenDefinition; } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParseConstants.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParseConstants.java index 2689c8decb31ce9318cbef630852eaefa47ad253..8ed43999a2463614627a7c1535cd3eacf5d47082 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParseConstants.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParseConstants.java @@ -17,6 +17,7 @@ public interface ParseConstants { String COMPONENT = "component"; String ADAPTER = "adapter"; String SCRIPT = "script"; + String SCRIPT_LOADER = "script-loader"; /** * Attributes; @@ -31,4 +32,6 @@ public interface ParseConstants { String CASE = "case"; String SUBPROCESS = "subprocess"; + String EXCEPTION_HANDLER = "exceptionHandler"; + } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParserContext.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParserContext.java index 6dc159270c4d64195b07af2b947a753bf55a4309..06716095a13ac108fb679e32f358862bd3d5762f 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParserContext.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ParserContext.java @@ -39,6 +39,21 @@ public class ParserContext { private final Map generatedIdentifiers = new ConcurrentHashMap<>(); private IdentifierManager identifierManager = new DefaultIdentifierManager(); + /** + * Script loaders in xml. + * + * @since 1.0.8 + */ + private final List scriptLoaders = new ArrayList<>(); + + public List getScriptLoaders() { + return scriptLoaders; + } + + public void addScriptLoad(ScriptLoader loader) { + this.scriptLoaders.add(loader); + } + public IdentifierManager getIdentifierManager() { return identifierManager; } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoader.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..a6f96194c24f2d3b3d0f3c84bfa787d01d17164d --- /dev/null +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoader.java @@ -0,0 +1,205 @@ +package org.smartboot.flow.core.parser; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.smartboot.flow.core.parser.definition.ScriptDefinition; +import org.smartboot.flow.core.util.AuxiliaryUtils; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; + +/** + * @author qinluo + * @date 2023/3/11 21:53 + * @since 1.0.0 + */ +public class ScriptLoader { + + private static final Logger LOGGER = LoggerFactory.getLogger(ScriptLoader.class); + + /** + * Script locations + */ + private final Set locations = new HashSet<>(); + + /** + * Accept file extensions. + */ + private final Set acceptExtensions = new HashSet<>(); + + /** + * Exclude file extensions. + */ + private final Set excludeExtensions = new HashSet<>(); + + public ScriptLoader() { + this.exclude("xml", "properties"); + } + + public void locations(String ...fileLocations) { + if (fileLocations == null) { + return; + } + + for (String fileLocation : fileLocations) { + if (fileLocation == null) { + continue; + } + + File file = new File(fileLocation); + if (!file.exists()) { + file = null; + URL resource = this.getClass().getResource(fileLocation); + + if (resource == null && !fileLocation.startsWith("/")) { + resource = this.getClass().getResource("/" + fileLocation); + } + + if (resource != null) { + file = new File(resource.getPath()); + } + } + + if (file == null || !file.exists() || !file.canRead()) { + continue; + } + + locations.add(file); + } + } + + public void locations(File ...fileLocations) { + if (fileLocations == null) { + return; + } + + for (File file : fileLocations) { + if (file == null || !file.exists() || !file.canRead()) { + continue; + } + + locations.add(file); + } + } + + public void accept(String ...extensions) { + this.acceptExtensions.addAll(AuxiliaryUtils.asList(extensions)); + } + + public void exclude(String ...extensions) { + this.excludeExtensions.addAll(AuxiliaryUtils.asList(extensions)); + } + + /** + * Load additional script from specified locations. + * + * @param ctx ctx. + */ + public void load(ParserContext ctx) { + // foreach locations + Set visitedLocations = new HashSet<>(locations.size()); + for (File file : locations) { + if (file.isFile() && !accept(file)) { + continue; + } + + // Found duplicated file in locations. + if (!visitedLocations.add(file.getAbsolutePath())) { + LOGGER.info("duplicated location {}", file.getAbsolutePath()); + continue; + } + + if (file.isFile()) { + doReadAndRegister(file, ctx); + } else if (file.isDirectory()){ + doReadDirectory(file, ctx); + } + } + + this.clear(); + } + + private void doReadDirectory(File file, ParserContext ctx) { + File[] files = file.listFiles(); + if (files == null) { + return; + } + + for (File f : files) { + if (f.isFile() && !accept(f)) { + continue; + } + + if (f.isFile()) { + doReadAndRegister(f, ctx); + } else if (f.isDirectory()){ + doReadDirectory(f, ctx); + } + } + } + + private void doReadAndRegister(File file, ParserContext ctx) { + String type = getExtension(file); + String name = file.getName().substring(0, file.getName().lastIndexOf(".")); + + // Additional script has lowest priority. + if (ctx.getRegistered(name) != null) { + return; + } + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int n; + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + while ((n = bis.read(buffer, 0, buffer.length)) != -1) { + bos.write(buffer, 0, n); + } + + String content = new String(bos.toByteArray(), StandardCharsets.UTF_8); + ScriptDefinition def = new ScriptDefinition(); + def.setScript(content); + def.setName(name); + def.setType(type); + def.setIdentifier(name); + ctx.register(def); + } catch (Exception e) { + LOGGER.error("read file {} failed", file.getPath(), e); + } + + } + + private void clear() { + this.locations.clear(); + } + + private boolean accept(File file) { + String extension = getExtension(file); + if (AuxiliaryUtils.isBlank(extension)) { + return false; + } + + if (excludeExtensions.contains(extension)) { + return false; + } + + return acceptExtensions.isEmpty() || acceptExtensions.contains(extension); + } + + private String getExtension(File file) { + String name = file.getName(); + int index = name.lastIndexOf("."); + if (index == -1) { + return ""; + } + + return name.substring(index + 1); + } + +} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoaderParser.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoaderParser.java new file mode 100644 index 0000000000000000000000000000000000000000..4b9856683b4ffe8bf6be8d6c853f5daebc590093 --- /dev/null +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ScriptLoaderParser.java @@ -0,0 +1,31 @@ +package org.smartboot.flow.core.parser; + +import org.smartboot.flow.core.util.AssertUtil; +import org.smartboot.flow.core.util.AuxiliaryUtils; +import org.w3c.dom.Element; + +/** + * @author qinluo + * @date 2023/3/12 23:57 + * @since 1.0.0 + */ +public class ScriptLoaderParser extends AbstractElementParser { + + @Override + public String getElementName() { + return ParseConstants.SCRIPT_LOADER; + } + + @Override + public void doParse(Element element, ParserContext context) { + String locations = element.getAttribute("locations"); + AssertUtil.notBlank(locations, "script-loader locations must not be null!"); + + ScriptLoader loader = new ScriptLoader(); + loader.locations(AuxiliaryUtils.splitByComma(locations).toArray(new String[0])); + + loader.exclude(AuxiliaryUtils.splitByComma(element.getAttribute("exclude")).toArray(new String[0])); + loader.accept(AuxiliaryUtils.splitByComma(element.getAttribute("accept")).toArray(new String[0])); + context.addScriptLoad(loader); + } +} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ThreadPoolCreator.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ThreadPoolCreator.java new file mode 100644 index 0000000000000000000000000000000000000000..81f6f55891f607c2c3d9520e0f649e7b0f8337e5 --- /dev/null +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/ThreadPoolCreator.java @@ -0,0 +1,85 @@ +package org.smartboot.flow.core.parser; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.RejectedExecutionHandler; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author qinluo + * @date 2023/3/19 14:02 + * @since 1.0.0 + */ +public class ThreadPoolCreator { + + public static ThreadPoolExecutor create(List attrs) { + + ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>()); + + boolean prestartAllCoreThreads = false; + + for (ElementAttr attr : attrs) { + if (Objects.equals(attr.getName(), "corePoolSize")) { + executor.setCorePoolSize(Integer.parseInt(attr.getValue())); + } else if (Objects.equals(attr.getName(), "maximumPoolSize")) { + executor.setMaximumPoolSize(Integer.parseInt(attr.getValue())); + } else if (Objects.equals(attr.getName(), "keepAliveTime")) { + executor.setKeepAliveTime(Long.parseLong(attr.getValue()), TimeUnit.MILLISECONDS); + } else if (Objects.equals(attr.getName(), "handler")) { + executor.setRejectedExecutionHandler(getHandler(attr.getValue())); + } else if (Objects.equals(attr.getName(), "threadFactory")) { + executor.setThreadFactory(new NamedThreadFactory(attr.getValue())); + } else if (Objects.equals(attr.getName(), "prestartAllCoreThreads")) { + prestartAllCoreThreads = true; + } + } + + if (prestartAllCoreThreads) { + executor.prestartAllCoreThreads(); + } + + return executor; + } + + private static RejectedExecutionHandler getHandler(String value) { + if (Objects.equals(value, ThreadPoolExecutor.AbortPolicy.class.getSimpleName())) { + return new ThreadPoolExecutor.AbortPolicy(); + } else if (Objects.equals(value, ThreadPoolExecutor.CallerRunsPolicy.class.getSimpleName())) { + return new ThreadPoolExecutor.CallerRunsPolicy(); + } else if (Objects.equals(value, ThreadPoolExecutor.DiscardOldestPolicy.class.getSimpleName())) { + return new ThreadPoolExecutor.DiscardOldestPolicy(); + } else if (Objects.equals(value, ThreadPoolExecutor.DiscardPolicy.class.getSimpleName())) { + return new ThreadPoolExecutor.DiscardPolicy(); + } + + return new ThreadPoolExecutor.AbortPolicy(); + } + + private static class NamedThreadFactory implements ThreadFactory { + + private final String prefix; + private final AtomicInteger sequence = new AtomicInteger(0); + + NamedThreadFactory(String prefix) { + this.prefix = prefix; + } + + @Override + public Thread newThread(Runnable r) { + if (r instanceof Thread) { + ((Thread) r).setName(prefix + "-" + sequence.incrementAndGet()); + return (Thread) r; + } + + Thread t = new Thread(r); + t.setName(prefix + "-" + sequence.incrementAndGet()); + return t; + } + } +} diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/EngineDefinition.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/EngineDefinition.java index 2c25a1427c1258eed04fed56a21b13e742bbe547..0466c06e13e84de54161955703115bccf1b6cd0b 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/EngineDefinition.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/EngineDefinition.java @@ -2,8 +2,12 @@ package org.smartboot.flow.core.parser.definition; import org.smartboot.flow.core.FlowEngine; import org.smartboot.flow.core.parser.DefinitionVisitor; +import org.smartboot.flow.core.parser.ElementAttr; import org.smartboot.flow.core.util.AssertUtil; +import java.util.ArrayList; +import java.util.List; + /** * @author qinluo * @date 2022-11-16 12:35:02 @@ -16,6 +20,17 @@ public class EngineDefinition extends ElementDefinition { */ private String pipeline; + private final List threadpools = new ArrayList<>(); + private String exceptionHandler; + + public String getExceptionHandler() { + return exceptionHandler; + } + + public void setExceptionHandler(String exceptionHandler) { + this.exceptionHandler = exceptionHandler; + } + public String getPipeline() { return this.pipeline; } @@ -24,6 +39,10 @@ public class EngineDefinition extends ElementDefinition { this.pipeline = pipeline; } + public List getThreadpools() { + return threadpools; + } + @Override public void validate() { AssertUtil.notNull(name, "engine's name must not be null"); diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/ScriptDefinition.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/ScriptDefinition.java index 659fb28ab0455ce47729a7424c91597c43239290..d31bac27dd68bbadd59839b033ab264690e0fb38 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/ScriptDefinition.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/parser/definition/ScriptDefinition.java @@ -1,7 +1,8 @@ package org.smartboot.flow.core.parser.definition; -import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.parser.DefinitionVisitor; import org.smartboot.flow.core.script.ScriptDetector; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AssertUtil; import org.smartboot.flow.core.util.AuxiliaryUtils; @@ -29,8 +30,8 @@ public class ScriptDefinition extends ElementDefinition { } if (javaType != null) { - AssertUtil.isTrue(ScriptCondition.class.isAssignableFrom(javaType), "script type must be a subclass of ScriptCondition"); - AssertUtil.isTrue(ScriptCondition.class != javaType, "script type must be a subclass of ScriptCondition"); + AssertUtil.isTrue(ScriptExecutor.class.isAssignableFrom(javaType), "script type must be a subclass of ScriptExecutor"); + AssertUtil.isTrue(ScriptExecutor.class != javaType, "script type must be a subclass of ScriptExecutor"); } } @@ -48,6 +49,16 @@ public class ScriptDefinition extends ElementDefinition { return javaType; } + @Override + public Class resolveType() { + return getJavaType(); + } + + @Override + protected void visit0(DefinitionVisitor visitor) { + visitor.visit(this); + } + public String getType() { return type; } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptCondition.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptCondition.java index ff1b712cb02863f97ed26aa6c65fb75ab919263d..878e5458925b8c66edc0fc4f39cbc871ed79ac20 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptCondition.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptCondition.java @@ -3,35 +3,23 @@ package org.smartboot.flow.core.script; import org.smartboot.flow.core.EngineContext; import org.smartboot.flow.core.NamedCondition; -import java.util.Map; - /** * @author qinluo * @date 2022/11/28 19:41 * @since 1.0.0 */ -public abstract class ScriptCondition extends NamedCondition { +public class ScriptCondition extends NamedCondition { - /** - * 执行脚本 - */ - protected String script; + private ScriptExecutor scriptExecutor; - public String getScript() { - return script; + public ScriptExecutor getScriptExecutor() { + return scriptExecutor; } - public void setScript(String script) { - this.script = script; + public void setScriptExecutor(ScriptExecutor scriptExecutor) { + this.scriptExecutor = scriptExecutor; } - /** - * 获取脚本条件的类型 - * - * @return type string - */ - public abstract String getType(); - /** * Don't override this method. */ @@ -47,22 +35,12 @@ public abstract class ScriptCondition extends NamedCondition { * @return 执行结果 */ @Override - public abstract Object test(EngineContext context); - - /** - * 允许用户在脚本上下文中绑定自定义的变量,用于执行脚本。 - * 其中key为脚本中用到的变量名,内置变量名参考 {@link org.smartboot.flow.core.script.ScriptConstants} - * - * @since 1.0.5 - * @param context engine ctx. - * @return bound keys. - */ - protected Map bindCustomized(EngineContext context) { - return ScriptVariableManager.getRegistered(context.getEngineName()); + public Object test(EngineContext context) { + return scriptExecutor.execute(context); } @Override public String describe() { - return "script-" + getType() + "-" + super.describe(); + return scriptExecutor.describe(); } } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptDetector.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptDetector.java index 3f6901512ff71f3eb27dd7f19df41b411fd66430..1086df5e0d4e2e0e7fb83feb5790324684e4f126 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptDetector.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/script/ScriptDetector.java @@ -19,12 +19,12 @@ import java.util.concurrent.ConcurrentHashMap; public class ScriptDetector { /** - * The phrase for {@link org.smartboot.flow.core.script.ScriptCondition} location. + * The phrase for {@link org.smartboot.flow.core.script.ScriptExecutor} location. */ private static final String LOCATION = "META-INF/smart-flow-script"; /** - * The stored phrase for {@link org.smartboot.flow.core.script.ScriptCondition} + * The stored phrase for {@link org.smartboot.flow.core.script.ScriptExecutor} */ private final Map> javaTypes = new ConcurrentHashMap<>(); @@ -55,8 +55,8 @@ public class ScriptDetector { AssertUtil.notBlank(type, "script " + key + " type must not be blank"); Class javaType = AuxiliaryUtils.asClass(type); AssertUtil.notNull(javaType, "script " + key + " type must be a javaType"); - AssertUtil.isTrue(ScriptCondition.class.isAssignableFrom(javaType), "script " + key + " type must be a subclass of ScriptCondition"); - AssertUtil.isTrue(ScriptCondition.class != (javaType), "script " + key + " type must be a subclass of ScriptCondition"); + AssertUtil.isTrue(ScriptExecutor.class.isAssignableFrom(javaType), "script " + key + " type must be a subclass of ScriptExecutor"); + AssertUtil.isTrue(ScriptExecutor.class != (javaType), "script " + key + " type must be a subclass of ScriptExecutor"); javaTypes.put(key.toLowerCase(), javaType); } } @@ -74,8 +74,8 @@ public class ScriptDetector { public void register(String phrase, Class javaType) { AssertUtil.notBlank(phrase, "phrase must not blank"); AssertUtil.notNull(javaType, "type must be null"); - AssertUtil.isTrue(ScriptCondition.class.isAssignableFrom(javaType), "type must be a subclass of ScriptCondition"); - AssertUtil.isTrue(ScriptCondition.class != (javaType), "type must be a subclass of ScriptCondition"); + AssertUtil.isTrue(ScriptExecutor.class.isAssignableFrom(javaType), "type must be a subclass of ScriptExecutor"); + AssertUtil.isTrue(ScriptExecutor.class != (javaType), "type must be a subclass of ScriptExecutor"); javaTypes.put(phrase, javaType); } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/trace/Node.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/trace/Node.java index 031c837d20e872b028a8c3435b5020bc6b46252c..abd44cbe8a0e9efc500658d7f6db1c7ef15a490d 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/trace/Node.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/trace/Node.java @@ -1,7 +1,5 @@ package org.smartboot.flow.core.trace; -import org.smartboot.flow.core.EngineConstants; - import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -13,6 +11,8 @@ import java.util.List; */ public class Node { + private static final int TAB_SIZE = 4; + /** * Node message info. */ @@ -121,7 +121,7 @@ public class Node { return "|---"; } - if (prefix.length() == EngineConstants.TAB_SIZE) { + if (prefix.length() == TAB_SIZE) { return (hasNext ? "|" : " ") + " |" + (async ? "~~~" : "---"); } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/util/AuxiliaryUtils.java b/smart-flow-core/src/main/java/org/smartboot/flow/core/util/AuxiliaryUtils.java index 411dbed618416e3888779eb4ee4aed538adbdb9c..02973c4f6db3637d20f3d15be6538698e0bc9fa5 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/util/AuxiliaryUtils.java +++ b/smart-flow-core/src/main/java/org/smartboot/flow/core/util/AuxiliaryUtils.java @@ -1,5 +1,9 @@ package org.smartboot.flow.core.util; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * @author qinluo * @date 2022-11-20 11:32:23 @@ -24,12 +28,7 @@ public final class AuxiliaryUtils { } public static boolean isType(String typename) { - try { - Class.forName(typename); - return true; - } catch (Exception e) { - return false; - } + return asClass(typename) != null; } public static Class asClass(String typename) { @@ -49,4 +48,35 @@ public final class AuxiliaryUtils { public static boolean isAnonymous(String name) { return name != null && name.contains("anonymous"); } + + public static List asList(T ...args) { + List values = new ArrayList<>(0); + if (args == null || args.length == 0) { + return values; + } + + for (T arg : args) { + if (arg != null) { + values.add(arg); + } + } + + return values; + } + + public static List splitByComma(String value) { + if (value == null || value.trim().length() == 0) { + return Collections.emptyList(); + } + + List values = new ArrayList<>(); + String[] split = value.split(",+"); + for (String val : split) { + if (val.trim().length() != 0) { + values.add(val.trim()); + } + } + + return values; + } } diff --git a/smart-flow-core/src/main/resources/smart-flow-1.0.1.xsd b/smart-flow-core/src/main/resources/smart-flow-1.0.1.xsd index bf9a97bbbce6058adcc8d09c2e8734b5f8605f89..f4aba095b3456431be4729d79558f09ab89f4a3f 100644 --- a/smart-flow-core/src/main/resources/smart-flow-1.0.1.xsd +++ b/smart-flow-core/src/main/resources/smart-flow-1.0.1.xsd @@ -108,6 +108,7 @@ + @@ -115,6 +116,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -129,6 +156,7 @@ + diff --git a/smart-flow-helper/pom.xml b/smart-flow-helper/pom.xml index f341413907916d5394fe10765b2621690f87fb1c..fd6a9d483a833b90d10d561aff323e051dc521ca 100644 --- a/smart-flow-helper/pom.xml +++ b/smart-flow-helper/pom.xml @@ -5,7 +5,7 @@ smart-flow-parent org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeObjectCreator.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeObjectCreator.java index d367eeedf5a9301093e2a031996a288cbc032d95..8c7210c3d3bcd558e908f566cd94f8077a59d888 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeObjectCreator.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeObjectCreator.java @@ -6,7 +6,7 @@ import org.smartboot.flow.core.DegradeCallback; import org.smartboot.flow.core.executable.Executable; import org.smartboot.flow.core.parser.DefaultObjectCreator; import org.smartboot.flow.core.parser.ObjectCreator; -import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.script.ScriptExecutor; /** * Fake object creator, Return prepared fake object. @@ -26,8 +26,8 @@ public class FakeObjectCreator implements ObjectCreator { if (expectType == Condition.class) { return (T)new FakeCondition(type); - } else if (expectType == ScriptCondition.class) { - return (T)new FakeScriptCondition(type); + } else if (expectType == ScriptExecutor.class) { + return (T)new FakeScriptExecutor(type); } else if (expectType == Executable.class) { return (T)new FakeExecutable(type); } else if (expectType == Adapter.class) { diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptCondition.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptExecutor.java similarity index 75% rename from smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptCondition.java rename to smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptExecutor.java index b215f97982b43c31c12d223dae4e090aa62dabc2..e1e4fc30f46f65de587f3119afbcf0cc502d400c 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptCondition.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/mock/FakeScriptExecutor.java @@ -1,8 +1,8 @@ package org.smartboot.flow.helper.mock; import org.smartboot.flow.core.EngineContext; -import org.smartboot.flow.core.script.ScriptCondition; import org.smartboot.flow.core.script.ScriptDetector; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AuxiliaryUtils; /** @@ -12,11 +12,11 @@ import org.smartboot.flow.core.util.AuxiliaryUtils; * @date 2023/1/27 12:35 * @since 1.0.0 */ -public class FakeScriptCondition extends ScriptCondition { +public class FakeScriptExecutor extends ScriptExecutor { private final String type; - public FakeScriptCondition(String type) { + public FakeScriptExecutor(String type) { this.type = type; } @@ -31,7 +31,7 @@ public class FakeScriptCondition extends ScriptCondition { } @Override - public Object test(EngineContext context) { + public Object execute(EngineContext context) { // do-noting return null; } diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Context.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Context.java similarity index 97% rename from smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Context.java rename to smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Context.java index b7a13a1ad7489bb290cefe61d58ba37a728d4279..7ca0b6a10df207ade77373cb76024a4f7af87827 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Context.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Context.java @@ -1,4 +1,4 @@ -package org.smartboot.flow.core.useful; +package org.smartboot.flow.helper.useful; import org.smartboot.flow.core.Key; diff --git a/smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Mediator.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Mediator.java similarity index 96% rename from smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Mediator.java rename to smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Mediator.java index c886ed0e6056d9d5b0347e66cef57c5f661d9d0e..a105794ec04b3bb3ba83a43645077b86bf93b091 100644 --- a/smart-flow-core/src/main/java/org/smartboot/flow/core/useful/Mediator.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/useful/Mediator.java @@ -1,4 +1,4 @@ -package org.smartboot.flow.core.useful; +package org.smartboot.flow.helper.useful; import org.smartboot.flow.core.Key; diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/PlantumlComponent.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/PlantumlComponent.java index 248dd7cfcf6ad45b620d89c3d0ba5603c1447532..38ada00fda9baf0b6894e524c5ba51afb48e9371 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/PlantumlComponent.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/PlantumlComponent.java @@ -6,6 +6,7 @@ import org.smartboot.flow.core.attribute.AttributeHolder; import org.smartboot.flow.core.attribute.Attributes; import org.smartboot.flow.core.component.Component; import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AuxiliaryUtils; import org.smartboot.flow.core.visitor.ComponentVisitor; import org.smartboot.flow.core.visitor.ConditionVisitor; @@ -225,7 +226,8 @@ public class PlantumlComponent extends ComponentVisitor { public void visitSource(Condition condition) { if (condition instanceof ScriptCondition) { ScriptCondition sc = (ScriptCondition) condition; - PlantumlComponent.this.condition = sc.getName() + "-" + sc.getType(); + ScriptExecutor scriptExecutor = sc.getScriptExecutor(); + PlantumlComponent.this.condition = scriptExecutor.getName() + "-" + scriptExecutor.getType(); } } } diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/ScriptCollector.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/ScriptCollector.java index e291e9e986ad20ea16350266a914f7fda0c89d0b..f34770bed49a260d3493ec876b174da8072a376a 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/ScriptCollector.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/ScriptCollector.java @@ -15,16 +15,20 @@ import java.util.Map; public class ScriptCollector { private static final ThreadLocal HOLDER = new ThreadLocal<>(); + + /** + * script-name : script-content : script-type + */ private final Map> scripts = new HashMap<>(); public static void start() { HOLDER.set(new ScriptCollector()); } - public static void collect(String condition, String script, String name) { + public static void collect(String name, String script, String type) { ScriptCollector collector = HOLDER.get(); if (collector != null) { - collector.scripts.put(condition, Pair.of(name, script)); + collector.scripts.put(name, Pair.of(script, type)); } } diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlComponentVisitor.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlComponentVisitor.java index 9a5bce96f59538f27ab5473d112dc00048ea4bf1..34aa108f34411d0ccf1045dfc528495e7a7f0872 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlComponentVisitor.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlComponentVisitor.java @@ -4,7 +4,10 @@ import org.smartboot.flow.core.Condition; import org.smartboot.flow.core.attribute.AttributeHolder; import org.smartboot.flow.core.attribute.Attributes; import org.smartboot.flow.core.common.ComponentType; +import org.smartboot.flow.core.executable.Executable; import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.script.ScriptExecutable; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AuxiliaryUtils; import org.smartboot.flow.core.visitor.ComponentVisitor; import org.smartboot.flow.core.visitor.ConditionVisitor; @@ -28,12 +31,15 @@ public class XmlComponentVisitor extends ComponentVisitor { private String branch; private final List components = new ArrayList<>(); private String executable; + private final String name; private String script; private String scriptName; - private final String name; private String scriptType; + private String rollbackScript; + private String rollbackScriptName; + private String rollbackScriptType; - public XmlComponentVisitor(ComponentType type, String name, String describe) { + public XmlComponentVisitor(ComponentType type, String name, String ignoredDescribe) { this.type = type; this.name = name; } @@ -41,7 +47,7 @@ public class XmlComponentVisitor extends ComponentVisitor { @Override public ExecutableVisitor visitExecutable(String executable) { this.executable = executable; - return null; + return new XmlExecutableVisitor(); } @Override @@ -99,7 +105,11 @@ public class XmlComponentVisitor extends ComponentVisitor { } if (script != null) { - ScriptCollector.collect(scriptType, script, scriptName); + ScriptCollector.collect(scriptName, script, scriptType); + } + + if (rollbackScript != null) { + ScriptCollector.collect(rollbackScriptName, rollbackScript, rollbackScriptType); } if (type == ComponentType.BASIC) { @@ -190,10 +200,35 @@ public class XmlComponentVisitor extends ComponentVisitor { public void visitSource(Condition condition) { if (condition instanceof ScriptCondition) { ScriptCondition sc = (ScriptCondition) condition; - XmlComponentVisitor.this.scriptName = sc.getName(); - XmlComponentVisitor.this.condition = sc.getName(); - XmlComponentVisitor.this.scriptType = sc.getType(); - XmlComponentVisitor.this.script = sc.getScript(); + ScriptExecutor scriptExecutor = sc.getScriptExecutor(); + XmlComponentVisitor.this.scriptName = scriptExecutor.getName(); + XmlComponentVisitor.this.condition = scriptExecutor.getName(); + XmlComponentVisitor.this.scriptType = scriptExecutor.getType(); + XmlComponentVisitor.this.script = scriptExecutor.getScript(); + } + } + } + + private class XmlExecutableVisitor extends ExecutableVisitor { + + @Override + public void visitSource(Executable executable) { + if (executable instanceof ScriptExecutable) { + ScriptExecutable sc = (ScriptExecutable) executable; + ScriptExecutor scriptExecutor = sc.getScriptExecutor(); + XmlComponentVisitor.this.scriptName = scriptExecutor.getName(); + XmlComponentVisitor.this.scriptType = scriptExecutor.getType(); + XmlComponentVisitor.this.script = scriptExecutor.getScript(); + + // Ensure executable name is scriptExecutor's name. + XmlComponentVisitor.this.executable = scriptExecutor.getName(); + + ScriptExecutor rollbackExecutor = sc.getRollbackExecutor(); + if (rollbackExecutor != null) { + XmlComponentVisitor.this.rollbackScriptName = rollbackExecutor.getName(); + XmlComponentVisitor.this.rollbackScriptType = rollbackExecutor.getType(); + XmlComponentVisitor.this.rollbackScript = rollbackExecutor.getScript(); + } } } } diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlEngineVisitor.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlEngineVisitor.java index 30bc3053b6b658ccb6967e3094c9c8541f57cfb8..9aa646cec3e6c91279d29749b305ee65a18e9d64 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlEngineVisitor.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlEngineVisitor.java @@ -57,9 +57,9 @@ public class XmlEngineVisitor extends EngineVisitor { Map> scripts = ScriptCollector.end(); if (scripts != null && scripts.size() > 0) { - scripts.forEach((k, v) -> content.append("\n\t")); + scripts.forEach((k, v) -> content.append("\n\t")); } content.append("\n").append(END).append("\n"); diff --git a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlPipelineVisitor.java b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlPipelineVisitor.java index bfa55f3394a3d31fdd4fcd16c53cc77edb294e0f..3811c8caf22fb8360d70a4be08c6857dfd1bf176 100644 --- a/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlPipelineVisitor.java +++ b/smart-flow-helper/src/main/java/org/smartboot/flow/helper/view/XmlPipelineVisitor.java @@ -1,6 +1,5 @@ package org.smartboot.flow.helper.view; -import org.smartboot.flow.core.EngineConstants; import org.smartboot.flow.core.common.ComponentType; import org.smartboot.flow.core.util.AuxiliaryUtils; import org.smartboot.flow.core.visitor.ComponentVisitor; @@ -43,7 +42,7 @@ public class XmlPipelineVisitor extends PipelineVisitor { // for anonymous-pipeline boolean incrementTab = false; // - if (name != null && !name.contains(EngineConstants.ANONYMOUS_PREFIX)) { + if (name != null && !AuxiliaryUtils.isAnonymous(name)) { incrementTab = true; AuxiliaryUtils.appendTab(content, numbersOfTab); content.append("\n"); @@ -53,7 +52,7 @@ public class XmlPipelineVisitor extends PipelineVisitor { component.generate(content, incrementTab ? numbersOfTab + 1 : numbersOfTab); } - if (name != null && !name.contains(EngineConstants.ANONYMOUS_PREFIX)) { + if (name != null && !AuxiliaryUtils.isAnonymous(name)) { AuxiliaryUtils.appendTab(content, numbersOfTab); content.append("\n"); } diff --git a/smart-flow-manager/pom.xml b/smart-flow-manager/pom.xml index 172de30b99bd56de6ac87cf2b352596df1f97e3b..c331e021e843b3d94ddead94d58eb711da6e4cdd 100644 --- a/smart-flow-manager/pom.xml +++ b/smart-flow-manager/pom.xml @@ -5,7 +5,7 @@ smart-flow-parent org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/ManagerConfiguration.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/ManagerConfiguration.java index 4f5ec79f1bdfb03cf519ba6921e518f3bc9f1c6a..792810a33b365ce9586398641c8a89927848e410 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/ManagerConfiguration.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/ManagerConfiguration.java @@ -11,4 +11,10 @@ public class ManagerConfiguration { * 异常信息上报最大堆栈神对,默认10 */ public static int reportMaxStackDepth = 10; + + /** + * 采集Request或者result配置 + */ + public static boolean traceRequest = false; + public static boolean traceResult = false; } diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/metric/MetricExecutionListener.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/metric/MetricExecutionListener.java index 3a6e2753de3768ba9338752ff2594af4c8d4ec71..27b566e9ca3a05b3bcb8ded9a749edfa3a18a9f2 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/metric/MetricExecutionListener.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/metric/MetricExecutionListener.java @@ -2,7 +2,6 @@ package org.smartboot.flow.manager.metric; import org.smartboot.flow.core.EngineContext; import org.smartboot.flow.core.ExecutionListener; -import org.smartboot.flow.core.ExecutionListenerSupport; import org.smartboot.flow.core.Key; import org.smartboot.flow.core.Measurable; import org.smartboot.flow.core.metrics.Metrics; @@ -15,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; * @date 2022-11-25 21:23:28 * @since 1.0.0 */ -public class MetricExecutionListener extends ExecutionListenerSupport { +public class MetricExecutionListener implements ExecutionListener { private static final ExecutionListener INSTANCE = new MetricExecutionListener(); diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/ManagerExecutionListener.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/ManagerExecutionListener.java index b58339237701facfeccb400db26586784eb264cb..2c7e6a9d05641d6ad2d6efb0b700f7e03eae2c3c 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/ManagerExecutionListener.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/ManagerExecutionListener.java @@ -1,9 +1,10 @@ package org.smartboot.flow.manager.trace; import org.smartboot.flow.core.EngineContext; -import org.smartboot.flow.core.ExecutionListenerSupport; +import org.smartboot.flow.core.ExecutionListener; import org.smartboot.flow.core.Key; import org.smartboot.flow.core.component.Component; +import org.smartboot.flow.manager.ManagerConfiguration; /** * 由管理模块进行Listener的注册 @@ -13,22 +14,30 @@ import org.smartboot.flow.core.component.Component; * @since 1.0.7 */ @SuppressWarnings("rawtypes") -public class ManagerExecutionListener extends ExecutionListenerSupport { +public class ManagerExecutionListener implements ExecutionListener { /** * Invoke trace in engine invoking. */ private static final Key TRACES = Key.of("traces"); private final TraceReporter traceReporter; - private final TraceSampleStrategy sampleStrategy; + private TraceSampleStrategy sampleStrategy; ManagerExecutionListener(TraceReporter traceReporter, TraceSampleStrategy sampleStrategy) { this.traceReporter = traceReporter; this.sampleStrategy = sampleStrategy; } + public void setSampleStrategy(TraceSampleStrategy sampleStrategy) { + this.sampleStrategy = sampleStrategy; + } + @Override public void start(EngineContext context) { + if (sampleStrategy != null && !sampleStrategy.sampled(context)) { + return; + } + TraceIdGenerator generator = TraceIdGenerator.getTraceIdGenerator(); if (generator == null) { return; @@ -38,6 +47,11 @@ public class ManagerExecutionListener extends ExecutionListenerSupport { TraceData trace = new TraceData(); trace.setEngineName(context.getEngineName()); trace.setTraceId(generator.getTraceId(context)); + trace.setTraceTime(System.currentTimeMillis()); + + if (ManagerConfiguration.traceRequest) { + trace.setRequest(context.getReq()); + } // 暂时init个object context.putExt(TRACES, trace); @@ -128,9 +142,13 @@ public class ManagerExecutionListener extends ExecutionListenerSupport { } trace.setEx(context.getFatal()); - if (sampleStrategy == null || sampleStrategy.sampled(context)) { - // 将执行采集到的数据进行上报 - traceReporter.submit(trace); + trace.setEndTime(System.currentTimeMillis()); + + if (ManagerConfiguration.traceResult) { + trace.setResult(context.getReq()); } + + // 将执行采集到的数据进行上报 + traceReporter.submit(trace); } } diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceData.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceData.java index 505087ed7174cb2b607a61858c0c756cb0f4accc..27a98759220a262c98395819e3ad70960e41f4f9 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceData.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceData.java @@ -13,9 +13,13 @@ import java.util.concurrent.ConcurrentHashMap; @SuppressWarnings("rawtypes") public class TraceData { + private Object request; + private Object result; private String engineName; private String traceId; private Throwable ex; + private long traceTime; + private long endTime; private final Map components = new ConcurrentHashMap<>(); public String getEngineName() { @@ -53,4 +57,36 @@ public class TraceData { public ComponentData getData(Component comp) { return components.get(comp); } + + public Object getRequest() { + return request; + } + + public void setRequest(Object request) { + this.request = request; + } + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + + public long getTraceTime() { + return traceTime; + } + + public void setTraceTime(long traceTime) { + this.traceTime = traceTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } } diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReportRequest.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReportRequest.java index e2ab01e0d2736161727ea1fd0a12dcf9b3831d80..a935f4d51821515b13f4d7ddfaad8198fc2fdd3c 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReportRequest.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReportRequest.java @@ -20,6 +20,10 @@ public class TraceReportRequest implements Serializable { private Serializable json; private boolean success; private String ex; + private String request; + private String result; + private long traceTime; + private long endTime; public boolean getSuccess() { return success; @@ -100,4 +104,36 @@ public class TraceReportRequest implements Serializable { public void setTraceId(String traceId) { this.traceId = traceId; } + + public String getRequest() { + return request; + } + + public void setRequest(String request) { + this.request = request; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public long getTraceTime() { + return traceTime; + } + + public void setTraceTime(long traceTime) { + this.traceTime = traceTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } } diff --git a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReporter.java b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReporter.java index 5cc938a3bce688694b617608cb7b88dc03b2f156..54ce5b060583f7a517ee1eb34d053c7149f792a1 100644 --- a/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReporter.java +++ b/smart-flow-manager/src/main/java/org/smartboot/flow/manager/trace/TraceReporter.java @@ -62,6 +62,7 @@ public class TraceReporter { private int port; private Double radio; private TraceSampleStrategy sampleStrategy; + private ManagerExecutionListener executionListener; private Map headers; private final BlockingQueue traceQueue = new ArrayBlockingQueue<>(20000); @@ -101,9 +102,13 @@ public class TraceReporter { request.setTraceId(trace.getTraceId()); request.setEngineName(trace.getEngineName()); request.setSuccess(trace.getEx() == null); + request.setTraceTime(trace.getTraceTime()); + request.setEndTime(trace.getEndTime()); if (!request.getSuccess()) { request.setEx(serialExToString(trace.getEx())); } + request.setRequest(JSON.toJSONString(trace.getRequest())); + request.setResult(JSON.toJSONString(trace.getResult())); if (flatEngine.getReportContent()) { request.setContent(flatEngine.getContent()); @@ -137,8 +142,10 @@ public class TraceReporter { // Use body stream write. post.body().write(bytes, 0, bytes.length).done().onSuccess(httpResponse -> { + LOGGER.info("send trace success"); }) .onFailure(throwable -> { + LOGGER.error("send trace failed", throwable); }); } @@ -180,7 +187,8 @@ public class TraceReporter { sampleStrategy.setRadio(radio); } - ExecutionListenerRegistry.register(new ManagerExecutionListener(this, sampleStrategy)); + executionListener = new ManagerExecutionListener(this, sampleStrategy); + ExecutionListenerRegistry.register(executionListener); this.executorService.schedule(this::export, idle, TimeUnit.MILLISECONDS); UpdateContentTask.startTask(host, port); } @@ -220,6 +228,13 @@ public class TraceReporter { public void setRadio(Double radio) { this.radio = radio; + if (sampleStrategy == null && radio != null && radio > 0 && radio <= 1) { + sampleStrategy = new TraceSampleStrategy(); + sampleStrategy.setRadio(radio); + if (this.executionListener != null) { + this.executionListener.setSampleStrategy(this.sampleStrategy); + } + } } public TraceSampleStrategy getSampleStrategy() { @@ -228,5 +243,8 @@ public class TraceReporter { public void setSampleStrategy(TraceSampleStrategy sampleStrategy) { this.sampleStrategy = sampleStrategy; + if (this.executionListener != null) { + this.executionListener.setSampleStrategy(this.sampleStrategy); + } } } diff --git a/smart-flow-script-condition/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script b/smart-flow-script-condition/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script deleted file mode 100644 index a3d233455b668d439a1c0663168587c3f3b1fb21..0000000000000000000000000000000000000000 --- a/smart-flow-script-condition/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script +++ /dev/null @@ -1 +0,0 @@ -ognl=org.smartboot.flow.condition.extension.ognl.OgnlScriptCondition \ No newline at end of file diff --git a/smart-flow-script-condition/pom.xml b/smart-flow-script/pom.xml similarity index 92% rename from smart-flow-script-condition/pom.xml rename to smart-flow-script/pom.xml index 16c47f0c33c366f47da5cae9017418aff6304c2e..05c5e4533b7610f2aa2ee74d17540e78ef3c47cb 100644 --- a/smart-flow-script-condition/pom.xml +++ b/smart-flow-script/pom.xml @@ -5,7 +5,7 @@ smart-flow-parent org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 pom @@ -16,7 +16,7 @@ smart-flow-script-qlexpress - smart-flow-script-condition + smart-flow-script 8 diff --git a/smart-flow-script-condition/smart-flow-script-groovy/pom.xml b/smart-flow-script/smart-flow-script-groovy/pom.xml similarity index 91% rename from smart-flow-script-condition/smart-flow-script-groovy/pom.xml rename to smart-flow-script/smart-flow-script-groovy/pom.xml index 1bfa39484c065c77d826cda3fbc35794033ed504..1017a5d027053d11a2c26781f42bbaa023777c3c 100644 --- a/smart-flow-script-condition/smart-flow-script-groovy/pom.xml +++ b/smart-flow-script/smart-flow-script-groovy/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - smart-flow-script-condition + smart-flow-script org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptCondition.java b/smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptExecutor.java similarity index 89% rename from smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptCondition.java rename to smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptExecutor.java index 475b0b6bf2bebbe126af2d17f002eca5305658c4..cb4cccf3adbf068855624c19097606eff0fd64bf 100644 --- a/smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptCondition.java +++ b/smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/GroovyScriptExecutor.java @@ -4,8 +4,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.smartboot.flow.core.EngineContext; import org.smartboot.flow.core.exception.FlowException; -import org.smartboot.flow.core.script.ScriptCondition; import org.smartboot.flow.core.script.ScriptConstants; +import org.smartboot.flow.core.script.ScriptExecutor; import javax.script.Bindings; import javax.script.ScriptEngine; @@ -17,9 +17,9 @@ import java.util.Map; * @date 2022/11/29 21:01 * @since 1.0.0 */ -public class GroovyScriptCondition extends ScriptCondition { +public class GroovyScriptExecutor extends ScriptExecutor { - private static final Logger LOGGER = LoggerFactory.getLogger(GroovyScriptCondition.class); + private static final Logger LOGGER = LoggerFactory.getLogger(GroovyScriptExecutor.class); private static final ScriptEngineManager MANAGER = new ScriptEngineManager(); protected String getScriptLang() { @@ -27,7 +27,7 @@ public class GroovyScriptCondition extends ScriptCondition { } @Override - public Object test(EngineContext engineContext) { + public Object execute(EngineContext engineContext) { try { ScriptEngine engine = MANAGER.getEngineByName(getScriptLang()); Bindings data = engine.createBindings(); diff --git a/smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptCondition.java b/smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptExecutor.java similarity index 73% rename from smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptCondition.java rename to smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptExecutor.java index a21e89be6226f42086d7f26b9f5298feb86a789d..add780de56b66a78e5fe0879c606f8f8de4ffe47 100644 --- a/smart-flow-script-condition/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptCondition.java +++ b/smart-flow-script/smart-flow-script-groovy/src/main/java/org/smartboot/flow/condition/extension/groovy/JavaScriptExecutor.java @@ -5,7 +5,7 @@ package org.smartboot.flow.condition.extension.groovy; * @date 2022/11/29 21:01 * @since 1.0.0 */ -public class JavaScriptCondition extends GroovyScriptCondition { +public class JavaScriptExecutor extends GroovyScriptExecutor { @Override protected String getScriptLang() { diff --git a/smart-flow-script-condition/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script b/smart-flow-script/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script similarity index 58% rename from smart-flow-script-condition/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script rename to smart-flow-script/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script index f679dcb2a498326db0f2e0579a7092c6acac4971..d6e4f86e8a093ec565324ec43e20a2ebb4f6b90a 100644 --- a/smart-flow-script-condition/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script +++ b/smart-flow-script/smart-flow-script-groovy/src/main/resources/META-INF/smart-flow-script @@ -1,2 +1,3 @@ -groovy=org.smartboot.flow.condition.extension.groovy.GroovyScriptCondition -javascript=org.smartboot.flow.condition.extension.groovy.JavaScriptCondition \ No newline at end of file +groovy=org.smartboot.flow.condition.extension.groovy.GroovyScriptExecutor +javascript=org.smartboot.flow.condition.extension.groovy.JavaScriptExecutor +js=org.smartboot.flow.condition.extension.groovy.JavaScriptExecutor \ No newline at end of file diff --git a/smart-flow-script-condition/smart-flow-script-ognl/pom.xml b/smart-flow-script/smart-flow-script-ognl/pom.xml similarity index 90% rename from smart-flow-script-condition/smart-flow-script-ognl/pom.xml rename to smart-flow-script/smart-flow-script-ognl/pom.xml index 3dc13ca3a0d74d59435895f0be931d35350b6628..a835fcf80bccd8d2a54df766aaf99426bc9875f4 100644 --- a/smart-flow-script-condition/smart-flow-script-ognl/pom.xml +++ b/smart-flow-script/smart-flow-script-ognl/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - smart-flow-script-condition + smart-flow-script org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-script-condition/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptCondition.java b/smart-flow-script/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptExecutor.java similarity index 87% rename from smart-flow-script-condition/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptCondition.java rename to smart-flow-script/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptExecutor.java index 796434ad17b2514d4bcee0c838ee19f83def7234..e022195f4cc8998dafd0fe1baf4323ffda837370 100644 --- a/smart-flow-script-condition/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptCondition.java +++ b/smart-flow-script/smart-flow-script-ognl/src/main/java/org/smartboot/flow/condition/extension/ognl/OgnlScriptExecutor.java @@ -5,8 +5,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.smartboot.flow.core.EngineContext; import org.smartboot.flow.core.exception.FlowException; -import org.smartboot.flow.core.script.ScriptCondition; import org.smartboot.flow.core.script.ScriptConstants; +import org.smartboot.flow.core.script.ScriptExecutor; import java.util.HashMap; import java.util.Map; @@ -16,12 +16,12 @@ import java.util.Map; * @date 2022/11/29 21:01 * @since 1.0.0 */ -public class OgnlScriptCondition extends ScriptCondition { +public class OgnlScriptExecutor extends ScriptExecutor { - private static final Logger LOGGER = LoggerFactory.getLogger(OgnlScriptCondition.class); + private static final Logger LOGGER = LoggerFactory.getLogger(OgnlScriptExecutor.class); @Override - public Object test(EngineContext engineContext) { + public Object execute(EngineContext engineContext) { try { Map context = new HashMap<>(8); context.put(ScriptConstants.REQ, engineContext.getReq()); diff --git a/smart-flow-script/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script b/smart-flow-script/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script new file mode 100644 index 0000000000000000000000000000000000000000..03b2018578154dc443b122b53bbeeb260942d623 --- /dev/null +++ b/smart-flow-script/smart-flow-script-ognl/src/main/resources/META-INF/smart-flow-script @@ -0,0 +1 @@ +ognl=org.smartboot.flow.condition.extension.ognl.OgnlScriptExecutor \ No newline at end of file diff --git a/smart-flow-script-condition/smart-flow-script-qlexpress/pom.xml b/smart-flow-script/smart-flow-script-qlexpress/pom.xml similarity index 90% rename from smart-flow-script-condition/smart-flow-script-qlexpress/pom.xml rename to smart-flow-script/smart-flow-script-qlexpress/pom.xml index d1cc4b475f9c93b822d145fe14bb9c8bd4010a87..3e0657cab987ce9bd6695297d6d40850a6e6205a 100644 --- a/smart-flow-script-condition/smart-flow-script-qlexpress/pom.xml +++ b/smart-flow-script/smart-flow-script-qlexpress/pom.xml @@ -3,9 +3,9 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - smart-flow-script-condition + smart-flow-script org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-script-condition/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptCondition.java b/smart-flow-script/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptExecutor.java similarity index 87% rename from smart-flow-script-condition/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptCondition.java rename to smart-flow-script/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptExecutor.java index b74f17b9eb2d1e54e5756f4a3e70ff8652d5a28f..d1d52eb41bca1e9e5eece0f591df72de367bb46b 100644 --- a/smart-flow-script-condition/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptCondition.java +++ b/smart-flow-script/smart-flow-script-qlexpress/src/main/java/org/smartboot/flow/condition/extension/qlexpress/QlExpressScriptExecutor.java @@ -6,8 +6,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.smartboot.flow.core.EngineContext; import org.smartboot.flow.core.exception.FlowException; -import org.smartboot.flow.core.script.ScriptCondition; import org.smartboot.flow.core.script.ScriptConstants; +import org.smartboot.flow.core.script.ScriptExecutor; import java.util.Map; @@ -16,12 +16,12 @@ import java.util.Map; * @date 2022/11/29 21:01 * @since 1.0.0 */ -public class QlExpressScriptCondition extends ScriptCondition { +public class QlExpressScriptExecutor extends ScriptExecutor { - private static final Logger LOGGER = LoggerFactory.getLogger(QlExpressScriptCondition.class); + private static final Logger LOGGER = LoggerFactory.getLogger(QlExpressScriptExecutor.class); @Override - public Object test(EngineContext engineContext) { + public Object execute(EngineContext engineContext) { try { DefaultContext qlContext = new DefaultContext<>(); diff --git a/smart-flow-script-condition/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script b/smart-flow-script/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script similarity index 77% rename from smart-flow-script-condition/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script rename to smart-flow-script/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script index ec9ffd12e55d024fd2cb7c2127d5e680d70d8837..06819424c21a05c687eedb1562e02149b873b25c 100644 --- a/smart-flow-script-condition/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script +++ b/smart-flow-script/smart-flow-script-qlexpress/src/main/resources/META-INF/smart-flow-script @@ -1 +1 @@ -qlexpress=org.smartboot.flow.condition.extension.qlexpress.QlExpressScriptCondition \ No newline at end of file +qlexpress=org.smartboot.flow.condition.extension.qlexpress.QlExpressScriptExecutor \ No newline at end of file diff --git a/smart-flow-spring-extension/pom.xml b/smart-flow-spring-extension/pom.xml index 1c04dbb6231c26709d9385385821acf2467245c7..450141700a1d5dab77bd6eb139e627359e5021d1 100644 --- a/smart-flow-spring-extension/pom.xml +++ b/smart-flow-spring-extension/pom.xml @@ -5,7 +5,7 @@ smart-flow-parent org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0 diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionRegister.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionRegister.java index fa0b792560c3cff14a4525475da8c48f9b2a4ca8..8d6f6712d5c34ad59c3ef8feef7c86167acb5101 100644 --- a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionRegister.java +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionRegister.java @@ -40,4 +40,8 @@ public class BeanDefinitionRegister { registered.put(identifier, def); } } + + public boolean isSpringBean(String identifier) { + return registered.get(identifier) == null; + } } diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionVisitor.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionVisitor.java index 79f94cb4a907813a6b4039b6df76517d2e1e5d57..34eaca5d02e151a10099be07e9f92cbbb7f00333 100644 --- a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionVisitor.java +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/BeanDefinitionVisitor.java @@ -5,6 +5,7 @@ import org.smartboot.flow.core.attribute.AttributeValueResolver; import org.smartboot.flow.core.attribute.Attributes; import org.smartboot.flow.core.parser.DefinitionVisitor; import org.smartboot.flow.core.parser.ParserContext; +import org.smartboot.flow.core.parser.ThreadPoolCreator; import org.smartboot.flow.core.parser.definition.AdapterDefinition; import org.smartboot.flow.core.parser.definition.ChooseDefinition; import org.smartboot.flow.core.parser.definition.ElementDefinition; @@ -14,6 +15,8 @@ import org.smartboot.flow.core.parser.definition.PipelineComponentDefinition; import org.smartboot.flow.core.parser.definition.PipelineDefinition; import org.smartboot.flow.core.parser.definition.ScriptDefinition; import org.smartboot.flow.core.script.ScriptCondition; +import org.smartboot.flow.core.script.ScriptExecutable; +import org.smartboot.flow.core.script.ScriptExecutor; import org.smartboot.flow.core.util.AssertUtil; import org.smartboot.flow.core.util.AuxiliaryUtils; import org.springframework.beans.BeansException; @@ -73,10 +76,11 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar // Maybe a ref. if (javaType == null) { BeanDefinition beanDefinition = register.getBeanDefinition(sed.getName()); + AssertUtil.notNull(beanDefinition, "Could not found ScriptExecutor " + sed.getName() + " in spring container"); String beanClassName = beanDefinition.getBeanClassName(); Class defJavaType = AuxiliaryUtils.asClass(beanClassName); - AssertUtil.notNull(defJavaType, "bean " + sed.getName() + " javaType must be subclass of ScriptCondition"); - AssertUtil.isTrue(ScriptCondition.class.isAssignableFrom(defJavaType), "bean " + sed.getName() + " javaType must be subclass of ScriptCondition"); + AssertUtil.notNull(defJavaType, "bean " + sed.getName() + " javaType must be subclass of ScriptExecutor"); + AssertUtil.isTrue(ScriptExecutor.class.isAssignableFrom(defJavaType), "bean " + sed.getName() + " javaType must be subclass of ScriptExecutor"); // Register script content. beanDefinition.getPropertyValues().add("script", sed.getScript()); @@ -84,13 +88,9 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar if (AuxiliaryUtils.isNotBlank(sed.getName())) { beanDefinition.getPropertyValues().add("name", sed.getName()); } - } else { - RootBeanDefinition definition = new RootBeanDefinition(); - definition.setBeanClass(javaType); + RootBeanDefinition definition = asSpringDefinition(ed); PropertyValue script = new PropertyValue("script", sed.getScript()); - PropertyValue name = new PropertyValue("name", sed.getName()); - definition.getPropertyValues().addPropertyValue(name); definition.getPropertyValues().addPropertyValue(script); register.registerBeanDefinition(ed.getIdentifier(), definition, true); } @@ -102,25 +102,35 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar @Override public void visit(EngineDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); + RootBeanDefinition definition = asSpringDefinition(ed); PropertyValue pipeline = new PropertyValue("pipeline", new RuntimeBeanReference(ed.getPipeline())); - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); definition.getPropertyValues().addPropertyValue(pipeline); definition.setInitMethodName("validate"); + + if (ed.getThreadpools().size() > 0) { + definition.getPropertyValues().addPropertyValue("executor", ThreadPoolCreator.create(ed.getThreadpools())); + } + + if (AuxiliaryUtils.isNotBlank(ed.getExceptionHandler())) { + if (AuxiliaryUtils.isType(ed.getExceptionHandler())) { + RootBeanDefinition handlerDef = new RootBeanDefinition(); + handlerDef.setBeanClassName(ed.getExceptionHandler()); + definition.getPropertyValues().addPropertyValue("exceptionHandler", handlerDef); + } else { + // 可能是spring bean + definition.getPropertyValues().addPropertyValue("exceptionHandler", new RuntimeBeanReference(ed.getExceptionHandler())); + } + } + register.registerBeanDefinition(ed.getIdentifier(), definition, true); } @Override public void visit(PipelineDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); + RootBeanDefinition definition = asSpringDefinition(ed); ManagedList components = new ManagedList<>(); - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); definition.getPropertyValues().add("components", components); ed.getChildren().forEach(p -> p.visit(this)); @@ -134,19 +144,15 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar components.add(beanDefinition); } - register.registerBeanDefinition(ed.getIdentifier(), definition, !isAnonymous(ed.getIdentifier())); + register.registerBeanDefinition(ed.getIdentifier(), definition, !AuxiliaryUtils.isAnonymous(ed.getIdentifier())); } @Override public void visit(PipelineComponentDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); + RootBeanDefinition definition = asSpringDefinition(ed); PropertyValue pipeline = new PropertyValue("pipeline", new RuntimeBeanReference(ed.getPipeline())); - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); - - if (isAnonymous(ed.getPipeline())) { + if (AuxiliaryUtils.isAnonymous(ed.getPipeline())) { context.getRegistered(ed.getPipeline()).visit(this); definition.getPropertyValues().add("pipeline", register.getBeanDefinition(ed.getPipeline())); } else { @@ -157,10 +163,6 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar register.registerBeanDefinition(ed.getIdentifier(), definition); } - private boolean isAnonymous(String name) { - return name.contains("anonymous-pipeline"); - } - private void appendAttributes(ElementDefinition ed, RootBeanDefinition definition) { List attributes = ed.getAttributes(); AttributeValueResolver resolver = AttributeValueResolver.getInstance(); @@ -180,8 +182,6 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar } PropertyValue value = new PropertyValue(attribute.getName(), holder.getValue()); definition.getPropertyValues().addPropertyValue(value); - - } definition.getPropertyValues().add("attributes", ed.getAttributes()); @@ -189,19 +189,39 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar @Override public void visitBasic(ElementDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); + RootBeanDefinition definition = asSpringDefinition(ed); - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); + String execute = ed.getExecute(); - if (isType(ed.getExecute())) { + if (isType(execute)) { RootBeanDefinition conditionDef = new RootBeanDefinition(); - conditionDef.setBeanClassName(ed.getExecute()); + conditionDef.setBeanClassName(execute); definition.getPropertyValues().add("executable", conditionDef); + } else if (ed.getContext().getRegistered(execute) != null) { + ed.getContext().getRegistered(execute).visit(this); + BeanDefinition beanDefinition = register.getBeanDefinition(execute); + Class beanType = beanDefinition != null ? AuxiliaryUtils.asClass(beanDefinition.getBeanClassName()) : null; + if (beanType != null && ScriptExecutor.class.isAssignableFrom(beanType)) { + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setBeanClass(ScriptExecutable.class); + rbd.getPropertyValues().addPropertyValue("scriptExecutor", register.isSpringBean(execute) ? new RuntimeBeanReference(execute) : beanDefinition); + + String rollbackName = getRollbackScriptName(execute); + + if (ed.getContext().getRegistered(rollbackName) != null) { + ed.getContext().getRegistered(rollbackName).visit(this); + BeanDefinition rollbackRbd = register.getBeanDefinition(execute); + beanType = rollbackRbd != null ? AuxiliaryUtils.asClass(rollbackRbd.getBeanClassName()) : null; + if (beanType != null && ScriptExecutor.class.isAssignableFrom(beanType)) { + rbd.getPropertyValues().addPropertyValue("rollbackExecutor", register.isSpringBean(rollbackName) ? new RuntimeBeanReference(rollbackName) : rollbackRbd); + } + } + definition.getPropertyValues().add("executable", rbd); + } else { + definition.getPropertyValues().add("executable", new RuntimeBeanReference(execute)); + } } else { - AssertUtil.notBlank(ed.getExecute(), "component element ref must not be null!"); - definition.getPropertyValues().add("executable", new RuntimeBeanReference(ed.getExecute())); + definition.getPropertyValues().add("executable", new RuntimeBeanReference(execute)); } AttributeHolder degradeCallback = ed.getAttributes().stream() @@ -235,20 +255,9 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar @Override public void visit(IfElementDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); + RootBeanDefinition definition = asSpringDefinition(ed); - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); - - if (isType(ed.getTest())) { - RootBeanDefinition conditionDef = new RootBeanDefinition(); - conditionDef.setBeanClassName(ed.getTest()); - definition.getPropertyValues().add("condition", conditionDef); - } else { - AssertUtil.notBlank(ed.getTest(), "if element ref must not be null!"); - definition.getPropertyValues().add("condition", new RuntimeBeanReference(ed.getTest())); - } + processCondition(ed, definition); ed.getIfThenRef().visit(this); BeanDefinition beanDefinition = register.getBeanDefinition(ed.getIfThenRef().getIdentifier()); @@ -268,20 +277,10 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar @Override public void visit(ChooseDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); - - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); + RootBeanDefinition definition = asSpringDefinition(ed); definition.getPropertyValues().add("allBranchWasString", true); - if (isType(ed.getTest())) { - RootBeanDefinition conditionDef = new RootBeanDefinition(); - conditionDef.setBeanClassName(ed.getTest()); - definition.getPropertyValues().add("condition", conditionDef); - } else { - definition.getPropertyValues().add("condition", new RuntimeBeanReference(ed.getTest())); - } + processCondition(ed, definition); ManagedMap managedMap = new ManagedMap<>(); List chooseCaseList = ed.getChooseCaseList(); @@ -305,20 +304,39 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar register.registerBeanDefinition(ed.getIdentifier(), definition); } + private void processCondition(ElementDefinition ed, RootBeanDefinition definition) { + String test = ed.getTest(); + + if (isType(test)) { + RootBeanDefinition conditionDef = new RootBeanDefinition(); + conditionDef.setBeanClassName(test); + definition.getPropertyValues().add("condition", conditionDef); + } else if (ed.getContext().getRegistered(test) != null) { + ed.getContext().getRegistered(test).visit(this); + BeanDefinition beanDefinition = register.getBeanDefinition(test); + Class beanType = beanDefinition != null ? AuxiliaryUtils.asClass(beanDefinition.getBeanClassName()) : null; + if (beanType != null && ScriptExecutor.class.isAssignableFrom(beanType)) { + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setBeanClass(ScriptCondition.class); + rbd.getPropertyValues().addPropertyValue("scriptExecutor", register.isSpringBean(test) ? new RuntimeBeanReference(test) : beanDefinition); + definition.getPropertyValues().add("condition", rbd); + } else { + definition.getPropertyValues().add("condition", new RuntimeBeanReference(test)); + } + } else { + definition.getPropertyValues().add("condition", new RuntimeBeanReference(test)); + } + } + @Override public void visit(AdapterDefinition ed) { - RootBeanDefinition definition = new RootBeanDefinition(); - PropertyValue name = new PropertyValue("name", ed.getName()); - - definition.setBeanClass(ed.resolveType()); - definition.getPropertyValues().addPropertyValue(name); + RootBeanDefinition definition = asSpringDefinition(ed); if (isType(ed.getExecute())) { RootBeanDefinition adapterDef = new RootBeanDefinition(); adapterDef.setBeanClassName(ed.getExecute()); definition.getPropertyValues().add("adapter", adapterDef); } else { - AssertUtil.notNull(ed.getExecute(), "adapter[execute] must not be null"); definition.getPropertyValues().add("adapter", new RuntimeBeanReference(ed.getExecute())); } @@ -330,4 +348,12 @@ public class BeanDefinitionVisitor implements DefinitionVisitor, BeanFactoryAwar register.registerBeanDefinition(ed.getIdentifier(), definition); } + + private RootBeanDefinition asSpringDefinition(ElementDefinition ed) { + RootBeanDefinition definition = new RootBeanDefinition(); + PropertyValue name = new PropertyValue("name", ed.getName()); + definition.setBeanClass(ed.resolveType()); + definition.getPropertyValues().addPropertyValue(name); + return definition; + } } diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/ProxyParser.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/ProxyParser.java index 4e6d94eb00b7ffae63d7d2fc10c161d618243897..e83dc604c62211231b14b2645a0fc321a47bed05 100644 --- a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/ProxyParser.java +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/ProxyParser.java @@ -16,10 +16,25 @@ import org.w3c.dom.Element; */ public class ProxyParser implements BeanDefinitionParser { + private static final ProxyParser INSTANCE = new ProxyParser(); + + private org.smartboot.flow.core.parser.ParserContext context; + + public static ProxyParser getInstance() { + return INSTANCE; + } + + public org.smartboot.flow.core.parser.ParserContext getContext() { + return context; + } + @Override public BeanDefinition parse(Element element, ParserContext parserContext) { + if (context == null) { + context = new org.smartboot.flow.core.parser.ParserContext(); + } + SmartFlowRegistrar.registerAll(parserContext.getRegistry()); - org.smartboot.flow.core.parser.ParserContext context = new org.smartboot.flow.core.parser.ParserContext(); // Ensure identifier in spring scope is unique. context.setIdentifierManager(new SpringIdentifierManager(parserContext.getRegistry())); @@ -27,8 +42,10 @@ public class ProxyParser implements BeanDefinitionParser { AssertUtil.notNull(parser, "Could not find parse for element " + ElementUtils.getName(element)); parser.parseElement(element, context); - BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(parserContext.getRegistry(), context); - context.getRegistered().forEach(visitor::visit); return null; } + + public void reset() { + this.context = null; + } } diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowBeanFactoryRegistry.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowBeanFactoryRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..559dfd833e23ad51b4653a554f6fc996a5c8d643 --- /dev/null +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowBeanFactoryRegistry.java @@ -0,0 +1,38 @@ +package org.smartboot.flow.spring.extension; + +import org.smartboot.flow.core.parser.ParserContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; + +/** + * @author qinluo + * @date 2023/3/12 12:41 + * @since 1.0.0 + */ +public class SmartFlowBeanFactoryRegistry implements BeanDefinitionRegistryPostProcessor { + + private BeanDefinitionRegistry registry; + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + this.registry = registry; + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + try { + // Touch visit all parsed elements after all bean definition loaded. + ParserContext ctx = ProxyParser.getInstance().getContext(); + if (ctx != null) { + // Load script inside xml. + ctx.getScriptLoaders().forEach(p -> p.load(ctx)); + BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(registry, ctx); + ctx.getRegistered().forEach(visitor::visit); + } + } finally { + ProxyParser.getInstance().reset(); + } + } +} diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowRegistrar.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowRegistrar.java index cc3818e16ba4da25efdbaad42b7f91d218b875ff..abadd1f6603d45929d184a2b36f2e0b7cd42394b 100644 --- a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowRegistrar.java +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SmartFlowRegistrar.java @@ -13,8 +13,8 @@ import org.springframework.core.type.AnnotationMetadata; */ public class SmartFlowRegistrar implements ImportBeanDefinitionRegistrar { - private static volatile boolean registered = false; private static final String NOTIFIER_PROCESS = "smart-flow-notifer-processor"; + private static final String REGISTRY_NAME = "smart-flow-registry-processor"; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) { @@ -23,15 +23,24 @@ public class SmartFlowRegistrar implements ImportBeanDefinitionRegistrar { public static void registerAll(BeanDefinitionRegistry registry) { registerNotifier(registry); + registerRegistry(registry); } private static void registerNotifier(BeanDefinitionRegistry registry) { - if (registered) { + if (registry.containsBeanDefinition(NOTIFIER_PROCESS)) { return; } - registered = true; RootBeanDefinition definition = new RootBeanDefinition(); definition.setBeanClass(NotifierProcessor.class); registry.registerBeanDefinition(NOTIFIER_PROCESS, definition); } + + private static void registerRegistry(BeanDefinitionRegistry registry) { + if (registry.containsBeanDefinition(REGISTRY_NAME)) { + return; + } + RootBeanDefinition definition = new RootBeanDefinition(); + definition.setBeanClass(SmartFlowBeanFactoryRegistry.class); + registry.registerBeanDefinition(REGISTRY_NAME, definition); + } } diff --git a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SpringNamespaceHandler.java b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SpringNamespaceHandler.java index 621c1b35e7c12da0d82815222c4df298e228f509..e33379cecf94e9d49eb81030b50b8273415244a5 100644 --- a/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SpringNamespaceHandler.java +++ b/smart-flow-spring-extension/src/main/java/org/smartboot/flow/spring/extension/SpringNamespaceHandler.java @@ -11,9 +11,10 @@ public class SpringNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { - ProxyParser proxyParser = new ProxyParser(); + ProxyParser proxyParser = ProxyParser.getInstance(); this.registerBeanDefinitionParser("pipeline", proxyParser); this.registerBeanDefinitionParser("engine", proxyParser); this.registerBeanDefinitionParser("script", proxyParser); + this.registerBeanDefinitionParser("script-loader", proxyParser); } } diff --git a/smart-flow-springboot-starter/pom.xml b/smart-flow-springboot-starter/pom.xml index 6b0a46f828385cf8ead605aebcbb38cd69ea3f17..07f6a1397f2790a7e5417e3569f310738d6f1936 100644 --- a/smart-flow-springboot-starter/pom.xml +++ b/smart-flow-springboot-starter/pom.xml @@ -5,7 +5,7 @@ smart-flow-parent org.smartboot.flow - 1.0.7 + 1.0.8 4.0.0