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;
 | 
					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.ListenableFuture;
 | 
				
			||||||
import com.google.common.util.concurrent.ListeningExecutorService;
 | 
					import com.google.common.util.concurrent.ListeningExecutorService;
 | 
				
			||||||
import com.google.common.util.concurrent.MoreExecutors;
 | 
					import com.google.common.util.concurrent.MoreExecutors;
 | 
				
			||||||
@ -111,12 +110,13 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
 | 
				
			|||||||
        OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE);
 | 
					        OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE);
 | 
				
			||||||
        parserConfig = new SandboxedParserConfiguration();
 | 
					        parserConfig = new SandboxedParserConfiguration();
 | 
				
			||||||
        parserConfig.addImport("JSON", TbJson.class);
 | 
					        parserConfig.addImport("JSON", TbJson.class);
 | 
				
			||||||
 | 
					        parserConfig.registerDataType("Date", TbDate.class, date -> 8L);
 | 
				
			||||||
        TbUtils.register(parserConfig);
 | 
					        TbUtils.register(parserConfig);
 | 
				
			||||||
        executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "mvel-executor"));
 | 
					        executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "mvel-executor"));
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // Special command to warm up MVEL engine
 | 
					            // Special command to warm up MVEL engine
 | 
				
			||||||
            Serializable script = MVEL.compileExpression("var warmUp = {}; warmUp", new SandboxedParserContext(parserConfig));
 | 
					            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) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
            // do nothing
 | 
					            // do nothing
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -146,11 +146,6 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected ListenableFuture<UUID> doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames) {
 | 
					    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(() -> {
 | 
					        return executor.submit(() -> {
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                Serializable compiledScript = MVEL.compileExpression(scriptBody, new SandboxedParserContext(parserConfig));
 | 
					                Serializable compiledScript = MVEL.compileExpression(scriptBody, new SandboxedParserContext(parserConfig));
 | 
				
			||||||
@ -165,7 +160,7 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected MvelScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args) {
 | 
					    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(() -> {
 | 
					        return new MvelScriptExecutionTask(executionContext, executor.submit(() -> {
 | 
				
			||||||
            MvelScript script = scriptMap.get(scriptId);
 | 
					            MvelScript script = scriptMap.get(scriptId);
 | 
				
			||||||
            if (script == null) {
 | 
					            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)));
 | 
					                ExecutionContext.class, String.class)));
 | 
				
			||||||
        parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes",
 | 
					        parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes",
 | 
				
			||||||
                ExecutionContext.class, String.class, String.class)));
 | 
					                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) {
 | 
					    public static String btoa(String input) {
 | 
				
			||||||
@ -84,4 +96,72 @@ public class TbUtils {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return list;
 | 
					        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>
 | 
					        <zookeeper.version>3.5.5</zookeeper.version>
 | 
				
			||||||
        <protobuf.version>3.21.9</protobuf.version>
 | 
					        <protobuf.version>3.21.9</protobuf.version>
 | 
				
			||||||
        <grpc.version>1.42.1</grpc.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>
 | 
					        <lombok.version>1.18.18</lombok.version>
 | 
				
			||||||
        <paho.client.version>1.2.4</paho.client.version>
 | 
					        <paho.client.version>1.2.4</paho.client.version>
 | 
				
			||||||
        <netty.version>4.1.75.Final</netty.version>
 | 
					        <netty.version>4.1.75.Final</netty.version>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user