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