refactoring after merge to PE
This commit is contained in:
parent
c9e4904135
commit
eb36297b69
@ -321,7 +321,7 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM
|
||||
callback.onSuccess();
|
||||
}
|
||||
if (DebugModeUtil.isDebugAllAvailable(ctx.getCalculatedField())) {
|
||||
systemContext.persistCalculatedFieldDebugEvent(tenantId, ctx.getCfId(), entityId, state.getArguments(), tbMsgId, tbMsgType, calculationResult.getResult().toString(), null);
|
||||
systemContext.persistCalculatedFieldDebugEvent(tenantId, ctx.getCfId(), entityId, state.getArguments(), tbMsgId, tbMsgType, calculationResult.toStringOrElseNull(), null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.ProfileEntityIdInfo;
|
||||
import org.thingsboard.server.common.data.cf.CalculatedField;
|
||||
import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduleSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.id.AssetId;
|
||||
import org.thingsboard.server.common.data.id.CalculatedFieldId;
|
||||
import org.thingsboard.server.common.data.id.DeviceId;
|
||||
@ -482,7 +482,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
|
||||
|
||||
private void scheduleDynamicArgumentsRefreshTaskForCfIfNeeded(CalculatedFieldCtx cfCtx) {
|
||||
CalculatedField cf = cfCtx.getCalculatedField();
|
||||
if (!(cf.getConfiguration() instanceof ScheduleSupportedCalculatedFieldConfiguration scheduledCfConfig)) {
|
||||
if (!(cf.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration scheduledCfConfig)) {
|
||||
return;
|
||||
}
|
||||
if (!scheduledCfConfig.isScheduledUpdateEnabled()) {
|
||||
|
||||
@ -34,14 +34,8 @@ public final class CalculatedFieldResult {
|
||||
(result.isTextual() && result.asText().isEmpty());
|
||||
}
|
||||
|
||||
public String getResultAsString() {
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
if (result.isTextual()) {
|
||||
return result.asText();
|
||||
}
|
||||
return result.toString();
|
||||
public String toStringOrElseNull() {
|
||||
return result == null ? null : result.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.common.util.ThingsBoardExecutors;
|
||||
import org.thingsboard.server.actors.calculatedField.CalculatedFieldTelemetryMsg;
|
||||
@ -31,7 +30,6 @@ import org.thingsboard.server.actors.calculatedField.MultipleTbCallback;
|
||||
import org.thingsboard.server.cluster.TbClusterService;
|
||||
import org.thingsboard.server.common.data.DataConstants;
|
||||
import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
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.ArgumentType;
|
||||
@ -45,11 +43,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery;
|
||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.KvEntry;
|
||||
import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||
import org.thingsboard.server.common.data.msg.TbMsgType;
|
||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||
@ -76,10 +70,6 @@ import org.thingsboard.server.service.cf.ctx.CalculatedFieldEntityCtxId;
|
||||
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry;
|
||||
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx;
|
||||
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.GeofencingCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.SimpleCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry;
|
||||
import org.thingsboard.server.service.cf.ctx.state.TsRollingArgumentEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -96,6 +86,9 @@ import java.util.stream.Collectors;
|
||||
import static org.thingsboard.server.common.data.DataConstants.SCOPE;
|
||||
import static org.thingsboard.server.common.data.cf.configuration.geofencing.EntityCoordinates.ENTITY_ID_LATITUDE_ARGUMENT_KEY;
|
||||
import static org.thingsboard.server.common.data.cf.configuration.geofencing.EntityCoordinates.ENTITY_ID_LONGITUDE_ARGUMENT_KEY;
|
||||
import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createDefaultKvEntry;
|
||||
import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createStateByType;
|
||||
import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.transformSingleValueArgument;
|
||||
import static org.thingsboard.server.utils.CalculatedFieldUtils.toProto;
|
||||
|
||||
@TbRuleEngineComponent
|
||||
@ -144,7 +137,7 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
var result = createStateByType(ctx);
|
||||
result.updateState(ctx, resolveArgumentFutures(argFutures));
|
||||
return result;
|
||||
}, calculatedFieldCallbackExecutor);
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -171,7 +164,7 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
default -> {
|
||||
var resolvedEntityIdsFuture = resolveGeofencingEntityIds(ctx.getTenantId(), entityId, entry);
|
||||
argFutures.put(entry.getKey(), Futures.transformAsync(resolvedEntityIdsFuture, resolvedEntityIds ->
|
||||
fetchGeofencingKvEntry(ctx.getTenantId(), resolvedEntityIds, entry.getValue()), calculatedFieldCallbackExecutor));
|
||||
fetchGeofencingKvEntry(ctx.getTenantId(), resolvedEntityIds, entry.getValue()), MoreExecutors.directExecutor()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,7 +203,7 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
OutputType type = calculatedFieldResult.getType();
|
||||
TbMsgType msgType = OutputType.ATTRIBUTES.equals(type) ? TbMsgType.POST_ATTRIBUTES_REQUEST : TbMsgType.POST_TELEMETRY_REQUEST;
|
||||
TbMsgMetaData md = OutputType.ATTRIBUTES.equals(type) ? new TbMsgMetaData(Map.of(SCOPE, calculatedFieldResult.getScope().name())) : TbMsgMetaData.EMPTY;
|
||||
TbMsg msg = TbMsg.newMsg().type(msgType).originator(entityId).previousCalculatedFieldIds(cfIds).metaData(md).data(calculatedFieldResult.getResult().toString()).build();
|
||||
TbMsg msg = TbMsg.newMsg().type(msgType).originator(entityId).previousCalculatedFieldIds(cfIds).metaData(md).data(calculatedFieldResult.toStringOrElseNull()).build();
|
||||
clusterService.pushMsgToRuleEngine(tenantId, entityId, msg, new TbQueueCallback() {
|
||||
@Override
|
||||
public void onSuccess(TbQueueMsgMetadata metadata) {
|
||||
@ -337,20 +330,16 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
ListenableFuture<List<Entry<EntityId, AttributeKvEntry>>> allFutures = Futures.allAsList(kvFutures);
|
||||
|
||||
return Futures.transform(allFutures, entries -> ArgumentEntry.createGeofencingValueArgument(entries.stream()
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))),
|
||||
calculatedFieldCallbackExecutor
|
||||
);
|
||||
.collect(Collectors.toMap(Entry::getKey, Entry::getValue))), MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
private ListenableFuture<ArgumentEntry> fetchKvEntry(TenantId tenantId, EntityId entityId, Argument argument) {
|
||||
return switch (argument.getRefEntityKey().getType()) {
|
||||
case TS_ROLLING -> fetchTsRolling(tenantId, entityId, argument);
|
||||
case ATTRIBUTE -> transformSingleValueArgument(
|
||||
Futures.transform(
|
||||
attributesService.find(tenantId, entityId, argument.getRefEntityKey().getScope(), argument.getRefEntityKey().getKey()),
|
||||
Futures.transform(attributesService.find(tenantId, entityId, argument.getRefEntityKey().getScope(), argument.getRefEntityKey().getKey()),
|
||||
result -> result.or(() -> Optional.of(new BaseAttributeKvEntry(createDefaultKvEntry(argument), System.currentTimeMillis(), 0L))),
|
||||
calculatedFieldCallbackExecutor)
|
||||
);
|
||||
calculatedFieldCallbackExecutor));
|
||||
case TS_LATEST -> transformSingleValueArgument(
|
||||
Futures.transform(
|
||||
timeseriesService.findLatest(tenantId, entityId, argument.getRefEntityKey().getKey()),
|
||||
@ -359,16 +348,6 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
};
|
||||
}
|
||||
|
||||
private ListenableFuture<ArgumentEntry> transformSingleValueArgument(ListenableFuture<Optional<? extends KvEntry>> kvEntryFuture) {
|
||||
return Futures.transform(kvEntryFuture, kvEntry -> {
|
||||
if (kvEntry.isPresent() && kvEntry.get().getValue() != null) {
|
||||
return ArgumentEntry.createSingleValueArgument(kvEntry.get());
|
||||
} else {
|
||||
return new SingleValueArgumentEntry();
|
||||
}
|
||||
}, calculatedFieldCallbackExecutor);
|
||||
}
|
||||
|
||||
private ListenableFuture<ArgumentEntry> fetchTsRolling(TenantId tenantId, EntityId entityId, Argument argument) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long timeWindow = argument.getTimeWindow() == 0 ? System.currentTimeMillis() : argument.getTimeWindow();
|
||||
@ -383,29 +362,6 @@ public class DefaultCalculatedFieldProcessingService implements CalculatedFieldP
|
||||
return Futures.transform(tsRollingFuture, tsRolling -> tsRolling == null ? new TsRollingArgumentEntry(limit, timeWindow) : ArgumentEntry.createTsRollingArgument(tsRolling, limit, timeWindow), calculatedFieldCallbackExecutor);
|
||||
}
|
||||
|
||||
private KvEntry createDefaultKvEntry(Argument argument) {
|
||||
String key = argument.getRefEntityKey().getKey();
|
||||
String defaultValue = argument.getDefaultValue();
|
||||
if (StringUtils.isBlank(defaultValue)) {
|
||||
return new StringDataEntry(key, null);
|
||||
}
|
||||
if (NumberUtils.isParsable(defaultValue)) {
|
||||
return new DoubleDataEntry(key, Double.parseDouble(defaultValue));
|
||||
}
|
||||
if ("true".equalsIgnoreCase(defaultValue) || "false".equalsIgnoreCase(defaultValue)) {
|
||||
return new BooleanDataEntry(key, Boolean.parseBoolean(defaultValue));
|
||||
}
|
||||
return new StringDataEntry(key, defaultValue);
|
||||
}
|
||||
|
||||
private CalculatedFieldState createStateByType(CalculatedFieldCtx ctx) {
|
||||
return switch (ctx.getCfType()) {
|
||||
case SIMPLE -> new SimpleCalculatedFieldState(ctx.getArgNames());
|
||||
case SCRIPT -> new ScriptCalculatedFieldState(ctx.getArgNames());
|
||||
case GEOFENCING -> new GeofencingCalculatedFieldState(ctx.getArgNames());
|
||||
};
|
||||
}
|
||||
|
||||
private static class TbCallbackWrapper implements TbQueueCallback {
|
||||
private final TbCallback callback;
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalcula
|
||||
import org.thingsboard.server.common.data.cf.configuration.ExpressionBasedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.Output;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduleSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.SimpleCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.id.CalculatedFieldId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
@ -67,11 +67,10 @@ public class CalculatedFieldCtx {
|
||||
private String expression;
|
||||
private boolean useLatestTs;
|
||||
private TbelInvokeService tbelInvokeService;
|
||||
private RelationService relationService;
|
||||
private CalculatedFieldScriptEngine calculatedFieldScriptEngine;
|
||||
private ThreadLocal<Expression> customExpression;
|
||||
|
||||
private RelationService relationService;
|
||||
|
||||
private boolean initialized;
|
||||
|
||||
private long maxDataPointsPerRollingArg;
|
||||
@ -129,7 +128,7 @@ public class CalculatedFieldCtx {
|
||||
}
|
||||
}
|
||||
case GEOFENCING -> initialized = true;
|
||||
default -> {
|
||||
case SIMPLE -> {
|
||||
if (isValidExpression(expression)) {
|
||||
this.customExpression = ThreadLocal.withInitial(() ->
|
||||
new ExpressionBuilder(expression)
|
||||
@ -323,8 +322,8 @@ public class CalculatedFieldCtx {
|
||||
}
|
||||
|
||||
public boolean hasSchedulingConfigChanges(CalculatedFieldCtx other) {
|
||||
if (calculatedField.getConfiguration() instanceof ScheduleSupportedCalculatedFieldConfiguration thisConfig
|
||||
&& other.calculatedField.getConfiguration() instanceof ScheduleSupportedCalculatedFieldConfiguration otherConfig) {
|
||||
if (calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration thisConfig
|
||||
&& other.calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration otherConfig) {
|
||||
boolean refreshTriggerChanged = thisConfig.isScheduledUpdateEnabled() != otherConfig.isScheduledUpdateEnabled();
|
||||
boolean refreshIntervalChanged = thisConfig.getScheduledUpdateIntervalSec() != otherConfig.getScheduledUpdateIntervalSec();
|
||||
return refreshTriggerChanged || refreshIntervalChanged;
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright © 2016-2025 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.utils;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.thingsboard.server.common.data.StringUtils;
|
||||
import org.thingsboard.server.common.data.cf.configuration.Argument;
|
||||
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
|
||||
import org.thingsboard.server.common.data.kv.KvEntry;
|
||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
||||
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry;
|
||||
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx;
|
||||
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.GeofencingCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.SimpleCalculatedFieldState;
|
||||
import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class CalculatedFieldArgumentUtils {
|
||||
|
||||
public static ListenableFuture<ArgumentEntry> transformSingleValueArgument(ListenableFuture<Optional<? extends KvEntry>> kvEntryFuture) {
|
||||
return Futures.transform(kvEntryFuture, kvEntry -> {
|
||||
if (kvEntry.isPresent() && kvEntry.get().getValue() != null) {
|
||||
return ArgumentEntry.createSingleValueArgument(kvEntry.get());
|
||||
}
|
||||
return new SingleValueArgumentEntry();
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
public static KvEntry createDefaultKvEntry(Argument argument) {
|
||||
String key = argument.getRefEntityKey().getKey();
|
||||
String defaultValue = argument.getDefaultValue();
|
||||
if (StringUtils.isBlank(defaultValue)) {
|
||||
return new StringDataEntry(key, null);
|
||||
}
|
||||
if (NumberUtils.isParsable(defaultValue)) {
|
||||
return new DoubleDataEntry(key, Double.parseDouble(defaultValue));
|
||||
}
|
||||
if ("true".equalsIgnoreCase(defaultValue) || "false".equalsIgnoreCase(defaultValue)) {
|
||||
return new BooleanDataEntry(key, Boolean.parseBoolean(defaultValue));
|
||||
}
|
||||
return new StringDataEntry(key, defaultValue);
|
||||
}
|
||||
|
||||
public static CalculatedFieldState createStateByType(CalculatedFieldCtx ctx) {
|
||||
return switch (ctx.getCfType()) {
|
||||
case SIMPLE -> new SimpleCalculatedFieldState(ctx.getArgNames());
|
||||
case SCRIPT -> new ScriptCalculatedFieldState(ctx.getArgNames());
|
||||
case GEOFENCING -> new GeofencingCalculatedFieldState(ctx.getArgNames());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -448,7 +448,6 @@ public class GeofencingCalculatedFieldStateTest {
|
||||
var config = new GeofencingCalculatedFieldConfiguration();
|
||||
|
||||
EntityCoordinates entityCoordinates = new EntityCoordinates("latitude", "longitude");
|
||||
entityCoordinates.setRefEntityId(DEVICE_ID);
|
||||
config.setEntityCoordinates(entityCoordinates);
|
||||
|
||||
ZoneGroupConfiguration allowedZonesGroup = new ZoneGroupConfiguration("allowedZones", "zone", reportStrategy, true);
|
||||
|
||||
@ -26,7 +26,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
property = "type"
|
||||
)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = RelationQueryDynamicSourceConfiguration.class, name = "RELATION_QUERY"),
|
||||
@JsonSubTypes.Type(value = RelationQueryDynamicSourceConfiguration.class, name = "RELATION_QUERY")
|
||||
})
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public interface CfArgumentDynamicSourceConfiguration {
|
||||
|
||||
@ -20,15 +20,17 @@ import lombok.Data;
|
||||
import org.thingsboard.server.common.data.cf.CalculatedFieldType;
|
||||
import org.thingsboard.server.common.data.cf.configuration.geofencing.EntityCoordinates;
|
||||
import org.thingsboard.server.common.data.cf.configuration.geofencing.ZoneGroupConfiguration;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduleSupportedCalculatedFieldConfiguration {
|
||||
public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration {
|
||||
|
||||
private EntityCoordinates entityCoordinates;
|
||||
private List<ZoneGroupConfiguration> zoneGroups;
|
||||
@ -49,6 +51,11 @@ public class GeofencingCalculatedFieldConfiguration implements ArgumentsBasedCal
|
||||
return args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityId> getReferencedEntities() {
|
||||
return zoneGroups.stream().map(ZoneGroupConfiguration::getRefEntityId).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Output getOutput() {
|
||||
return output;
|
||||
|
||||
@ -17,7 +17,7 @@ package org.thingsboard.server.common.data.cf.configuration;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
public interface ScheduleSupportedCalculatedFieldConfiguration extends CalculatedFieldConfiguration {
|
||||
public interface ScheduledUpdateSupportedCalculatedFieldConfiguration extends CalculatedFieldConfiguration {
|
||||
|
||||
@JsonIgnore
|
||||
boolean isScheduledUpdateEnabled();
|
||||
@ -35,9 +35,6 @@ public class EntityCoordinates {
|
||||
private final String latitudeKeyName;
|
||||
private final String longitudeKeyName;
|
||||
|
||||
@Nullable
|
||||
private EntityId refEntityId;
|
||||
|
||||
public void validate() {
|
||||
if (StringUtils.isBlank(latitudeKeyName)) {
|
||||
throw new IllegalArgumentException("Entity coordinates latitude key name must be specified!");
|
||||
@ -56,7 +53,6 @@ public class EntityCoordinates {
|
||||
|
||||
private Argument toArgument(String keyName) {
|
||||
var argument = new Argument();
|
||||
argument.setRefEntityId(refEntityId);
|
||||
argument.setRefEntityKey(new ReferencedEntityKey(keyName, ArgumentType.TS_LATEST, null));
|
||||
return argument;
|
||||
}
|
||||
|
||||
@ -1379,14 +1379,14 @@ public class ProtoUtils {
|
||||
|
||||
public static TransportProtos.EntityIdProto toProto(EntityId entityId) {
|
||||
return TransportProtos.EntityIdProto.newBuilder()
|
||||
.setEntityType(toProto(entityId.getEntityType()))
|
||||
.setEntityIdMSB(getMsb(entityId))
|
||||
.setEntityIdLSB(getLsb(entityId))
|
||||
.setType(toProto(entityId.getEntityType()))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static EntityId fromProto(TransportProtos.EntityIdProto entityIdProto) {
|
||||
return EntityIdFactory.getByTypeAndUuid(fromProto(entityIdProto.getEntityType()), new UUID(entityIdProto.getEntityIdMSB(), entityIdProto.getEntityIdLSB()));
|
||||
return EntityIdFactory.getByTypeAndUuid(fromProto(entityIdProto.getType()), new UUID(entityIdProto.getEntityIdMSB(), entityIdProto.getEntityIdLSB()));
|
||||
}
|
||||
|
||||
private static boolean isNotNull(Object obj) {
|
||||
|
||||
@ -83,9 +83,9 @@ enum ApiUsageRecordKeyProto {
|
||||
}
|
||||
|
||||
message EntityIdProto {
|
||||
EntityTypeProto entityType = 1;
|
||||
int64 entityIdMSB = 2;
|
||||
int64 entityIdLSB = 3;
|
||||
int64 entityIdMSB = 1;
|
||||
int64 entityIdLSB = 2;
|
||||
EntityTypeProto type = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -357,7 +357,7 @@ class ProtoUtilsTest {
|
||||
// toProto
|
||||
TransportProtos.EntityIdProto proto = ProtoUtils.toProto(original);
|
||||
assertThat(proto).isNotNull();
|
||||
assertThat(proto.getEntityType().getNumber()).isEqualTo(entityType.getProtoNumber());
|
||||
assertThat(proto.getType().getNumber()).isEqualTo(entityType.getProtoNumber());
|
||||
assertThat(proto.getEntityIdMSB()).isEqualTo(uuid.getMostSignificantBits());
|
||||
assertThat(proto.getEntityIdLSB()).isEqualTo(uuid.getLeastSignificantBits());
|
||||
|
||||
|
||||
@ -29,9 +29,9 @@ public class PerimeterDefinitionSerializer extends JsonSerializer<PerimeterDefin
|
||||
public void serialize(PerimeterDefinition value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
if (value instanceof CirclePerimeterDefinition c) {
|
||||
gen.writeStartObject();
|
||||
gen.writeNumberField("latitude", c.getLatitude());
|
||||
gen.writeNumberField("latitude", c.getLatitude());
|
||||
gen.writeNumberField("longitude", c.getLongitude());
|
||||
gen.writeNumberField("radius", c.getRadius());
|
||||
gen.writeNumberField("radius", c.getRadius());
|
||||
gen.writeEndObject();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.EntityType;
|
||||
import org.thingsboard.server.common.data.cf.CalculatedField;
|
||||
import org.thingsboard.server.common.data.cf.CalculatedFieldLink;
|
||||
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduleSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration;
|
||||
import org.thingsboard.server.common.data.id.CalculatedFieldId;
|
||||
import org.thingsboard.server.common.data.id.CalculatedFieldLinkId;
|
||||
import org.thingsboard.server.common.data.id.EntityId;
|
||||
@ -94,7 +94,7 @@ public class BaseCalculatedFieldService extends AbstractEntityService implements
|
||||
}
|
||||
|
||||
private void updatedSchedulingConfiguration(CalculatedField calculatedField) {
|
||||
if (calculatedField.getConfiguration() instanceof ScheduleSupportedCalculatedFieldConfiguration configuration) {
|
||||
if (calculatedField.getConfiguration() instanceof ScheduledUpdateSupportedCalculatedFieldConfiguration configuration) {
|
||||
if (!configuration.isScheduledUpdateEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -66,17 +66,14 @@ public class CalculatedFieldDataValidator extends DataValidator<CalculatedField>
|
||||
}
|
||||
|
||||
private void validateNumberOfArgumentsPerCF(TenantId tenantId, CalculatedField calculatedField) {
|
||||
if (!(calculatedField instanceof ArgumentsBasedCalculatedFieldConfiguration argumentsBasedCfg)) {
|
||||
return;
|
||||
}
|
||||
long maxArgumentsPerCF = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getMaxArgumentsPerCF);
|
||||
if (maxArgumentsPerCF <= 0) {
|
||||
return;
|
||||
}
|
||||
if (CalculatedFieldType.GEOFENCING.equals(calculatedField.getType()) && maxArgumentsPerCF < 3) {
|
||||
throw new DataValidationException("Geofencing calculated field requires at least 3 arguments, but the system limit is " +
|
||||
maxArgumentsPerCF + ". Contact your administrator to increase the limit."
|
||||
);
|
||||
}
|
||||
if (calculatedField.getConfiguration() instanceof ArgumentsBasedCalculatedFieldConfiguration configuration
|
||||
&& configuration.getArguments().size() > maxArgumentsPerCF) {
|
||||
if (argumentsBasedCfg.getArguments().size() > maxArgumentsPerCF) {
|
||||
throw new DataValidationException("Calculated field arguments limit reached!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,6 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
|
||||
|
||||
// Coordinates: TS_LATEST, no dynamic source
|
||||
EntityCoordinates entityCoordinates = new EntityCoordinates("latitude", "longitude");
|
||||
entityCoordinates.setRefEntityId(device.getId());
|
||||
cfg.setEntityCoordinates(entityCoordinates);
|
||||
|
||||
// Zone-group argument (ATTRIBUTE) — no DYNAMIC configuration, so no scheduling even if the scheduled interval is set
|
||||
@ -156,7 +155,6 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
|
||||
|
||||
// Coordinates: TS_LATEST, no dynamic source
|
||||
EntityCoordinates entityCoordinates = new EntityCoordinates("latitude", "longitude");
|
||||
entityCoordinates.setRefEntityId(device.getId());
|
||||
cfg.setEntityCoordinates(entityCoordinates);
|
||||
|
||||
// Zone-group argument (ATTRIBUTE) — make it DYNAMIC so scheduling is enabled
|
||||
@ -208,7 +206,6 @@ public class CalculatedFieldServiceTest extends AbstractServiceTest {
|
||||
|
||||
// Coordinates: TS_LATEST, no dynamic source
|
||||
EntityCoordinates entityCoordinates = new EntityCoordinates("latitude", "longitude");
|
||||
entityCoordinates.setRefEntityId(device.getId());
|
||||
cfg.setEntityCoordinates(entityCoordinates);
|
||||
|
||||
// Zone-group argument (ATTRIBUTE) — make it DYNAMIC so scheduling is enabled
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user