Fix no type-cast for attributes; telemetry controller refactoring
This commit is contained in:
parent
097b9d7148
commit
fb966bded0
@ -33,11 +33,11 @@ import jakarta.annotation.PostConstruct;
|
|||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
@ -65,25 +65,17 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.common.data.id.UUIDBased;
|
import org.thingsboard.server.common.data.id.UUIDBased;
|
||||||
import org.thingsboard.server.common.data.kv.Aggregation;
|
import org.thingsboard.server.common.data.kv.Aggregation;
|
||||||
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
|
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery;
|
import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery;
|
||||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.BooleanDataEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.DataType;
|
import org.thingsboard.server.common.data.kv.DataType;
|
||||||
import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
|
import org.thingsboard.server.common.data.kv.DeleteTsKvQuery;
|
||||||
import org.thingsboard.server.common.data.kv.DoubleDataEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.IntervalType;
|
import org.thingsboard.server.common.data.kv.IntervalType;
|
||||||
import org.thingsboard.server.common.data.kv.JsonDataEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.KvEntry;
|
import org.thingsboard.server.common.data.kv.KvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.LongDataEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.StringDataEntry;
|
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
|
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
|
||||||
import org.thingsboard.server.common.msg.rule.engine.DeviceAttributesEventNotificationMsg;
|
import org.thingsboard.server.common.msg.rule.engine.DeviceAttributesEventNotificationMsg;
|
||||||
import org.thingsboard.server.config.annotations.ApiOperation;
|
import org.thingsboard.server.config.annotations.ApiOperation;
|
||||||
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
import org.thingsboard.server.dao.timeseries.TimeseriesService;
|
||||||
import org.thingsboard.server.exception.InvalidParametersException;
|
|
||||||
import org.thingsboard.server.exception.UncheckedApiException;
|
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
import org.thingsboard.server.service.security.AccessValidator;
|
import org.thingsboard.server.service.security.AccessValidator;
|
||||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||||
@ -156,9 +148,6 @@ public class TelemetryController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TbTelemetryService tbTelemetryService;
|
private TbTelemetryService tbTelemetryService;
|
||||||
|
|
||||||
@Value("${transport.json.max_string_value_length:0}")
|
|
||||||
private int maxStringValueLength;
|
|
||||||
|
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
@ -345,12 +334,13 @@ public class TelemetryController extends BaseController {
|
|||||||
"Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED' that includes an error stacktrace."),
|
"Platform creates an audit log event about device attributes updates with action type 'ATTRIBUTES_UPDATED' that includes an error stacktrace."),
|
||||||
})
|
})
|
||||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/{deviceId}/{scope}", method = RequestMethod.POST)
|
@PostMapping(value = "/{deviceId}/{scope}")
|
||||||
@ResponseBody
|
public DeferredResult<ResponseEntity> saveDeviceAttributes(@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true)
|
||||||
public DeferredResult<ResponseEntity> saveDeviceAttributes(
|
@PathVariable("deviceId") String deviceIdStr,
|
||||||
@Parameter(description = DEVICE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("deviceId") String deviceIdStr,
|
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED))
|
||||||
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope") AttributeScope scope,
|
@PathVariable("scope") AttributeScope scope,
|
||||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
|
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)
|
||||||
|
@RequestBody String request) throws ThingsboardException {
|
||||||
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
|
EntityId entityId = EntityIdFactory.getByTypeAndUuid(EntityType.DEVICE, deviceIdStr);
|
||||||
return saveAttributes(getTenantId(), entityId, scope, request);
|
return saveAttributes(getTenantId(), entityId, scope, request);
|
||||||
}
|
}
|
||||||
@ -367,13 +357,15 @@ public class TelemetryController extends BaseController {
|
|||||||
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
|
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
|
||||||
})
|
})
|
||||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/{entityType}/{entityId}/{scope}", method = RequestMethod.POST)
|
@PostMapping(value = "/{entityType}/{entityId}/{scope}")
|
||||||
@ResponseBody
|
public DeferredResult<ResponseEntity> saveEntityAttributesV1(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
|
||||||
public DeferredResult<ResponseEntity> saveEntityAttributesV1(
|
@PathVariable("entityType") String entityType,
|
||||||
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
|
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
|
||||||
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
|
@PathVariable("entityId") String entityIdStr,
|
||||||
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"})) @PathVariable("scope") AttributeScope scope,
|
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}))
|
||||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
|
@PathVariable("scope") AttributeScope scope,
|
||||||
|
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)
|
||||||
|
@RequestBody String request) throws ThingsboardException {
|
||||||
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
|
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
|
||||||
return saveAttributes(getTenantId(), entityId, scope, request);
|
return saveAttributes(getTenantId(), entityId, scope, request);
|
||||||
}
|
}
|
||||||
@ -390,13 +382,15 @@ public class TelemetryController extends BaseController {
|
|||||||
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
|
@ApiResponse(responseCode = "500", description = SAVE_ENTITY_ATTRIBUTES_STATUS_INTERNAL_SERVER_ERROR),
|
||||||
})
|
})
|
||||||
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||||
@RequestMapping(value = "/{entityType}/{entityId}/attributes/{scope}", method = RequestMethod.POST)
|
@PostMapping(value = "/{entityType}/{entityId}/attributes/{scope}")
|
||||||
@ResponseBody
|
public DeferredResult<ResponseEntity> saveEntityAttributesV2(@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE"))
|
||||||
public DeferredResult<ResponseEntity> saveEntityAttributesV2(
|
@PathVariable("entityType") String entityType,
|
||||||
@Parameter(description = ENTITY_TYPE_PARAM_DESCRIPTION, required = true, schema = @Schema(defaultValue = "DEVICE")) @PathVariable("entityType") String entityType,
|
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true)
|
||||||
@Parameter(description = ENTITY_ID_PARAM_DESCRIPTION, required = true) @PathVariable("entityId") String entityIdStr,
|
@PathVariable("entityId") String entityIdStr,
|
||||||
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED)) @PathVariable("scope") AttributeScope scope,
|
@Parameter(description = ATTRIBUTES_SCOPE_DESCRIPTION, schema = @Schema(allowableValues = {"SERVER_SCOPE", "SHARED_SCOPE"}, requiredMode = Schema.RequiredMode.REQUIRED))
|
||||||
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true) @RequestBody JsonNode request) throws ThingsboardException {
|
@PathVariable("scope") AttributeScope scope,
|
||||||
|
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = ATTRIBUTES_JSON_REQUEST_DESCRIPTION, required = true)
|
||||||
|
@RequestBody String request) throws ThingsboardException {
|
||||||
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
|
EntityId entityId = EntityIdFactory.getByTypeAndId(entityType, entityIdStr);
|
||||||
return saveAttributes(getTenantId(), entityId, scope, request);
|
return saveAttributes(getTenantId(), entityId, scope, request);
|
||||||
}
|
}
|
||||||
@ -616,18 +610,24 @@ public class TelemetryController extends BaseController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private DeferredResult<ResponseEntity> saveAttributes(TenantId srcTenantId, EntityId entityIdSrc, AttributeScope scope, JsonNode json) throws ThingsboardException {
|
private DeferredResult<ResponseEntity> saveAttributes(TenantId srcTenantId, EntityId entityIdSrc, AttributeScope scope, String jsonStr) throws ThingsboardException {
|
||||||
if (AttributeScope.SERVER_SCOPE != scope && AttributeScope.SHARED_SCOPE != scope) {
|
if (AttributeScope.SERVER_SCOPE != scope && AttributeScope.SHARED_SCOPE != scope) {
|
||||||
return getImmediateDeferredResult("Invalid scope: " + scope, HttpStatus.BAD_REQUEST);
|
return getImmediateDeferredResult("Invalid scope: " + scope, HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
if (json.isObject()) {
|
JsonElement json;
|
||||||
List<AttributeKvEntry> attributes = extractRequestAttributes(json);
|
try {
|
||||||
|
json = JsonParser.parseString(jsonStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return getImmediateDeferredResult("Invalid JSON", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (json.isJsonObject()) {
|
||||||
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json);
|
||||||
if (attributes.isEmpty()) {
|
if (attributes.isEmpty()) {
|
||||||
return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST);
|
return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
for (AttributeKvEntry attributeKvEntry : attributes) {
|
for (AttributeKvEntry attributeKvEntry : attributes) {
|
||||||
if (attributeKvEntry.getKey().isEmpty() || attributeKvEntry.getKey().trim().length() == 0) {
|
if (attributeKvEntry.getKey().isBlank()) {
|
||||||
return getImmediateDeferredResult("Key cannot be empty or contains only spaces", HttpStatus.BAD_REQUEST);
|
return getImmediateDeferredResult("Key cannot be blank", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SecurityUser user = getCurrentUser();
|
SecurityUser user = getCurrentUser();
|
||||||
@ -885,43 +885,6 @@ public class TelemetryController extends BaseController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<AttributeKvEntry> extractRequestAttributes(JsonNode jsonNode) {
|
|
||||||
long ts = System.currentTimeMillis();
|
|
||||||
List<AttributeKvEntry> attributes = new ArrayList<>();
|
|
||||||
jsonNode.fields().forEachRemaining(entry -> {
|
|
||||||
String key = entry.getKey();
|
|
||||||
JsonNode value = entry.getValue();
|
|
||||||
if (entry.getValue().isObject() || entry.getValue().isArray()) {
|
|
||||||
attributes.add(new BaseAttributeKvEntry(new JsonDataEntry(key, toJsonStr(value)), ts));
|
|
||||||
} else if (entry.getValue().isTextual()) {
|
|
||||||
if (maxStringValueLength > 0 && entry.getValue().textValue().length() > maxStringValueLength) {
|
|
||||||
String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", entry.getValue().textValue().length(), key, maxStringValueLength);
|
|
||||||
throw new UncheckedApiException(new InvalidParametersException(message));
|
|
||||||
}
|
|
||||||
attributes.add(new BaseAttributeKvEntry(new StringDataEntry(key, value.textValue()), ts));
|
|
||||||
} else if (entry.getValue().isBoolean()) {
|
|
||||||
attributes.add(new BaseAttributeKvEntry(new BooleanDataEntry(key, value.booleanValue()), ts));
|
|
||||||
} else if (entry.getValue().isDouble()) {
|
|
||||||
attributes.add(new BaseAttributeKvEntry(new DoubleDataEntry(key, value.doubleValue()), ts));
|
|
||||||
} else if (entry.getValue().isNumber()) {
|
|
||||||
if (entry.getValue().isBigInteger()) {
|
|
||||||
throw new UncheckedApiException(new InvalidParametersException("Big integer values are not supported!"));
|
|
||||||
} else {
|
|
||||||
attributes.add(new BaseAttributeKvEntry(new LongDataEntry(key, value.longValue()), ts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String toJsonStr(JsonNode value) {
|
|
||||||
try {
|
|
||||||
return JacksonUtil.toString(value);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
throw new JsonParseException("Can't parse jsonValue: " + value, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private JsonNode toJsonNode(String value) {
|
private JsonNode toJsonNode(String value) {
|
||||||
try {
|
try {
|
||||||
return JacksonUtil.toJsonNode(value);
|
return JacksonUtil.toJsonNode(value);
|
||||||
|
|||||||
@ -266,7 +266,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
|
|||||||
SettableFuture<Void> futureToSet = SettableFuture.create();
|
SettableFuture<Void> futureToSet = SettableFuture.create();
|
||||||
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
|
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
|
||||||
AttributeScope scope = AttributeScope.valueOf(metaData.getValue(DataConstants.SCOPE));
|
AttributeScope scope = AttributeScope.valueOf(metaData.getValue(DataConstants.SCOPE));
|
||||||
List<AttributeKvEntry> attributes = new ArrayList<>(JsonConverter.convertToAttributes(json, ts));
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json, ts);
|
||||||
ListenableFuture<List<AttributeKvEntry>> future = filterAttributesByTs(tenantId, entityId, scope, attributes);
|
ListenableFuture<List<AttributeKvEntry>> future = filterAttributesByTs(tenantId, entityId, scope, attributes);
|
||||||
Futures.addCallback(future, new FutureCallback<>() {
|
Futures.addCallback(future, new FutureCallback<>() {
|
||||||
@Override
|
@Override
|
||||||
@ -314,7 +314,7 @@ public abstract class BaseTelemetryProcessor extends BaseEdgeProcessor {
|
|||||||
SettableFuture<Void> futureToSet = SettableFuture.create();
|
SettableFuture<Void> futureToSet = SettableFuture.create();
|
||||||
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
|
JsonObject json = JsonUtils.getJsonObject(msg.getKvList());
|
||||||
AttributeScope scope = AttributeScope.valueOf(metaData.getValue(DataConstants.SCOPE));
|
AttributeScope scope = AttributeScope.valueOf(metaData.getValue(DataConstants.SCOPE));
|
||||||
List<AttributeKvEntry> attributes = new ArrayList<>(JsonConverter.convertToAttributes(json, ts));
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(json, ts);
|
||||||
ListenableFuture<List<AttributeKvEntry>> future = filterAttributesByTs(tenantId, entityId, scope, attributes);
|
ListenableFuture<List<AttributeKvEntry>> future = filterAttributesByTs(tenantId, entityId, scope, attributes);
|
||||||
Futures.addCallback(future, new FutureCallback<>() {
|
Futures.addCallback(future, new FutureCallback<>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -67,7 +67,6 @@ import org.thingsboard.server.service.security.permission.Resource;
|
|||||||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
|
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
|
||||||
import org.thingsboard.server.utils.CsvUtils;
|
import org.thingsboard.server.utils.CsvUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -235,7 +234,7 @@ public abstract class AbstractBulkImportService<E extends HasId<? extends Entity
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
private void saveAttributes(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry, BulkImportColumnType kvType) {
|
private void saveAttributes(SecurityUser user, E entity, Map.Entry<BulkImportColumnType, JsonObject> kvsEntry, BulkImportColumnType kvType) {
|
||||||
String scope = kvType.getKey();
|
String scope = kvType.getKey();
|
||||||
List<AttributeKvEntry> attributes = new ArrayList<>(JsonConverter.convertToAttributes(kvsEntry.getValue()));
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(kvsEntry.getValue());
|
||||||
|
|
||||||
accessValidator.validateEntityAndCallback(user, Operation.WRITE_ATTRIBUTES, entity.getId(), (result, tenantId, entityId) -> {
|
accessValidator.validateEntityAndCallback(user, Operation.WRITE_ATTRIBUTES, entity.getId(), (result, tenantId, entityId) -> {
|
||||||
tsSubscriptionService.saveAttributes(AttributesSaveRequest.builder()
|
tsSubscriptionService.saveAttributes(AttributesSaveRequest.builder()
|
||||||
|
|||||||
@ -56,11 +56,9 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509Ce
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@ -538,13 +536,13 @@ public class JsonConverter {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<AttributeKvEntry> convertToAttributes(JsonElement element) {
|
public static List<AttributeKvEntry> convertToAttributes(JsonElement element) {
|
||||||
long ts = System.currentTimeMillis();
|
long ts = System.currentTimeMillis();
|
||||||
return convertToAttributes(element, ts);
|
return convertToAttributes(element, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<AttributeKvEntry> convertToAttributes(JsonElement element, long ts) {
|
public static List<AttributeKvEntry> convertToAttributes(JsonElement element, long ts) {
|
||||||
return new HashSet<>(parseValues(element.getAsJsonObject()).stream().map(kv -> new BaseAttributeKvEntry(kv, ts)).toList());
|
return parseValues(element.getAsJsonObject()).stream().<AttributeKvEntry>map(kv -> new BaseAttributeKvEntry(kv, ts)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<KvEntry> parseValues(JsonObject valuesObject) {
|
private static List<KvEntry> parseValues(JsonObject valuesObject) {
|
||||||
|
|||||||
@ -23,8 +23,6 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.parallel.Isolated;
|
import org.junit.jupiter.api.parallel.Isolated;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
@Isolated("JsonConverter static settings being modified")
|
@Isolated("JsonConverter static settings being modified")
|
||||||
public class JsonConverterTest {
|
public class JsonConverterTest {
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ public class JsonConverterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseAttributesBigDecimalAsLong() {
|
public void testParseAttributesBigDecimalAsLong() {
|
||||||
var result = new ArrayList<>(JsonConverter.convertToAttributes(JsonParser.parseString("{\"meterReadingDelta\": 1E1}")));
|
var result = JsonConverter.convertToAttributes(JsonParser.parseString("{\"meterReadingDelta\": 1E1}"));
|
||||||
Assertions.assertEquals(10L, result.get(0).getLongValue().get().longValue());
|
Assertions.assertEquals(10L, result.get(0).getLongValue().get().longValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,4 +106,5 @@ public class JsonConverterTest {
|
|||||||
JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
|
JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,6 @@ import org.thingsboard.server.common.msg.TbMsg;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT;
|
import static org.thingsboard.server.common.data.msg.TbMsgType.ACTIVITY_EVENT;
|
||||||
@ -115,14 +114,13 @@ public class TbCopyAttributesToEntityViewNode implements TbNode {
|
|||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData()));
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData())).stream()
|
||||||
List<AttributeKvEntry> filteredAttributes =
|
.filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).toList();
|
||||||
attributes.stream().filter(attr -> attributeContainsInEntityView(scope, attr.getKey(), entityView)).collect(Collectors.toList());
|
|
||||||
ctx.getTelemetryService().saveAttributes(AttributesSaveRequest.builder()
|
ctx.getTelemetryService().saveAttributes(AttributesSaveRequest.builder()
|
||||||
.tenantId(ctx.getTenantId())
|
.tenantId(ctx.getTenantId())
|
||||||
.entityId(entityView.getId())
|
.entityId(entityView.getId())
|
||||||
.scope(scope)
|
.scope(scope)
|
||||||
.entries(filteredAttributes)
|
.entries(attributes)
|
||||||
.callback(getFutureCallback(ctx, msg, entityView))
|
.callback(getFutureCallback(ctx, msg, entityView))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -258,7 +258,7 @@ class DeviceState {
|
|||||||
|
|
||||||
private boolean processAttributes(TbContext ctx, TbMsg msg, String scope) throws ExecutionException, InterruptedException {
|
private boolean processAttributes(TbContext ctx, TbMsg msg, String scope) throws ExecutionException, InterruptedException {
|
||||||
boolean stateChanged = false;
|
boolean stateChanged = false;
|
||||||
Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData()));
|
List<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData()));
|
||||||
if (!attributes.isEmpty()) {
|
if (!attributes.isEmpty()) {
|
||||||
SnapshotUpdate update = merge(latestValues, attributes, scope);
|
SnapshotUpdate update = merge(latestValues, attributes, scope);
|
||||||
for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) {
|
for (DeviceProfileAlarm alarm : deviceProfile.getAlarmSettings()) {
|
||||||
@ -321,7 +321,7 @@ class DeviceState {
|
|||||||
return new SnapshotUpdate(AlarmConditionKeyType.TIME_SERIES, keys);
|
return new SnapshotUpdate(AlarmConditionKeyType.TIME_SERIES, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SnapshotUpdate merge(DataSnapshot latestValues, Set<AttributeKvEntry> attributes, String scope) {
|
private SnapshotUpdate merge(DataSnapshot latestValues, List<AttributeKvEntry> attributes, String scope) {
|
||||||
long newTs = 0;
|
long newTs = 0;
|
||||||
Set<AlarmConditionFilterKey> keys = new HashSet<>();
|
Set<AlarmConditionFilterKey> keys = new HashSet<>();
|
||||||
for (AttributeKvEntry entry : attributes) {
|
for (AttributeKvEntry entry : attributes) {
|
||||||
|
|||||||
@ -103,8 +103,7 @@ public class TbCalculatedFieldsNode implements TbNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processPostAttributesRequest(TbContext ctx, TbMsg msg) {
|
private void processPostAttributesRequest(TbContext ctx, TbMsg msg) {
|
||||||
List<AttributeKvEntry> newAttributes = new ArrayList<>(JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData())));
|
List<AttributeKvEntry> newAttributes = JsonConverter.convertToAttributes(JsonParser.parseString(msg.getData()));
|
||||||
|
|
||||||
if (newAttributes.isEmpty()) {
|
if (newAttributes.isEmpty()) {
|
||||||
ctx.tellSuccess(msg);
|
ctx.tellSuccess(msg);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -41,7 +41,6 @@ import org.thingsboard.server.common.data.plugin.ComponentType;
|
|||||||
import org.thingsboard.server.common.data.util.TbPair;
|
import org.thingsboard.server.common.data.util.TbPair;
|
||||||
import org.thingsboard.server.common.msg.TbMsg;
|
import org.thingsboard.server.common.msg.TbMsg;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -133,7 +132,7 @@ public class TbMsgAttributesNode implements TbNode {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String src = msg.getData();
|
String src = msg.getData();
|
||||||
List<AttributeKvEntry> newAttributes = new ArrayList<>(JsonConverter.convertToAttributes(JsonParser.parseString(src)));
|
List<AttributeKvEntry> newAttributes = JsonConverter.convertToAttributes(JsonParser.parseString(src));
|
||||||
if (newAttributes.isEmpty()) {
|
if (newAttributes.isEmpty()) {
|
||||||
ctx.tellSuccess(msg);
|
ctx.tellSuccess(msg);
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user