Update mvel2 dependency
This commit is contained in:
parent
830a612bf8
commit
4607d89369
@ -85,7 +85,7 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mvel</groupId>
|
||||
<groupId>org.thingsboard</groupId>
|
||||
<artifactId>mvel2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@ -22,15 +22,15 @@ import com.google.common.util.concurrent.MoreExecutors;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.mvel2.ExecutionContext;
|
||||
import org.mvel2.MVEL;
|
||||
import org.mvel2.ParserContext;
|
||||
import org.mvel2.optimizers.AccessorOptimizer;
|
||||
import org.mvel2.SandboxedParserContext;
|
||||
import org.mvel2.optimizers.OptimizerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.thingsboard.common.util.ThingsBoardExecutors;
|
||||
import org.thingsboard.script.api.AbstractScriptInvokeService;
|
||||
import org.thingsboard.script.api.ScriptType;
|
||||
@ -101,12 +101,9 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
super.init();
|
||||
Field field = ReflectionUtils.findField(OptimizerFactory.class, "accessorCompilers");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
Map<String, AccessorOptimizer> accessorCompilers = (Map<String, AccessorOptimizer>) field.get(null);
|
||||
accessorCompilers.put(OptimizerFactory.SAFE_REFLECTIVE, new TbReflectiveAccessorOptimizer());
|
||||
|
||||
parserContext = new ParserContext(new TbMvelParserConfiguration());
|
||||
OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE);
|
||||
parserContext = new SandboxedParserContext();
|
||||
parserContext.addImport("JSON", TbJson.class);
|
||||
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(2, "mvel-executor"));
|
||||
}
|
||||
|
||||
@ -159,7 +156,9 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
|
||||
throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException("Script not found!"));
|
||||
}
|
||||
try {
|
||||
return MVEL.executeExpression(script.getCompiledScript(), script.createVars(args));
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
// TODO:
|
||||
return MVEL.executeExpression(script.getCompiledScript(), executionContext, script.createVars(args));
|
||||
} catch (OutOfMemoryError e) {
|
||||
Runtime.getRuntime().gc();
|
||||
throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, script.getScriptBody(), new RuntimeException("Memory error!"));
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.mvel2.ExecutionContext;
|
||||
import org.mvel2.util.ArgsRepackUtil;
|
||||
import org.thingsboard.common.util.JacksonUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -28,13 +30,13 @@ public class TbJson {
|
||||
return value != null ? JacksonUtil.toString(value) : "null";
|
||||
}
|
||||
|
||||
public static Object parse(String value) throws IOException {
|
||||
public static Object parse(ExecutionContext ctx, String value) throws IOException {
|
||||
if (value != null) {
|
||||
JsonNode node = JacksonUtil.toJsonNode(value);
|
||||
if (node.isObject()) {
|
||||
return JacksonUtil.convertValue(node, Map.class);
|
||||
return ArgsRepackUtil.repack(ctx, JacksonUtil.convertValue(node, Map.class));
|
||||
} else if (node.isArray()) {
|
||||
return JacksonUtil.convertValue(node, List.class);
|
||||
return ArgsRepackUtil.repack(ctx, JacksonUtil.convertValue(node, List.class));
|
||||
} else if (node.isDouble()) {
|
||||
return node.doubleValue();
|
||||
} else if (node.isLong()) {
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import org.mvel2.compiler.Accessor;
|
||||
import org.mvel2.compiler.ExecutableAccessor;
|
||||
import org.mvel2.compiler.ExecutableStatement;
|
||||
import org.mvel2.integration.VariableResolverFactory;
|
||||
import org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TbMapCreator implements Accessor {
|
||||
private Accessor[] keys;
|
||||
private Accessor[] vals;
|
||||
private int size;
|
||||
|
||||
public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) {
|
||||
Map map = new HashMap<>(size * 2);
|
||||
for (int i = size - 1; i != -1; i--) {
|
||||
//noinspection unchecked
|
||||
map.put(getKey(i, ctx, elCtx, variableFactory), vals[i].getValue(ctx, elCtx, variableFactory));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private Object getKey(int index, Object ctx, Object elCtx, VariableResolverFactory variableFactory) {
|
||||
Accessor keyAccessor = keys[index];
|
||||
if (keyAccessor instanceof ExprValueAccessor) {
|
||||
ExecutableStatement executableStatement = ((ExprValueAccessor) keyAccessor).stmt;
|
||||
if (executableStatement instanceof ExecutableAccessor) {
|
||||
return ((ExecutableAccessor) executableStatement).getNode().getName();
|
||||
}
|
||||
}
|
||||
return keys[index].getValue(ctx, elCtx, variableFactory);
|
||||
}
|
||||
|
||||
public TbMapCreator(Accessor[] keys, Accessor[] vals) {
|
||||
this.size = (this.keys = keys).length;
|
||||
this.vals = vals;
|
||||
}
|
||||
|
||||
public Object setValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory, Object value) {
|
||||
// not implemented
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class getKnownEgressType() {
|
||||
return Map.class;
|
||||
}
|
||||
}
|
||||
@ -1,92 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import org.mvel2.compiler.AbstractParser;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class TbMvelClassLoader extends URLClassLoader {
|
||||
|
||||
private static final Set<String> allowedClasses = new HashSet<>();
|
||||
private static final Set<String> allowedPackages = new HashSet<>();
|
||||
|
||||
static {
|
||||
|
||||
AbstractParser.LITERALS.remove("System");
|
||||
AbstractParser.LITERALS.remove("Runtime");
|
||||
AbstractParser.LITERALS.remove("Class");
|
||||
AbstractParser.LITERALS.remove("ClassLoader");
|
||||
AbstractParser.LITERALS.remove("Thread");
|
||||
AbstractParser.LITERALS.remove("Compiler");
|
||||
AbstractParser.LITERALS.remove("ThreadLocal");
|
||||
AbstractParser.LITERALS.remove("SecurityManager");
|
||||
|
||||
AbstractParser.CLASS_LITERALS.remove("System");
|
||||
AbstractParser.CLASS_LITERALS.remove("Runtime");
|
||||
AbstractParser.CLASS_LITERALS.remove("Class");
|
||||
AbstractParser.CLASS_LITERALS.remove("ClassLoader");
|
||||
AbstractParser.CLASS_LITERALS.remove("Thread");
|
||||
AbstractParser.CLASS_LITERALS.remove("Compiler");
|
||||
AbstractParser.CLASS_LITERALS.remove("ThreadLocal");
|
||||
AbstractParser.CLASS_LITERALS.remove("SecurityManager");
|
||||
AbstractParser.CLASS_LITERALS.put("JSON", TbJson.class);
|
||||
AbstractParser.LITERALS.put("JSON", TbJson.class);
|
||||
|
||||
AbstractParser.CLASS_LITERALS.values().forEach(val -> allowedClasses.add(((Class) val).getName()));
|
||||
}
|
||||
|
||||
static {
|
||||
allowedPackages.add("org.mvel2");
|
||||
allowedPackages.add("java.util");
|
||||
}
|
||||
|
||||
public TbMvelClassLoader() {
|
||||
super(new URL[0], Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (!classNameAllowed(name)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (!classNameAllowed(name)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
private boolean classNameAllowed(String name) {
|
||||
if (allowedClasses.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
for (String pkgName : allowedPackages) {
|
||||
if (name.startsWith(pkgName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import org.mvel2.ParserConfiguration;
|
||||
import org.mvel2.integration.VariableResolverFactory;
|
||||
|
||||
public class TbMvelParserConfiguration extends ParserConfiguration {
|
||||
|
||||
private static final long serialVersionUID = 5558151976348875590L;
|
||||
|
||||
TbMvelParserConfiguration() {
|
||||
setClassLoader(new TbMvelClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableResolverFactory getVariableFactory(VariableResolverFactory factory) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new RuntimeException("Thread is interrupted!");
|
||||
}
|
||||
return new TbMvelResolverFactory(factory);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import org.mvel2.integration.VariableResolver;
|
||||
import org.mvel2.integration.VariableResolverFactory;
|
||||
import org.mvel2.integration.impl.StackResetResolverFactory;
|
||||
|
||||
public class TbMvelResolverFactory extends StackResetResolverFactory {
|
||||
|
||||
public TbMvelResolverFactory(VariableResolverFactory delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VariableResolver getVariableResolver(String name) {
|
||||
if (Thread.interrupted()) {
|
||||
throw new RuntimeException("Thread is interrupted!");
|
||||
}
|
||||
return super.getVariableResolver(name);
|
||||
}
|
||||
}
|
||||
@ -1,120 +0,0 @@
|
||||
/**
|
||||
* Copyright © 2016-2022 The Thingsboard Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import org.mvel2.ParserContext;
|
||||
import org.mvel2.compiler.Accessor;
|
||||
import org.mvel2.integration.VariableResolverFactory;
|
||||
import org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer;
|
||||
import org.mvel2.optimizers.impl.refl.collection.ArrayCreator;
|
||||
import org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor;
|
||||
import org.mvel2.optimizers.impl.refl.collection.ListCreator;
|
||||
import org.mvel2.optimizers.impl.refl.nodes.Union;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mvel2.util.CompilerTools.expectType;
|
||||
import static org.mvel2.util.ParseTools.findClass;
|
||||
import static org.mvel2.util.ParseTools.getBaseComponentType;
|
||||
import static org.mvel2.util.ParseTools.getSubComponentType;
|
||||
import static org.mvel2.util.ParseTools.repeatChar;
|
||||
|
||||
public class TbReflectiveAccessorOptimizer extends ReflectiveAccessorOptimizer {
|
||||
private Object ctx;
|
||||
private Class returnType;
|
||||
private VariableResolverFactory variableFactory;
|
||||
|
||||
@Override
|
||||
public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset,
|
||||
Object ctx, Object thisRef, VariableResolverFactory factory) {
|
||||
this.start = this.cursor = start;
|
||||
this.length = start + offset;
|
||||
this.returnType = type;
|
||||
this.ctx = ctx;
|
||||
this.variableFactory = factory;
|
||||
this.pCtx = pCtx;
|
||||
|
||||
Accessor root = _getAccessor(o, returnType);
|
||||
|
||||
if (property != null && length > start) {
|
||||
return new Union(pCtx, root, property, cursor, offset);
|
||||
} else {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
private Accessor _getAccessor(Object o, Class type) {
|
||||
if (o instanceof List) {
|
||||
Accessor[] a = new Accessor[((List) o).size()];
|
||||
int i = 0;
|
||||
|
||||
for (Object item : (List) o) {
|
||||
a[i++] = _getAccessor(item, type);
|
||||
}
|
||||
|
||||
returnType = List.class;
|
||||
|
||||
return new ListCreator(a);
|
||||
} else if (o instanceof Map) {
|
||||
Accessor[] k = new Accessor[((Map) o).size()];
|
||||
Accessor[] v = new Accessor[k.length];
|
||||
int i = 0;
|
||||
|
||||
for (Object item : ((Map) o).keySet()) {
|
||||
k[i] = _getAccessor(item, type); // key
|
||||
v[i++] = _getAccessor(((Map) o).get(item), type); // value
|
||||
}
|
||||
|
||||
returnType = Map.class;
|
||||
|
||||
return new TbMapCreator(k, v);
|
||||
} else if (o instanceof Object[]) {
|
||||
Accessor[] a = new Accessor[((Object[]) o).length];
|
||||
int i = 0;
|
||||
int dim = 0;
|
||||
|
||||
if (type != null) {
|
||||
String nm = type.getName();
|
||||
while (nm.charAt(dim) == '[') dim++;
|
||||
} else {
|
||||
type = Object[].class;
|
||||
dim = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
Class base = getBaseComponentType(type);
|
||||
Class cls = dim > 1 ? findClass(null, repeatChar('[', dim - 1) + "L" + base.getName() + ";", pCtx)
|
||||
: type;
|
||||
|
||||
for (Object item : (Object[]) o) {
|
||||
expectType(pCtx, a[i++] = _getAccessor(item, cls), base, true);
|
||||
}
|
||||
|
||||
return new ArrayCreator(a, getSubComponentType(type));
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("this error should never throw:" + getBaseComponentType(type).getName(), e);
|
||||
}
|
||||
} else {
|
||||
if (returnType == null) returnType = Object.class;
|
||||
if (type.isArray()) {
|
||||
return new ExprValueAccessor((String) o, type, ctx, variableFactory, pCtx);
|
||||
} else {
|
||||
return new ExprValueAccessor((String) o, Object.class, ctx, variableFactory, pCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
4
pom.xml
4
pom.xml
@ -77,7 +77,7 @@
|
||||
<zookeeper.version>3.5.5</zookeeper.version>
|
||||
<protobuf.version>3.17.2</protobuf.version>
|
||||
<grpc.version>1.42.1</grpc.version>
|
||||
<mvel.version>2.4.14.Final</mvel.version>
|
||||
<mvel.version>2.4.16TB</mvel.version>
|
||||
<lombok.version>1.18.18</lombok.version>
|
||||
<paho.client.version>1.2.4</paho.client.version>
|
||||
<netty.version>4.1.75.Final</netty.version>
|
||||
@ -1575,7 +1575,7 @@
|
||||
<version>${grpc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mvel</groupId>
|
||||
<groupId>org.thingsboard</groupId>
|
||||
<artifactId>mvel2</artifactId>
|
||||
<version>${mvel.version}</version>
|
||||
</dependency>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user