From d7412edcebb4a2dd57893900f8b684c2df5425eb Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 12 Feb 2025 16:40:58 +0200 Subject: [PATCH] Refactoring of the arguments --- .../server/actors/ActorSystemContext.java | 5 +- .../service/cf/ctx/state/ArgumentEntry.java | 3 + .../RocksDBCalculatedFieldStateService.java | 17 ++--- .../ctx/state/ScriptCalculatedFieldState.java | 28 ++----- .../ctx/state/SingleValueArgumentEntry.java | 7 ++ .../cf/ctx/state/TsRollingArgumentEntry.java | 73 +++++++++++-------- .../state/ScriptCalculatedFieldStateTest.java | 30 ++++---- .../ctx/state/TsRollingArgumentEntryTest.java | 18 ++--- common/proto/src/main/proto/queue.proto | 12 ++- .../api/AbstractScriptInvokeService.java | 4 + .../api/tbel/DefaultTbelInvokeService.java | 6 +- .../script/api/tbel/TbelCfArg.java | 20 +++++ .../tbel/{TbCfArg.java => TbelCfObject.java} | 2 +- ...alueArg.java => TbelCfSingleValueArg.java} | 3 +- ...RollingArg.java => TbelCfTsDoubleVal.java} | 29 ++------ .../script/api/tbel/TbelCfTsRollingArg.java | 73 +++++++++++++++++++ 16 files changed, 214 insertions(+), 116 deletions(-) create mode 100644 common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfArg.java rename common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/{TbCfArg.java => TbelCfObject.java} (95%) rename common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/{TbCfSingleValueArg.java => TbelCfSingleValueArg.java} (93%) rename common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/{TbCfTsRollingArg.java => TbelCfTsDoubleVal.java} (54%) create mode 100644 common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsRollingArg.java diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index c787fc26af..90709638e0 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -810,7 +810,8 @@ public class ActorSystemContext { Futures.addCallback(future, RULE_CHAIN_DEBUG_EVENT_ERROR_CALLBACK, MoreExecutors.directExecutor()); } - public void persistCalculatedFieldDebugEvent(TenantId tenantId, CalculatedFieldId calculatedFieldId, EntityId entityId, Map arguments, UUID tbMsgId, TbMsgType tbMsgType, String result, Throwable error) { + public void persistCalculatedFieldDebugEvent(TenantId tenantId, CalculatedFieldId calculatedFieldId, EntityId entityId, Map arguments, + UUID tbMsgId, TbMsgType tbMsgType, String result, Throwable error) { if (cfDebugPerTenantEnabled) { TbRateLimits rateLimits = cfDebugPerTenantLimits.computeIfAbsent(tenantId, id -> new TbRateLimits(cfDebugPerTenantLimitsConfiguration)); @@ -831,7 +832,7 @@ public class ActorSystemContext { if (arguments != null) { eventBuilder.arguments(JacksonUtil.toString( arguments.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue())) + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toTbelCfArg())) )); } if (result != null) { diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ArgumentEntry.java index be471a8ad9..74e2d73601 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ArgumentEntry.java @@ -18,6 +18,7 @@ package org.thingsboard.server.service.cf.ctx.state; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.thingsboard.script.api.tbel.TbelCfArg; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -52,4 +53,6 @@ public interface ArgumentEntry { @JsonIgnore ArgumentEntry copy(); + TbelCfArg toTbelCfArg(); + } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java index 3374eb2660..0835038ce3 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/RocksDBCalculatedFieldStateService.java @@ -32,6 +32,8 @@ import org.thingsboard.server.common.util.KvProtoUtil; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldEntityCtxIdProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldStateProto; import org.thingsboard.server.gen.transport.TransportProtos.SingleValueArgumentProto; +import org.thingsboard.server.gen.transport.TransportProtos.TsDoubleValProto; +import org.thingsboard.server.gen.transport.TransportProtos.TsRollingArgumentProto; import org.thingsboard.server.gen.transport.TransportProtos.TsValueListProto; import org.thingsboard.server.gen.transport.TransportProtos.TsValueProto; import org.thingsboard.server.queue.util.AfterStartUp; @@ -130,11 +132,11 @@ public class RocksDBCalculatedFieldStateService implements CalculatedFieldStateS return builder.build(); } - private TsValueListProto toRollingArgumentProto(String argName, TsRollingArgumentEntry entry) { - TsValueListProto.Builder builder = TsValueListProto.newBuilder().setKey(argName); + private TsRollingArgumentProto toRollingArgumentProto(String argName, TsRollingArgumentEntry entry) { + TsRollingArgumentProto.Builder builder = TsRollingArgumentProto.newBuilder().setKey(argName); if (entry != TsRollingArgumentEntry.EMPTY) { - entry.getTsRecords().forEach((ts, value) -> builder.addTsValue(KvProtoUtil.toTsValueProto(ts, value))); + entry.getTsRecords().forEach((ts, value) -> builder.addTsValue(TsDoubleValProto.newBuilder().setTs(ts).setValue(value).build())); } return builder.build(); @@ -173,15 +175,12 @@ public class RocksDBCalculatedFieldStateService implements CalculatedFieldStateS return new SingleValueArgumentEntry(ts, kvEntry, proto.getVersion()); } - private TsRollingArgumentEntry fromRollingArgumentProto(TsValueListProto proto) { + private TsRollingArgumentEntry fromRollingArgumentProto(TsRollingArgumentProto proto) { if (proto.getTsValueCount() <= 0) { return (TsRollingArgumentEntry) TsRollingArgumentEntry.EMPTY; } - TreeMap tsRecords = new TreeMap<>(); - proto.getTsValueList().forEach(tsValueProto -> { - BasicKvEntry kvEntry = (BasicKvEntry) KvProtoUtil.fromTsValueProto(proto.getKey(), tsValueProto); - tsRecords.put(tsValueProto.getTs(), kvEntry); - }); + TreeMap tsRecords = new TreeMap<>(); + proto.getTsValueList().forEach(tsValueProto -> tsRecords.put(tsValueProto.getTs(), tsValueProto.getValue())); return new TsRollingArgumentEntry(tsRecords); } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldState.java index 7d86e376a3..d45b5eaa27 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldState.java @@ -21,15 +21,13 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; -import org.mvel2.execution.ExecutionArrayList; -import org.thingsboard.script.api.tbel.TbCfArg; -import org.thingsboard.script.api.tbel.TbCfSingleValueArg; -import org.thingsboard.script.api.tbel.TbCfTsRollingArg; +import org.thingsboard.script.api.tbel.TbelCfArg; +import org.thingsboard.script.api.tbel.TbelCfSingleValueArg; +import org.thingsboard.script.api.tbel.TbelCfTsDoubleVal; +import org.thingsboard.script.api.tbel.TbelCfTsRollingArg; import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.configuration.Argument; import org.thingsboard.server.common.data.cf.configuration.Output; -import org.thingsboard.server.common.data.kv.BasicKvEntry; import org.thingsboard.server.service.cf.CalculatedFieldResult; import java.util.ArrayList; @@ -60,7 +58,7 @@ public class ScriptCalculatedFieldState extends BaseCalculatedFieldState { arguments.forEach((key, argumentEntry) -> { if (argumentEntry instanceof TsRollingArgumentEntry tsRollingEntry) { Argument argument = ctx.getArguments().get(key); - TreeMap tsRecords = tsRollingEntry.getTsRecords(); + TreeMap tsRecords = tsRollingEntry.getTsRecords(); if (tsRecords.size() > argument.getLimit()) { tsRecords.pollFirstEntry(); } @@ -79,20 +77,8 @@ public class ScriptCalculatedFieldState extends BaseCalculatedFieldState { ); } - private TbCfArg toTbelArgument(String key) { - ArgumentEntry argEntry = arguments.get(key); - if (argEntry instanceof SingleValueArgumentEntry svArg) { - return new TbCfSingleValueArg(svArg.getTs(), argEntry.getValue()); - } else if (argEntry instanceof TsRollingArgumentEntry rollingArg) { - var tsRecords = rollingArg.getTsRecords(); - List values = new ArrayList<>(tsRecords.size()); - for(var e : tsRecords.entrySet()){ - values.add(new TbCfSingleValueArg(e.getKey(), e.getValue().getValue())); - } - return new TbCfTsRollingArg(values); - } else { - throw new RuntimeException("Argument is not supported for TBEL execution!"); - } + private TbelCfArg toTbelArgument(String key) { + return arguments.get(key).toTbelCfArg(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java index d7e5ddd017..5614e592d7 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SingleValueArgumentEntry.java @@ -19,6 +19,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import org.thingsboard.script.api.tbel.TbelCfArg; +import org.thingsboard.script.api.tbel.TbelCfSingleValueArg; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BasicKvEntry; import org.thingsboard.server.common.data.kv.KvEntry; @@ -84,6 +86,11 @@ public class SingleValueArgumentEntry implements ArgumentEntry { return new SingleValueArgumentEntry(this.ts, this.kvEntryValue, this.version); } + @Override + public TbelCfArg toTbelCfArg() { + return new TbelCfSingleValueArg(ts, kvEntryValue.getValue()); + } + @Override public boolean updateEntry(ArgumentEntry entry) { if (entry instanceof SingleValueArgumentEntry singleValueEntry) { diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java index ddae0c3513..f7bc891c41 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntry.java @@ -21,11 +21,16 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.math.NumberUtils; +import org.thingsboard.script.api.tbel.TbelCfArg; +import org.thingsboard.script.api.tbel.TbelCfTsDoubleVal; +import org.thingsboard.script.api.tbel.TbelCfTsRollingArg; import org.thingsboard.server.common.data.kv.BasicKvEntry; +import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.util.ProtoUtils; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -41,7 +46,7 @@ public class TsRollingArgumentEntry implements ArgumentEntry { private static final int MAX_ROLLING_ARGUMENT_ENTRY_SIZE = 1000; - private TreeMap tsRecords = new TreeMap<>(); + private TreeMap tsRecords = new TreeMap<>(); public TsRollingArgumentEntry(List kvEntries) { kvEntries.forEach(tsKvEntry -> addTsRecord(tsKvEntry.getTs(), tsKvEntry)); @@ -62,15 +67,7 @@ public class TsRollingArgumentEntry implements ArgumentEntry { @JsonIgnore @Override public Object getValue() { - return tsRecords.entrySet() - .stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - entry -> entry.getValue().getValue(), - (oldValue, newValue) -> oldValue, - TreeMap::new - )); - + return tsRecords; } @Override @@ -78,45 +75,57 @@ public class TsRollingArgumentEntry implements ArgumentEntry { return new TsRollingArgumentEntry(new TreeMap<>(tsRecords)); } + @Override + public TbelCfArg toTbelCfArg() { + List values = new ArrayList<>(tsRecords.size()); + for (var e : tsRecords.entrySet()) { + values.add(new TbelCfTsDoubleVal(e.getKey(), e.getValue())); + } + return new TbelCfTsRollingArg(values); + } + @Override public boolean updateEntry(ArgumentEntry entry) { if (entry instanceof TsRollingArgumentEntry tsRollingEntry) { - return updateTsRollingEntry(tsRollingEntry); + updateTsRollingEntry(tsRollingEntry); } else if (entry instanceof SingleValueArgumentEntry singleValueEntry) { - return updateSingleValueEntry(singleValueEntry); + updateSingleValueEntry(singleValueEntry); } else { throw new IllegalArgumentException("Unsupported argument entry type for rolling argument entry: " + entry.getType()); } + return true; } - private boolean updateTsRollingEntry(TsRollingArgumentEntry tsRollingEntry) { - boolean updated = false; - for (Map.Entry tsRecordEntry : tsRollingEntry.getTsRecords().entrySet()) { - updated |= addTsRecordIfAbsent(tsRecordEntry.getKey(), tsRecordEntry.getValue()); + private void updateTsRollingEntry(TsRollingArgumentEntry tsRollingEntry) { + for (Map.Entry tsRecordEntry : tsRollingEntry.getTsRecords().entrySet()) { + addTsRecord(tsRecordEntry.getKey(), tsRecordEntry.getValue()); } - return updated; } - private boolean updateSingleValueEntry(SingleValueArgumentEntry singleValueEntry) { - return addTsRecordIfAbsent(singleValueEntry.getTs(), singleValueEntry.getKvEntryValue()); + private void updateSingleValueEntry(SingleValueArgumentEntry singleValueEntry) { + addTsRecord(singleValueEntry.getTs(), singleValueEntry.getKvEntryValue()); } - private boolean addTsRecordIfAbsent(Long ts, KvEntry value) { - if (!tsRecords.containsKey(ts)) { - addTsRecord(ts, value); - return true; + private void addTsRecord(Long ts, KvEntry value) { + switch (value.getDataType()) { + case LONG -> value.getLongValue().ifPresent(aLong -> tsRecords.put(ts, aLong.doubleValue())); + case DOUBLE -> value.getDoubleValue().ifPresent(aDouble -> tsRecords.put(ts, aDouble)); + case BOOLEAN -> value.getBooleanValue().ifPresent(aBoolean -> tsRecords.put(ts, aBoolean ? 1.0 : 0.0)); + case STRING -> value.getStrValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); + case JSON -> value.getJsonValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); + //TODO: try catch } - return false; + pollFirstEntryIfNeeded(); } - private void addTsRecord(Long ts, KvEntry value) { - if (NumberUtils.isParsable(value.getValue().toString())) { - tsRecords.put(ts, ProtoUtils.basicKvEntryFromKvEntry(value)); - if (tsRecords.size() > MAX_ROLLING_ARGUMENT_ENTRY_SIZE) { - tsRecords.pollFirstEntry(); - } - } else { - throw new IllegalArgumentException("Argument type " + getType() + " only supports numeric values."); + private void addTsRecord(Long ts, double value) { + tsRecords.put(ts, value); + pollFirstEntryIfNeeded(); + } + + private void pollFirstEntryIfNeeded() { + if (tsRecords.size() > MAX_ROLLING_ARGUMENT_ENTRY_SIZE) { + tsRecords.pollFirstEntry(); } } diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldStateTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldStateTest.java index bded0d058d..f7fc3892b1 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldStateTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/ScriptCalculatedFieldStateTest.java @@ -134,10 +134,10 @@ public class ScriptCalculatedFieldStateTest { void testPerformCalculationWhenOldTelemetry() throws ExecutionException, InterruptedException { TsRollingArgumentEntry argumentEntry = new TsRollingArgumentEntry(); - TreeMap values = new TreeMap<>(); - values.put(ts - 40000, new LongDataEntry("deviceTemperature", 4L));// will not be used for calculation - values.put(ts - 45000, new LongDataEntry("deviceTemperature", 2L));// will not be used for calculation - values.put(ts - 20, new LongDataEntry("deviceTemperature", 0L)); + TreeMap values = new TreeMap<>(); + values.put(ts - 40000, 4.0);// will not be used for calculation + values.put(ts - 45000, 2.0);// will not be used for calculation + values.put(ts - 20, 0.0); argumentEntry.setTsRecords(values); @@ -155,13 +155,13 @@ public class ScriptCalculatedFieldStateTest { @Test void testPerformCalculationWhenArgumentsMoreThanLimit() throws ExecutionException, InterruptedException { TsRollingArgumentEntry argumentEntry = new TsRollingArgumentEntry(); - TreeMap values = new TreeMap<>(); - values.put(ts - 20, new LongDataEntry("deviceTemperature", 1000L));// will not be used - values.put(ts - 18, new LongDataEntry("deviceTemperature", 0L)); - values.put(ts - 16, new LongDataEntry("deviceTemperature", 0L)); - values.put(ts - 14, new LongDataEntry("deviceTemperature", 0L)); - values.put(ts - 12, new LongDataEntry("deviceTemperature", 0L)); - values.put(ts - 10, new LongDataEntry("deviceTemperature", 0L)); + TreeMap values = new TreeMap<>(); + values.put(ts - 20, 1000.0);// will not be used + values.put(ts - 18, 0.0); + values.put(ts - 16, 0.0); + values.put(ts - 14, 0.0); + values.put(ts - 12, 0.0); + values.put(ts - 10, 0.0); argumentEntry.setTsRecords(values); state.arguments = new HashMap<>(Map.of("deviceTemperature", argumentEntry, "assetHumidity", assetHumidityArgEntry)); @@ -198,10 +198,10 @@ public class ScriptCalculatedFieldStateTest { TsRollingArgumentEntry argumentEntry = new TsRollingArgumentEntry(); long ts = System.currentTimeMillis(); - TreeMap values = new TreeMap<>(); - values.put(ts - 40, new LongDataEntry("deviceTemperature", 10L)); - values.put(ts - 30, new LongDataEntry("deviceTemperature", 12L)); - values.put(ts - 20, new LongDataEntry("deviceTemperature", 17L)); + TreeMap values = new TreeMap<>(); + values.put(ts - 40, 10.0); + values.put(ts - 30, 12.0); + values.put(ts - 20, 17.0); argumentEntry.setTsRecords(values); return argumentEntry; diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntryTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntryTest.java index 5a6f5e96e5..ad098178f8 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntryTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/TsRollingArgumentEntryTest.java @@ -35,10 +35,10 @@ public class TsRollingArgumentEntryTest { @BeforeEach void setUp() { - TreeMap values = new TreeMap<>(); - values.put(ts - 40, new DoubleDataEntry("key", 10.0)); - values.put(ts - 30, new DoubleDataEntry("key", 12.0)); - values.put(ts - 20, new DoubleDataEntry("key", 17.0)); + TreeMap values = new TreeMap<>(); + values.put(ts - 40, 10.0); + values.put(ts - 30, 12.0); + values.put(ts - 20, 17.0); entry = new TsRollingArgumentEntry(values); } @@ -54,7 +54,7 @@ public class TsRollingArgumentEntryTest { assertThat(entry.updateEntry(newEntry)).isTrue(); assertThat(entry.getTsRecords()).hasSize(4); - assertThat(entry.getTsRecords().get(ts - 10).getValue()).isEqualTo(23.0); + assertThat(entry.getTsRecords().get(ts - 10)).isEqualTo(23.0); } @Test @@ -67,10 +67,10 @@ public class TsRollingArgumentEntryTest { @Test void testUpdateEntryWhenRollingEntryPassed() { TsRollingArgumentEntry newEntry = new TsRollingArgumentEntry(); - TreeMap values = new TreeMap<>(); - values.put(ts - 20, new DoubleDataEntry("key", 16.0)); - values.put(ts - 10, new DoubleDataEntry("key", 7.0)); - values.put(ts - 5, new DoubleDataEntry("key", 1.0)); + TreeMap values = new TreeMap<>(); + values.put(ts - 20, 16.0); + values.put(ts - 10, 7.0); + values.put(ts - 5, 1.0); newEntry.setTsRecords(values); assertThat(entry.updateEntry(newEntry)).isTrue(); diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 4a2f3710ae..d0050c310d 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -814,12 +814,22 @@ message SingleValueArgumentProto { int64 version = 3; } +message TsDoubleValProto { + int64 ts = 1; + double value = 2; +} + +message TsRollingArgumentProto { + string key = 1; + repeated TsDoubleValProto tsValue = 2; +} + message CalculatedFieldStateProto { CalculatedFieldEntityCtxIdProto id = 1; // int32 version = 2; string type = 3; repeated SingleValueArgumentProto singleValueArguments = 4; - repeated TsValueListProto rollingValueArguments = 5; + repeated TsRollingArgumentProto rollingValueArguments = 5; } //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java index 342801f9a8..e16dacca28 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java @@ -22,6 +22,8 @@ import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.script.api.tbel.TbelCfArg; +import org.thingsboard.script.api.tbel.TbelCfObject; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; @@ -256,6 +258,8 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService for (Object arg : args) { if (arg instanceof CharSequence) { totalArgsSize += ((CharSequence) arg).length(); + } else if (arg instanceof TbelCfObject tbelCfObj) { + totalArgsSize += tbelCfObj.memorySize(); } else { var str = JacksonUtil.toString(arg); if (str != null) { diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index 906e6ac393..177bc517a8 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -32,7 +32,6 @@ import org.mvel2.MVEL; import org.mvel2.ParserContext; import org.mvel2.SandboxedParserConfiguration; import org.mvel2.ScriptMemoryOverflowException; -import org.mvel2.integration.PropertyHandlerFactory; import org.mvel2.optimizers.OptimizerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -134,8 +133,9 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem parserConfig.registerDataType("Date", TbDate.class, val -> 8L); parserConfig.registerDataType("Random", Random.class, val -> 8L); parserConfig.registerDataType("Calendar", Calendar.class, val -> 8L); - parserConfig.registerDataType("TbCfSingleValueArg", TbCfSingleValueArg.class, TbCfSingleValueArg::memorySize); - parserConfig.registerDataType("TbCfTsRollingArg", TbCfTsRollingArg.class, TbCfTsRollingArg::memorySize); + parserConfig.registerDataType("TbelCfSingleValueArg", TbelCfSingleValueArg.class, TbelCfSingleValueArg::memorySize); + parserConfig.registerDataType("TbelCfTsRollingArg", TbelCfTsRollingArg.class, TbelCfTsRollingArg::memorySize); + parserConfig.registerDataType("TbelCfTsDoubleVal", TbelCfTsDoubleVal.class, TbelCfTsDoubleVal::memorySize); TbUtils.register(parserConfig); executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "tbel-executor")); try { diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfArg.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfArg.java new file mode 100644 index 0000000000..ac5bd5cc06 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfArg.java @@ -0,0 +1,20 @@ +/** + * Copyright © 2016-2024 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.tbel; + +public interface TbelCfArg extends TbelCfObject { + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfArg.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfObject.java similarity index 95% rename from common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfArg.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfObject.java index f5d990a553..b34c11089d 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfArg.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfObject.java @@ -15,7 +15,7 @@ */ package org.thingsboard.script.api.tbel; -public interface TbCfArg { +public interface TbelCfObject { long memorySize(); diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfSingleValueArg.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfSingleValueArg.java similarity index 93% rename from common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfSingleValueArg.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfSingleValueArg.java index e42fb64ba4..7076e9dd5e 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfSingleValueArg.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfSingleValueArg.java @@ -18,7 +18,7 @@ package org.thingsboard.script.api.tbel; import lombok.Data; @Data -public class TbCfSingleValueArg implements TbCfArg { +public class TbelCfSingleValueArg implements TbelCfArg { private final long ts; private final Object value; @@ -27,4 +27,5 @@ public class TbCfSingleValueArg implements TbCfArg { public long memorySize() { return 8L; // TODO; } + } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfTsRollingArg.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsDoubleVal.java similarity index 54% rename from common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfTsRollingArg.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsDoubleVal.java index a8abbc64ac..fa877868cd 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbCfTsRollingArg.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsDoubleVal.java @@ -15,33 +15,18 @@ */ package org.thingsboard.script.api.tbel; -import lombok.Getter; +import lombok.Data; -import java.util.List; +@Data +public class TbelCfTsDoubleVal implements TbelCfObject { -public class TbCfTsRollingArg implements TbCfArg { + public static final long OBJ_SIZE = 32L; // Approximate calculation; - @Getter - private final List values; - - public TbCfTsRollingArg(List values) { - this.values = values; - } + private final long ts; + private final double value; @Override public long memorySize() { - return values.size() * 8L; //TODO; + return OBJ_SIZE; } - - public double max() { - double max = Double.MIN_VALUE; - for (TbCfSingleValueArg arg : values) { - double val = Double.valueOf(arg.getValue().toString()); - if (max < val) { - max = val; - } - } - return max; - } - } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsRollingArg.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsRollingArg.java new file mode 100644 index 0000000000..14122bbde8 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelCfTsRollingArg.java @@ -0,0 +1,73 @@ +/** + * Copyright © 2016-2024 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.tbel; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +import static org.thingsboard.script.api.tbel.TbelCfTsDoubleVal.OBJ_SIZE; + +public class TbelCfTsRollingArg implements TbelCfArg, Iterable { + + @Getter + private final List values; + + public TbelCfTsRollingArg(List values) { + this.values = Collections.unmodifiableList(values); + } + + @Override + public long memorySize() { + return 12 + values.size() * OBJ_SIZE; + } + + @JsonIgnore + public List getValue() { + return values; + } + + public double max() { + double max = Double.MIN_VALUE; + for (TbelCfTsDoubleVal value : values) { + double val = value.getValue(); + if (max < val) { + max = val; + } + } + return max; + } + + @JsonIgnore + public int getSize() { + return values.size(); + } + + @Override + public Iterator iterator() { + return values.iterator(); + } + + @Override + public void forEach(Consumer action) { + values.forEach(action); + } + +}