diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java index fdbbb37568..1763bed7da 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java @@ -18,6 +18,8 @@ package org.thingsboard.server.service.cf.ctx.state; import lombok.Data; import net.objecthunter.exp4j.Expression; import net.objecthunter.exp4j.ExpressionBuilder; +import net.objecthunter.exp4j.function.Function; +import net.objecthunter.exp4j.function.Functions; import org.mvel2.MVEL; import org.thingsboard.script.api.tbel.TbelInvokeService; import org.thingsboard.server.common.data.AttributeScope; @@ -111,6 +113,7 @@ public class CalculatedFieldCtx { if (isValidExpression(expression)) { this.customExpression = ThreadLocal.withInitial(() -> new ExpressionBuilder(expression) + .functions(userDefinedFunctions) .implicitMultiplication(true) .variables(this.arguments.keySet()) .build() @@ -279,4 +282,50 @@ public class CalculatedFieldCtx { return "Failed to init CF state. State size exceeds limit of " + (maxStateSize / 1024) + "Kb!"; } + private static final List userDefinedFunctions = List.of( + new Function("ln") { + @Override + public double apply(double... args) { + return Math.log(args[0]); + } + }, + new Function("lg") { + @Override + public double apply(double... args) { + return Math.log10(args[0]); + } + }, + new Function("logab", 2) { + @Override + public double apply(double... args) { + return Math.log(args[1]) / Math.log(args[0]); + } + }, + + // Manually listing built-in functions to avoid inefficient equals-based lookup in Functions.getBuiltinFunction during each evaluation. + Functions.getBuiltinFunction("sin"), + Functions.getBuiltinFunction("cos"), + Functions.getBuiltinFunction("tan"), + Functions.getBuiltinFunction("cot"), + Functions.getBuiltinFunction("log"), + Functions.getBuiltinFunction("log2"), + Functions.getBuiltinFunction("log10"), + Functions.getBuiltinFunction("log1p"), + Functions.getBuiltinFunction("abs"), + Functions.getBuiltinFunction("acos"), + Functions.getBuiltinFunction("asin"), + Functions.getBuiltinFunction("atan"), + Functions.getBuiltinFunction("cbrt"), + Functions.getBuiltinFunction("floor"), + Functions.getBuiltinFunction("sinh"), + Functions.getBuiltinFunction("sqrt"), + Functions.getBuiltinFunction("tanh"), + Functions.getBuiltinFunction("cosh"), + Functions.getBuiltinFunction("ceil"), + Functions.getBuiltinFunction("pow"), + Functions.getBuiltinFunction("exp"), + Functions.getBuiltinFunction("expm1"), + Functions.getBuiltinFunction("signum") + ); + }