mirror of
https://github.com/LamGC/Oracle-Sentry.git
synced 2025-04-29 22:27:34 +00:00
feat: 添加 ScriptComponentFactory 以允许通过该接口实例动态生成脚本组件.
通过 ScriptComponentFactory 接口, 可以根据脚本信息动态得构造一些特定于脚本的组件, 例如日志. 本次提交同时调整了 Groovy 脚本的初始化过程, 让 ScriptInfo 的初始化能够更先于脚本 Trigger 的运行.
This commit is contained in:
parent
c2aa02cae3
commit
2f225d27fe
@ -0,0 +1,22 @@
|
|||||||
|
package net.lamgc.oracle.sentry.script;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脚本组件工厂.
|
||||||
|
* @author LamGC
|
||||||
|
*/
|
||||||
|
public interface ScriptComponentFactory<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建并获取实例.
|
||||||
|
* @param info 脚本信息.
|
||||||
|
* @return 返回对象.
|
||||||
|
*/
|
||||||
|
T getInstance(ScriptInfo info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对象属性名.
|
||||||
|
* @return 返回建议的对象属性名, {@link ScriptLoader} 并不一定遵守.
|
||||||
|
*/
|
||||||
|
String getPropertyName();
|
||||||
|
|
||||||
|
}
|
@ -2,12 +2,15 @@ package net.lamgc.oracle.sentry.script.groovy;
|
|||||||
|
|
||||||
import groovy.lang.Closure;
|
import groovy.lang.Closure;
|
||||||
import groovy.lang.DelegatesTo;
|
import groovy.lang.DelegatesTo;
|
||||||
import net.lamgc.oracle.sentry.ComputeInstanceManager;
|
|
||||||
import net.lamgc.oracle.sentry.script.Script;
|
import net.lamgc.oracle.sentry.script.Script;
|
||||||
import net.lamgc.oracle.sentry.script.ScriptInfo;
|
import net.lamgc.oracle.sentry.script.ScriptInfo;
|
||||||
import net.lamgc.oracle.sentry.script.tools.http.ScriptHttpClient;
|
import net.lamgc.oracle.sentry.script.groovy.trigger.GroovyTrigger;
|
||||||
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
|
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Groovy DSL 脚本的父类.
|
* Groovy DSL 脚本的父类.
|
||||||
* @author LamGC
|
* @author LamGC
|
||||||
@ -16,11 +19,14 @@ import org.codehaus.groovy.runtime.DefaultGroovyMethods;
|
|||||||
public class GroovyDslDelegate implements Script {
|
public class GroovyDslDelegate implements Script {
|
||||||
|
|
||||||
private final GroovyScriptInfo scriptInfo = new GroovyScriptInfo();
|
private final GroovyScriptInfo scriptInfo = new GroovyScriptInfo();
|
||||||
|
private final GroovyScriptLoader scriptLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建一个 DSL Delegate, 并传入可操作对象.
|
* 构建一个 DSL Delegate, 并传入可操作对象.
|
||||||
|
* @param scriptLoader 该脚本所属的加载器.
|
||||||
*/
|
*/
|
||||||
public GroovyDslDelegate() {
|
public GroovyDslDelegate(GroovyScriptLoader scriptLoader) {
|
||||||
|
this.scriptLoader = scriptLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,7 +35,11 @@ public class GroovyDslDelegate implements Script {
|
|||||||
* @param closure 待执行闭包.
|
* @param closure 待执行闭包.
|
||||||
*/
|
*/
|
||||||
private void trigger(String triggerName, Closure<?> closure){
|
private void trigger(String triggerName, Closure<?> closure){
|
||||||
DefaultGroovyMethods.with(GroovyTriggerProvider.INSTANCE.getTriggerByName(triggerName), closure);
|
if (!scriptLoader.isInitialed(this)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GroovyTrigger trigger = GroovyTriggerProvider.INSTANCE.getTriggerByName(triggerName);
|
||||||
|
DefaultGroovyMethods.with(trigger, closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.lamgc.oracle.sentry.script.groovy;
|
package net.lamgc.oracle.sentry.script.groovy;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import groovy.lang.Binding;
|
import groovy.lang.Binding;
|
||||||
import groovy.lang.GroovyClassLoader;
|
import groovy.lang.GroovyClassLoader;
|
||||||
@ -8,6 +9,7 @@ import net.lamgc.oracle.sentry.script.Script;
|
|||||||
import net.lamgc.oracle.sentry.script.ScriptComponents;
|
import net.lamgc.oracle.sentry.script.ScriptComponents;
|
||||||
import net.lamgc.oracle.sentry.script.ScriptInfo;
|
import net.lamgc.oracle.sentry.script.ScriptInfo;
|
||||||
import net.lamgc.oracle.sentry.script.ScriptLoader;
|
import net.lamgc.oracle.sentry.script.ScriptLoader;
|
||||||
|
import net.lamgc.oracle.sentry.script.ScriptComponentFactory;
|
||||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -17,7 +19,9 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,8 +34,8 @@ public class GroovyScriptLoader implements ScriptLoader {
|
|||||||
private final static Logger log = LoggerFactory.getLogger(GroovyScriptLoader.class);
|
private final static Logger log = LoggerFactory.getLogger(GroovyScriptLoader.class);
|
||||||
|
|
||||||
private final GroovyClassLoader scriptClassLoader;
|
private final GroovyClassLoader scriptClassLoader;
|
||||||
|
|
||||||
private final Map<Script, ScriptInfo> scriptInfoMap = new ConcurrentHashMap<>();
|
private final Map<Script, ScriptInfo> scriptInfoMap = new ConcurrentHashMap<>();
|
||||||
|
private final Set<Script> initialedScript = new HashSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造一个新的脚本加载器.
|
* 构造一个新的脚本加载器.
|
||||||
@ -58,11 +62,17 @@ public class GroovyScriptLoader implements ScriptLoader {
|
|||||||
Constructor<? extends DelegatingScript> constructor =
|
Constructor<? extends DelegatingScript> constructor =
|
||||||
scriptClass.asSubclass(DelegatingScript.class).getConstructor();
|
scriptClass.asSubclass(DelegatingScript.class).getConstructor();
|
||||||
DelegatingScript newScriptObject = constructor.newInstance();
|
DelegatingScript newScriptObject = constructor.newInstance();
|
||||||
GroovyDslDelegate dslDelegate = new GroovyDslDelegate();
|
GroovyDslDelegate dslDelegate = new GroovyDslDelegate(this);
|
||||||
newScriptObject.setDelegate(dslDelegate);
|
newScriptObject.setDelegate(dslDelegate);
|
||||||
newScriptObject.setBinding(createBinding(context));
|
|
||||||
newScriptObject.run();
|
newScriptObject.run();
|
||||||
scriptInfoMap.put(dslDelegate, dslDelegate.getScriptInfo());
|
ScriptInfo scriptInfo = dslDelegate.getScriptInfo();
|
||||||
|
if (!checkScriptInfo(scriptInfo)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
initialedScript.add(dslDelegate);
|
||||||
|
newScriptObject.setBinding(createBinding(context, scriptInfo));
|
||||||
|
newScriptObject.run();
|
||||||
|
scriptInfoMap.put(dslDelegate, scriptInfo);
|
||||||
return dslDelegate;
|
return dslDelegate;
|
||||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
log.error("加载脚本时发生异常.(ScriptPath: {})\n{}", scriptFile.getAbsolutePath(), Throwables.getStackTraceAsString(e));
|
log.error("加载脚本时发生异常.(ScriptPath: {})\n{}", scriptFile.getAbsolutePath(), Throwables.getStackTraceAsString(e));
|
||||||
@ -75,18 +85,48 @@ public class GroovyScriptLoader implements ScriptLoader {
|
|||||||
return scriptInfoMap.get(script);
|
return scriptInfoMap.get(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Binding createBinding(ScriptComponents components) {
|
/**
|
||||||
|
* 检查脚本是否已经初始化完毕.
|
||||||
|
* @param script 脚本对象.
|
||||||
|
* @return 如果已初始化完毕, 返回 {@code true}.
|
||||||
|
*/
|
||||||
|
public boolean isInitialed(GroovyDslDelegate script) {
|
||||||
|
return initialedScript.contains(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Binding createBinding(ScriptComponents components, ScriptInfo info) {
|
||||||
Binding binding = new Binding();
|
Binding binding = new Binding();
|
||||||
for (Field field : components.getClass().getDeclaredFields()) {
|
for (Field field : components.getClass().getDeclaredFields()) {
|
||||||
try {
|
try {
|
||||||
String name = field.getName();
|
String name = field.getName();
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
Object o = field.get(components);
|
Object o = field.get(components);
|
||||||
|
if (o instanceof ScriptComponentFactory factory) {
|
||||||
|
binding.setProperty(factory.getPropertyName(), factory.getInstance(info));
|
||||||
|
} else {
|
||||||
binding.setProperty(name, o);
|
binding.setProperty(name, o);
|
||||||
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean checkScriptInfo(ScriptInfo info) {
|
||||||
|
if (Strings.isNullOrEmpty(info.getGroup())) {
|
||||||
|
log.warn("脚本信息缺少 {}, 跳过加载.", "Group");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Strings.isNullOrEmpty(info.getName())) {
|
||||||
|
log.warn("脚本信息缺少 {}, 跳过加载.", "Name");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Strings.isNullOrEmpty(info.getVersion())) {
|
||||||
|
log.warn("脚本信息缺少 {}, 跳过加载.", "Version");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user