Add new MVEL classes and util methods
This commit is contained in:
parent
cdd7eff00e
commit
ef82c00c49
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.thingsboard.script.api.mvel;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
@ -111,12 +110,13 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
|
||||
OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE);
|
||||
parserConfig = new SandboxedParserConfiguration();
|
||||
parserConfig.addImport("JSON", TbJson.class);
|
||||
parserConfig.registerDataType("Date", TbDate.class, date -> 8L);
|
||||
TbUtils.register(parserConfig);
|
||||
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "mvel-executor"));
|
||||
try {
|
||||
// Special command to warm up MVEL engine
|
||||
Serializable script = MVEL.compileExpression("var warmUp = {}; warmUp", new SandboxedParserContext(parserConfig));
|
||||
MVEL.executeTbExpression(script, new ExecutionContext(), Collections.emptyMap());
|
||||
MVEL.executeTbExpression(script, new ExecutionContext(parserConfig), Collections.emptyMap());
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
}
|
||||
@ -146,11 +146,6 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<UUID> doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames) {
|
||||
if (NEW_KEYWORD_PATTERN.matcher(scriptBody).matches()) {
|
||||
//TODO: output line number and char pos.
|
||||
return Futures.immediateFailedFuture(new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody,
|
||||
new IllegalArgumentException("Keyword 'new' is forbidden!")));
|
||||
}
|
||||
return executor.submit(() -> {
|
||||
try {
|
||||
Serializable compiledScript = MVEL.compileExpression(scriptBody, new SandboxedParserContext(parserConfig));
|
||||
@ -165,7 +160,7 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
|
||||
|
||||
@Override
|
||||
protected MvelScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args) {
|
||||
ExecutionContext executionContext = new ExecutionContext(maxMemoryLimitMb * 1024 * 1024);
|
||||
ExecutionContext executionContext = new ExecutionContext(this.parserConfig, maxMemoryLimitMb * 1024 * 1024);
|
||||
return new MvelScriptExecutionTask(executionContext, executor.submit(() -> {
|
||||
MvelScript script = scriptMap.get(scriptId);
|
||||
if (script == null) {
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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 java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class TbDate extends Date {
|
||||
|
||||
public TbDate() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TbDate(String s) {
|
||||
super(parse(s));
|
||||
}
|
||||
|
||||
public TbDate(long date) {
|
||||
super(date);
|
||||
}
|
||||
|
||||
public TbDate(int year, int month, int date) {
|
||||
this(year, month, date, 0, 0, 0);
|
||||
}
|
||||
|
||||
public TbDate(int year, int month, int date, int hrs, int min) {
|
||||
this(year, month, date, hrs, min, 0);
|
||||
}
|
||||
|
||||
public TbDate(int year, int month, int date,
|
||||
int hrs, int min, int second) {
|
||||
super(new GregorianCalendar(year, month, date, hrs, min, second).getTimeInMillis());
|
||||
}
|
||||
|
||||
public String toDateString() {
|
||||
DateFormat formatter = DateFormat.getDateInstance();
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
public String toTimeString() {
|
||||
DateFormat formatter = DateFormat.getTimeInstance(DateFormat.LONG);
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
public String toISOString() {
|
||||
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sssZ");
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
public String toLocaleString(String locale) {
|
||||
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.forLanguageTag(locale));
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
public String toLocaleString(String locale, String tz) {
|
||||
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.forLanguageTag(locale));
|
||||
formatter.setTimeZone(TimeZone.getTimeZone(tz));
|
||||
return formatter.format(this);
|
||||
}
|
||||
|
||||
public static long now() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public static long parse(String value) {
|
||||
try {
|
||||
return Date.parse(value);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static long UTC(int year, int month, int date,
|
||||
int hrs, int min, int sec) {
|
||||
return Date.UTC(year - 1900, month, date, hrs, min, sec);
|
||||
}
|
||||
|
||||
}
|
||||
@ -39,6 +39,18 @@ public class TbUtils {
|
||||
ExecutionContext.class, String.class)));
|
||||
parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes",
|
||||
ExecutionContext.class, String.class, String.class)));
|
||||
parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt",
|
||||
String.class)));
|
||||
parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt",
|
||||
String.class, int.class)));
|
||||
parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat",
|
||||
String.class)));
|
||||
parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble",
|
||||
String.class)));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Integer.class == int.class);
|
||||
}
|
||||
|
||||
public static String btoa(String input) {
|
||||
@ -84,4 +96,72 @@ public class TbUtils {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static Integer parseInt(String value) {
|
||||
if (value != null) {
|
||||
try {
|
||||
int radix = 10;
|
||||
if (isHexadecimal(value)) {
|
||||
radix = 16;
|
||||
}
|
||||
return Integer.parseInt(prepareNumberString(value), radix);
|
||||
} catch (NumberFormatException e) {
|
||||
Float f = parseFloat(value);
|
||||
if (f != null) {
|
||||
return f.intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Integer parseInt(String value, int radix) {
|
||||
if (value != null) {
|
||||
try {
|
||||
return Integer.parseInt(prepareNumberString(value), radix);
|
||||
} catch (NumberFormatException e) {
|
||||
Float f = parseFloat(value);
|
||||
if (f != null) {
|
||||
return f.intValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Float parseFloat(String value) {
|
||||
if (value != null) {
|
||||
try {
|
||||
return Float.parseFloat(prepareNumberString(value));
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Double parseDouble(String value) {
|
||||
if (value != null) {
|
||||
try {
|
||||
return Double.parseDouble(prepareNumberString(value));
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isHexadecimal(String value) {
|
||||
return value != null && (value.contains("0x") || value.contains("0X"));
|
||||
}
|
||||
|
||||
private static String prepareNumberString(String value) {
|
||||
if (value != null) {
|
||||
value = value.trim();
|
||||
if (isHexadecimal(value)) {
|
||||
value = value.replace("0x", "");
|
||||
value = value.replace("0X", "");
|
||||
}
|
||||
value = value.replace(",", ".");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
2
pom.xml
2
pom.xml
@ -77,7 +77,7 @@
|
||||
<zookeeper.version>3.5.5</zookeeper.version>
|
||||
<protobuf.version>3.21.9</protobuf.version>
|
||||
<grpc.version>1.42.1</grpc.version>
|
||||
<mvel.version>2.4.22TB</mvel.version>
|
||||
<mvel.version>2.4.23TB</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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user