feat: support java15+
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
f8ba885b8c
commit
389bfd7137
17
pom.xml
17
pom.xml
@ -1,8 +1,9 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>pw.yumc</groupId>
|
||||
<artifactId>MiaoScript</artifactId>
|
||||
<version>0.11.2</version>
|
||||
<version>0.13.0</version>
|
||||
<developers>
|
||||
<developer>
|
||||
<id>502647092</id>
|
||||
@ -53,15 +54,17 @@
|
||||
<properties>
|
||||
<env.GIT_COMMIT>DEV</env.GIT_COMMIT>
|
||||
<update.changes>
|
||||
§621-06-19 §afeat: 兼容JDK16 反射异常;
|
||||
§621-05-15 §afeat: 兼容JDK15+ 自动下载Nashorn类库;
|
||||
§621-03-25 §afeat: 异步加载 polyfill 并且同步加载 @ccms/core;
|
||||
§621-03-25 §cfix: 修改 ployfill 为 polyfill;
|
||||
§621-03-25 §cfix: 修改 ployfill 为 polyfill
|
||||
</update.changes>
|
||||
<update.changelog>
|
||||
§620-12-22 §cfix: 增加 require 效验;
|
||||
§620-12-17 §afeat: JavaScriptTask 新增任务ID 并通过 ID 比较优先级;
|
||||
§620-12-16 §afeat: 新增 require 缓存 优化路径寻找速度;
|
||||
§620-12-15 §cfix: 修复 非主线程重载时发生的异常;
|
||||
§620-12-07 §cfix: 修复 Windows 环境 重载异常
|
||||
</update.changes>
|
||||
<update.changelog>
|
||||
§620-12-07 §cfix: 修复 Windows 环境 重载异常;
|
||||
§620-11-19 §afeat: 新增 JavaScriptTask 类;
|
||||
§620-11-11 §afeat: 新增 package 版本锁定逻辑;
|
||||
§620-09-21 §afeat: 完善 upgrade 逻辑;
|
||||
@ -184,7 +187,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.10</version>
|
||||
<version>1.18.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.kamranzafar</groupId>
|
||||
|
@ -1,25 +1,21 @@
|
||||
package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.*;
|
||||
import java.io.File;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import javax.script.SimpleBindings;
|
||||
|
||||
import lombok.val;
|
||||
|
||||
/**
|
||||
* 喵式脚本引擎
|
||||
*
|
||||
@ -27,8 +23,12 @@ import lombok.val;
|
||||
* @since 2016年8月29日 上午7:51:43
|
||||
*/
|
||||
public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
private static String MavenRepo = "https://maven.aliyun.com/repository/public";
|
||||
private static MiaoScriptEngine DEFAULT;
|
||||
private static ScriptEngineManager manager;
|
||||
private static final ScriptEngineManager manager;
|
||||
|
||||
private Object ucp;
|
||||
private MethodHandle addURLMethodHandle;
|
||||
private ScriptEngine engine;
|
||||
|
||||
static {
|
||||
@ -48,39 +48,108 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(final String engineType) {
|
||||
this(manager, engineType);
|
||||
this(manager, engineType, null);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager) {
|
||||
this(engineManager, "js");
|
||||
this(engineManager, "js", null);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType) {
|
||||
public MiaoScriptEngine(final String engineType, String engineRoot) {
|
||||
this(manager, engineType, engineRoot);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType, String engineRoot) {
|
||||
try {
|
||||
engine = engineManager.getEngineByName(engineType);
|
||||
} catch (final NullPointerException ignored) {
|
||||
}
|
||||
if (engine == null) {
|
||||
val dirs = System.getProperty("java.ext.dirs").split(File.pathSeparator);
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
try {
|
||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
// 设置方法的访问权限
|
||||
method.setAccessible(true);
|
||||
// 获取系统类加载器
|
||||
URL url = nashorn.toURI().toURL();
|
||||
method.invoke(Thread.currentThread().getContextClassLoader(), url);
|
||||
engineManager = new ScriptEngineManager();
|
||||
engine = engineManager.getEngineByName(engineType);
|
||||
} catch (NoSuchMethodException | MalformedURLException | IllegalAccessException | InvocationTargetException | NullPointerException ignored) {
|
||||
val extDirs = System.getProperty("java.ext.dirs");
|
||||
if (extDirs != null) {
|
||||
val dirs = extDirs.split(File.pathSeparator);
|
||||
for (String dir : dirs) {
|
||||
File nashorn = new File(dir, "nashorn.jar");
|
||||
if (nashorn.exists()) {
|
||||
this.loadJar(nashorn);
|
||||
this.createEngineByName(engineType);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (engineRoot != null) {
|
||||
this.loadLocalNashorn(engineRoot);
|
||||
}
|
||||
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
|
||||
}
|
||||
if (engine == null)
|
||||
throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
|
||||
}
|
||||
|
||||
private void initReflect() {
|
||||
try {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
|
||||
Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||
MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
|
||||
Field ucpField;
|
||||
try {
|
||||
ucpField = loader.getClass().getDeclaredField("ucp");
|
||||
} catch (NoSuchFieldException e) {
|
||||
ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
|
||||
}
|
||||
long offset = unsafe.objectFieldOffset(ucpField);
|
||||
ucp = unsafe.getObject(loader, offset);
|
||||
Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
|
||||
addURLMethodHandle = lookup.unreflect(method);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadLocalNashorn(String engineRoot) {
|
||||
initReflect();
|
||||
File libRootFile = new File(engineRoot, "lib");
|
||||
libRootFile.mkdirs();
|
||||
String libRoot = libRootFile.getCanonicalPath();
|
||||
downloadJar(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.2");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm", "9.1");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-commons", "9.1");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-tree", "9.1");
|
||||
downloadJar(libRoot, "org.ow2.asm", "asm-util", "9.1");
|
||||
this.createEngineByName("nashorn");
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void loadJar(File file) {
|
||||
addURLMethodHandle.invoke(ucp, file.toURI().toURL());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void downloadJar(String engineRoot, String groupId, String artifactId, String version) {
|
||||
File lib = new File(engineRoot, artifactId + ".jar");
|
||||
if (!lib.exists()) {
|
||||
Files.copy(new URL(MavenRepo +
|
||||
String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.jar",
|
||||
groupId.replace(".", "/"),
|
||||
artifactId,
|
||||
version)
|
||||
).openStream(),
|
||||
lib.toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
this.loadJar(lib);
|
||||
}
|
||||
|
||||
private void createEngineByName(String engineType) {
|
||||
try {
|
||||
engine = new ScriptEngineManager(Thread.currentThread().getContextClassLoader()).getEngineByName(engineType);
|
||||
} catch (NullPointerException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public ScriptEngine getEngine() {
|
||||
return this.engine;
|
||||
}
|
||||
|
||||
public static MiaoScriptEngine getDefault() {
|
||||
|
@ -2,14 +2,9 @@ package pw.yumc.MiaoScript;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA
|
||||
@ -31,14 +26,13 @@ public class ScriptEngine {
|
||||
this.base = new Base(instance);
|
||||
}
|
||||
|
||||
public MiaoScriptEngine createEngine() {
|
||||
public void createEngine() {
|
||||
synchronized (logger) {
|
||||
if (this.engine == null) {
|
||||
this.engine = new MiaoScriptEngine(new ScriptEngineManager(), "nashorn");
|
||||
this.engine = new MiaoScriptEngine("nashorn", root);
|
||||
this.engine.put("base", this.base);
|
||||
this.engine.put("ScriptEngineContextHolder", this);
|
||||
}
|
||||
return this.engine;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,14 +54,16 @@ public class ScriptEngine {
|
||||
|
||||
@SneakyThrows
|
||||
public void enableEngine() {
|
||||
engine.invokeFunction("start", future);
|
||||
if (this.engine != null) {
|
||||
engine.invokeFunction("enable", future);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void disableEngine() {
|
||||
synchronized (logger) {
|
||||
if (this.engine != null) {
|
||||
this.engine.invokeFunction("engineDisable");
|
||||
this.engine.invokeFunction("disable");
|
||||
this.engine = null;
|
||||
}
|
||||
}
|
||||
|
@ -3,77 +3,88 @@ var global = this;
|
||||
/**
|
||||
* Init MiaoScriptEngine Runtime
|
||||
*/
|
||||
/*global base */
|
||||
(function () {
|
||||
global.engineDisable = function () {
|
||||
global.engineDisableImpl && global.engineDisableImpl()
|
||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "old_node_modules"))) {
|
||||
logger.info('Found old_node_modules folder delete...')
|
||||
base.delete(java.nio.file.Paths.get(root, "old_node_modules"))
|
||||
}
|
||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "upgrade"))) {
|
||||
logger.info('Found upgrade file delete node_modules...')
|
||||
base.delete(java.nio.file.Paths.get(root, "node_modules"))
|
||||
base.delete(java.nio.file.Paths.get(root, "upgrade"))
|
||||
}
|
||||
}
|
||||
var Files = Java.type('java.nio.file.Files')
|
||||
var Paths = Java.type('java.nio.file.Paths')
|
||||
var System = Java.type('java.lang.System')
|
||||
var Thread = Java.type('java.lang.Thread')
|
||||
var FutureTask = Java.type('java.util.concurrent.FutureTask')
|
||||
|
||||
global.boot = function (root, logger) {
|
||||
global.scope = java.lang.System.getenv("MS_NODE_CORE_SCOPE") || "@ccms"
|
||||
global.log = logger
|
||||
global.scope = System.getenv("MS_NODE_CORE_SCOPE") || "@ccms"
|
||||
global.logger = logger
|
||||
// Development Env Detect
|
||||
global.root = root || "src/main/resources"
|
||||
checkDebug()
|
||||
checkUpgrade()
|
||||
return bootEngineThread(checkClassLoader())
|
||||
}
|
||||
|
||||
function bootEngineThread(loader) {
|
||||
logger.info("ScriptEngine: " + ScriptEngineContextHolder.getEngine().getEngine().class.name)
|
||||
var future = new FutureTask(function () {
|
||||
Thread.currentThread().contextClassLoader = loader
|
||||
load(System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger)
|
||||
})
|
||||
// Async Loading MiaoScript Engine
|
||||
new Thread(future, "MiaoScript thread").start()
|
||||
return future
|
||||
}
|
||||
|
||||
global.enable = function (future) {
|
||||
if (!future.isDone()) {
|
||||
logger.info("Waiting MiaoScript booted...")
|
||||
future.get()
|
||||
}
|
||||
logger.info("MiaoScript booted starting...")
|
||||
global.engineDisableImpl = require(System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core')).default || function () {
|
||||
logger.info('Error: abnormal Initialization MiaoScript Engine. Skip disable step...')
|
||||
}
|
||||
}
|
||||
|
||||
global.disable = function () {
|
||||
global.engineDisableImpl && global.engineDisableImpl()
|
||||
}
|
||||
|
||||
function checkDebug() {
|
||||
if (__FILE__.indexOf('!') === -1) {
|
||||
logger.info('Loading custom BIOS file ' + __FILE__)
|
||||
global.debug = true
|
||||
}
|
||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "debug"))) {
|
||||
if (Files.exists(Paths.get(root, "debug"))) {
|
||||
logger.info('Running in debug mode...')
|
||||
global.debug = true
|
||||
}
|
||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "level"))) {
|
||||
global.level = base.read(java.nio.file.Paths.get(root, "level"))
|
||||
if (Files.exists(Paths.get(root, "level"))) {
|
||||
global.level = base.read(Paths.get(root, "level"))
|
||||
logger.info('Set system level to [' + global.level + ']...')
|
||||
}
|
||||
if (java.nio.file.Files.exists(java.nio.file.Paths.get(root, "upgrade"))) {
|
||||
}
|
||||
|
||||
function checkUpgrade() {
|
||||
if (Files.exists(Paths.get(root, "upgrade"))) {
|
||||
logger.info('Found upgrade file starting upgrade...')
|
||||
base.move(java.nio.file.Paths.get(root, "node_modules"), java.nio.file.Paths.get(root, "old_node_modules"))
|
||||
base.delete(java.nio.file.Paths.get(root, "upgrade"))
|
||||
base.move(Paths.get(root, "node_modules"), Paths.get(root, "old_node_modules"))
|
||||
base.delete(Paths.get(root, "upgrade"))
|
||||
}
|
||||
new java.lang.Thread(function () {
|
||||
new Thread(function () {
|
||||
try {
|
||||
base.delete(java.nio.file.Paths.get(root, "old_node_modules"))
|
||||
base.delete(Paths.get(root, "old_node_modules"))
|
||||
} catch (ex) {
|
||||
}
|
||||
}, "MiaoScript node_modules clean thread").start()
|
||||
// Check Class Loader, Sometimes Server will can't found plugin.yml file
|
||||
var loader = checkClassLoader()
|
||||
var future = new java.util.concurrent.FutureTask(function () {
|
||||
java.lang.Thread.currentThread().contextClassLoader = loader
|
||||
load(java.lang.System.getenv("MS_NODE_CORE_POLYFILL") || 'classpath:core/polyfill.js')(root, logger)
|
||||
})
|
||||
// Async Loading MiaoScript Engine
|
||||
new java.lang.Thread(future, "MiaoScript thread").start()
|
||||
return future
|
||||
}
|
||||
|
||||
global.start = function (future) {
|
||||
if (!future.isDone()) {
|
||||
log.info("Waiting MiaoScript booted...")
|
||||
future.get()
|
||||
}
|
||||
log.info("MiaoScript booted starting...")
|
||||
global.engineDisableImpl = require(java.lang.System.getenv("MS_NODE_CORE_MODULE") || (global.scope + '/core')).default || function () {
|
||||
log.info('Error: abnormal Initialization MiaoScript Engine. Skip disable step...')
|
||||
}
|
||||
}
|
||||
|
||||
function checkClassLoader() {
|
||||
var classLoader = java.lang.Thread.currentThread().contextClassLoader
|
||||
// Check Class Loader, Sometimes Server will can't found plugin.yml file
|
||||
var classLoader = Thread.currentThread().contextClassLoader
|
||||
if (classLoader.getResource("bios.js") === null) {
|
||||
throw Error("Error class loader: " + classLoader.class.name + " Please contact the author MiaoWoo!")
|
||||
} else {
|
||||
log.info("Class loader compatible: " + classLoader.class.name)
|
||||
logger.info("Class loader compatible: " + classLoader.class.name)
|
||||
if (classLoader.parent) {
|
||||
log.info("Parent class loader: " + classLoader.parent.class.name)
|
||||
logger.info("Parent class loader: " + classLoader.parent.class.name)
|
||||
}
|
||||
}
|
||||
return classLoader
|
||||
|
@ -39,8 +39,6 @@
|
||||
var Files = Java.type('java.nio.file.Files')
|
||||
// @ts-ignore
|
||||
var StandardCopyOption = Java.type('java.nio.file.StandardCopyOption')
|
||||
// @ts-ignore
|
||||
var FileNotFoundException = Java.type('java.io.FileNotFoundException')
|
||||
|
||||
// @ts-ignore
|
||||
var TarInputStream = Java.type('org.kamranzafar.jtar.TarInputStream')
|
||||
@ -403,7 +401,7 @@
|
||||
return _require(download(name), path, optional)
|
||||
} catch (ex) {
|
||||
notFoundModules[name] = true
|
||||
throw new FileNotFoundException("Can't found module " + name + ' in directory ' + path + ' ERROR: ' + ex, ex)
|
||||
throw new Error("Can't found module " + name + ' in directory ' + path + ' ERROR: ' + ex)
|
||||
}
|
||||
}
|
||||
setCacheModule(file, optional)
|
||||
|
Loading…
Reference in New Issue
Block a user