Browse Source

protection from use latest ts when output type is attributes

pull/14825/head
dshvaika 9 months ago
parent
commit
4897b33639
  1. 5
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java
  2. 6
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java
  3. 6
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java
  4. 2
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java
  5. 7
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/geofencing/GeofencingCalculatedFieldState.java
  6. 4
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java
  7. 3
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java
  8. 22
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasUseLatestTsConfig.java
  9. 9
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java
  10. 2
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java
  11. 3
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java
  12. 11
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/geofencing/GeofencingCalculatedFieldConfiguration.java

5
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/BaseCalculatedFieldState.java

@ -21,6 +21,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.actors.TbActorRef; import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId; import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId;
@ -142,8 +143,8 @@ public abstract class BaseCalculatedFieldState implements CalculatedFieldState,
protected void validateNewEntry(String key, ArgumentEntry newEntry) { protected void validateNewEntry(String key, ArgumentEntry newEntry) {
} }
protected ObjectNode toSimpleResult(boolean useLatestTs, ObjectNode valuesNode) { protected ObjectNode toResultNode(ObjectNode valuesNode) {
if (!useLatestTs) { if (ctx.getOutput().getType() == OutputType.ATTRIBUTES || !ctx.isUseLatestTs()) {
return valuesNode; return valuesNode;
} }
long latestTs = getLatestTimestamp(); long latestTs = getLatestTimestamp();

6
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java

@ -39,6 +39,7 @@ import org.thingsboard.server.common.data.cf.configuration.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentType; import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ExpressionBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ExpressionBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey; import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
@ -187,7 +188,6 @@ public class CalculatedFieldCtx implements Closeable {
.collect(Collectors.toList()); .collect(Collectors.toList());
if (argBasedConfig instanceof ExpressionBasedCalculatedFieldConfiguration expressionBasedConfig) { if (argBasedConfig instanceof ExpressionBasedCalculatedFieldConfiguration expressionBasedConfig) {
this.expression = expressionBasedConfig.getExpression(); this.expression = expressionBasedConfig.getExpression();
this.useLatestTs = CalculatedFieldType.SIMPLE.equals(calculatedField.getType()) && ((SimpleCalculatedFieldConfiguration) argBasedConfig).isUseLatestTs();
} }
if (calculatedField.getConfiguration() instanceof GeofencingCalculatedFieldConfiguration geofencingConfig) { if (calculatedField.getConfiguration() instanceof GeofencingCalculatedFieldConfiguration geofencingConfig) {
geofencingConfig.getZoneGroups().forEach((zoneGroupName, config) -> { geofencingConfig.getZoneGroups().forEach((zoneGroupName, config) -> {
@ -209,8 +209,8 @@ public class CalculatedFieldCtx implements Closeable {
if (calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration scheduledConfig) { if (calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration scheduledConfig) {
this.scheduledUpdateIntervalMillis = scheduledConfig.isScheduledUpdateEnabled() ? TimeUnit.SECONDS.toMillis(scheduledConfig.getScheduledUpdateInterval()) : DISABLED_INTERVAL_VALUE; this.scheduledUpdateIntervalMillis = scheduledConfig.isScheduledUpdateEnabled() ? TimeUnit.SECONDS.toMillis(scheduledConfig.getScheduledUpdateInterval()) : DISABLED_INTERVAL_VALUE;
} }
if (calculatedField.getConfiguration() instanceof RelatedEntitiesAggregationCalculatedFieldConfiguration aggConfig) { if (calculatedField.getConfiguration() instanceof HasUseLatestTsConfig hasUseLatestTsConfig) {
this.useLatestTs = aggConfig.isUseLatestTs(); this.useLatestTs = hasUseLatestTsConfig.isUseLatestTs();
} }
this.systemContext = systemContext; this.systemContext = systemContext;
this.tbelInvokeService = systemContext.getTbelInvokeService(); this.tbelInvokeService = systemContext.getTbelInvokeService();

6
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/SimpleCalculatedFieldState.java

@ -53,7 +53,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
Output output = ctx.getOutput(); Output output = ctx.getOutput();
Object result = NumberUtils.roundResult(expressionResult, output.getDecimalsByDefault()); Object result = NumberUtils.roundResult(expressionResult, output.getDecimalsByDefault());
JsonNode outputResult = createResultJson(ctx.isUseLatestTs(), output.getName(), result); JsonNode outputResult = createResultJson(output.getName(), result);
return Futures.immediateFuture(TelemetryCalculatedFieldResult.builder() return Futures.immediateFuture(TelemetryCalculatedFieldResult.builder()
.outputStrategy(output.getStrategy()) .outputStrategy(output.getStrategy())
@ -63,7 +63,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
.build()); .build());
} }
private JsonNode createResultJson(boolean useLatestTs, String outputName, Object result) { private JsonNode createResultJson(String outputName, Object result) {
ObjectNode valuesNode = JacksonUtil.newObjectNode(); ObjectNode valuesNode = JacksonUtil.newObjectNode();
if (result instanceof Double doubleValue) { if (result instanceof Double doubleValue) {
valuesNode.put(outputName, doubleValue); valuesNode.put(outputName, doubleValue);
@ -72,7 +72,7 @@ public class SimpleCalculatedFieldState extends BaseCalculatedFieldState {
} else { } else {
valuesNode.set(outputName, JacksonUtil.valueToTree(result)); valuesNode.set(outputName, JacksonUtil.valueToTree(result));
} }
return toSimpleResult(useLatestTs, valuesNode); return toResultNode(valuesNode);
} }
@Override @Override

2
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java

@ -201,7 +201,7 @@ public class RelatedEntitiesAggregationCalculatedFieldState extends BaseCalculat
.outputStrategy(output.getStrategy()) .outputStrategy(output.getStrategy())
.type(output.getType()) .type(output.getType())
.scope(output.getScope()) .scope(output.getScope())
.result(toSimpleResult(ctx.isUseLatestTs(), aggResult)) .result(toResultNode(aggResult))
.build()); .build());
} else { } else {
return Futures.immediateFuture(TelemetryCalculatedFieldResult.EMPTY); return Futures.immediateFuture(TelemetryCalculatedFieldResult.EMPTY);

7
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/geofencing/GeofencingCalculatedFieldState.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.service.cf.ctx.state.geofencing; package org.thingsboard.server.service.cf.ctx.state.geofencing;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -136,7 +135,7 @@ public class GeofencingCalculatedFieldState extends BaseCalculatedFieldState imp
.outputStrategy(ctx.getOutput().getStrategy()) .outputStrategy(ctx.getOutput().getStrategy())
.type(outputType) .type(outputType)
.scope(ctx.getOutput().getScope()) .scope(ctx.getOutput().getScope())
.result(toResultNode(outputType, valuesNode)) .result(toResultNode(valuesNode))
.build(); .build();
if (relationFutures.isEmpty()) { if (relationFutures.isEmpty()) {
return Futures.immediateFuture(result); return Futures.immediateFuture(result);
@ -186,10 +185,6 @@ public class GeofencingCalculatedFieldState extends BaseCalculatedFieldState imp
} }
} }
private JsonNode toResultNode(OutputType outputType, ObjectNode valuesNode) {
return toSimpleResult(outputType == OutputType.TIME_SERIES, valuesNode);
}
private GeofencingEvalResult aggregateZoneGroup(List<GeofencingEvalResult> zoneResults) { private GeofencingEvalResult aggregateZoneGroup(List<GeofencingEvalResult> zoneResults) {
boolean nowInside = zoneResults.stream().anyMatch(r -> INSIDE.equals(r.status())); boolean nowInside = zoneResults.stream().anyMatch(r -> INSIDE.equals(r.status()));
boolean prevInside = zoneResults.stream() boolean prevInside = zoneResults.stream()

4
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java

@ -24,7 +24,6 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.actors.TbActorRef; import org.thingsboard.server.actors.TbActorRef;
import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.CalculatedFieldType;
import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.data.util.CollectionsUtil;
import org.thingsboard.server.service.cf.CalculatedFieldProcessingService; import org.thingsboard.server.service.cf.CalculatedFieldProcessingService;
@ -171,8 +170,7 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState
throw new IllegalArgumentException("Unsupported argument type: " + argumentEntry.getType() + " detected for argument: " + outputKey + ". " + throw new IllegalArgumentException("Unsupported argument type: " + argumentEntry.getType() + " detected for argument: " + outputKey + ". " +
"Only Latest telemetry or Attribute arguments supported for 'Arguments Only' propagation mode!"); "Only Latest telemetry or Attribute arguments supported for 'Arguments Only' propagation mode!");
}); });
ObjectNode result = toSimpleResult(output.getType() == OutputType.TIME_SERIES, valuesNode); telemetryCfBuilder.result(toResultNode(valuesNode));
telemetryCfBuilder.result(result);
return telemetryCfBuilder.build(); return telemetryCfBuilder.build();
} }

3
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/BaseCalculatedFieldConfiguration.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.data.cf.configuration; package org.thingsboard.server.common.data.cf.configuration;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import java.util.Map; import java.util.Map;
@ -24,6 +25,8 @@ public abstract class BaseCalculatedFieldConfiguration implements ExpressionBase
protected Map<String, Argument> arguments; protected Map<String, Argument> arguments;
protected String expression; protected String expression;
@NotNull
protected Output output; protected Output output;
@Override @Override

22
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasUseLatestTsConfig.java

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2026 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.server.common.data.cf.configuration;
public interface HasUseLatestTsConfig {
boolean isUseLatestTs();
}

9
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.data.cf.configuration; package org.thingsboard.server.common.data.cf.configuration;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
@ -27,7 +28,7 @@ import java.util.List;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements HasRelationPathLevel { public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements HasRelationPathLevel, HasUseLatestTsConfig {
public static final String PROPAGATION_CONFIG_ARGUMENT = "propagationCtx"; public static final String PROPAGATION_CONFIG_ARGUMENT = "propagationCtx";
@ -37,6 +38,12 @@ public class PropagationCalculatedFieldConfiguration extends BaseCalculatedField
private boolean applyExpressionToResolvedArguments; private boolean applyExpressionToResolvedArguments;
@Override
@JsonIgnore
public boolean isUseLatestTs() {
return output.getType() == OutputType.TIME_SERIES;
}
@Override @Override
public CalculatedFieldType getType() { public CalculatedFieldType getType() {
return CalculatedFieldType.PROPAGATION; return CalculatedFieldType.PROPAGATION;

2
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/SimpleCalculatedFieldConfiguration.java

@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ExpressionBasedCalculatedFieldConfiguration { public class SimpleCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements ExpressionBasedCalculatedFieldConfiguration, HasUseLatestTsConfig {
private boolean useLatestTs; private boolean useLatestTs;

3
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java

@ -23,6 +23,7 @@ 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.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasRelationPathLevel; import org.thingsboard.server.common.data.cf.configuration.HasRelationPathLevel;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.relation.RelationPathLevel; import org.thingsboard.server.common.data.relation.RelationPathLevel;
@ -30,7 +31,7 @@ import org.thingsboard.server.common.data.relation.RelationPathLevel;
import java.util.Map; import java.util.Map;
@Data @Data
public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasRelationPathLevel { public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasRelationPathLevel, HasUseLatestTsConfig {
@NotNull @NotNull
private RelationPathLevel relation; private RelationPathLevel relation;

11
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/geofencing/GeofencingCalculatedFieldConfiguration.java

@ -22,7 +22,9 @@ import lombok.Data;
import org.thingsboard.server.common.data.cf.CalculatedFieldType; 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.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.HasUseLatestTsConfig;
import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
@ -35,7 +37,7 @@ import java.util.Set;
import static java.util.stream.Collectors.toSet; import static java.util.stream.Collectors.toSet;
@Data @Data
public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration { public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasUseLatestTsConfig {
@Valid @Valid
@NotNull @NotNull
@ -48,8 +50,15 @@ public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCal
private boolean scheduledUpdateEnabled; private boolean scheduledUpdateEnabled;
private int scheduledUpdateInterval; private int scheduledUpdateInterval;
@NotNull
private Output output; private Output output;
@Override
@JsonIgnore
public boolean isUseLatestTs() {
return output.getType() == OutputType.TIME_SERIES;
}
@Override @Override
public CalculatedFieldType getType() { public CalculatedFieldType getType() {
return CalculatedFieldType.GEOFENCING; return CalculatedFieldType.GEOFENCING;

Loading…
Cancel
Save